Hoi,

Ik probeer een tabel bij te werken zonder succes.

update 
	trn_spelers s1
		set s1.grafischevolgorde=
			(select
				FIND_IN_SET(if(s1.elo<>"",s1.elo,-s1.id), (
				SELECT GROUP_CONCAT(if(elo<>"",elo,-id)
				ORDER BY 
					if(elo<>"",elo,-id) DESC
				) rang
				FROM trn_spelers 
				where 
					id_toernooi=s1.id_toernooi)) r
			from
				trn_spelers s1
			left join 
				trn_spelers s2
				on s1.id=s2.id
			where 
				s1.id_toernooi=37)
where 
	s1.id_toernooi=37

Ik krijg steeds de fout: #1093 - You can't specify target table 's1' for update in FROM clause.
Ook al met een join geprobeerd maar ik raak er niet uit wijs :(
s1.id_toernooi=37 word via PHP opgebouwd
velden
grafischevolgorde==>float
id==>int
id_toernooi==>int
elo varchar(5)
De if is om uniekere resultaten te hebben indien er geen elo opgegeven is.


Hoe kan ik dit oplossen?

Jan
Bouw eenvoudigere queries en zet alles in een transactie? Aangenomen dat je een database engine hebt die dat ondersteunt (InnoDB).

Ook lijkt het alsof e.e.a. niet helemaal uitgenormaliseerd/gestructureerd is. Mogelijk kun je daar ook nog winst pakken, het ziet er nu naar uit dat data min of meer geëncodeerd staat opgeslagen in kolommen?
Dit is het mutating table probleem: je kan tabel trn_spelers niet updaten en tegelijkertijd selecteren in de from clause uit deze trn_spelers. Dit weigert vrijwel elk RDBMS gewoon omdat de kans bestaat dat je iets update dat in de select geselecteerd is wat dan weer de selectie ongeldig kan maken.
De foutmelding is daarin heel duidelijk: You can't specify target table trn_spelers for update in FROM clause.
Ik heb voor de duidelijkheid s1 even veranderd in trn_spelers want dat is wat er bedoeld wordt.
En de enige manier om te garanderen dat de geSELECTeerde gegevens niet wijzigen (of liever gezegd, de enige manier om te garanderen dat jouw huidige batch queries de enige partij is die records kan wijzigen (write lock)) is SELECT ... FOR UPDATE binnen een transactie.
Thomas van den Heuvel op 30/04/2019 16:05:47

Ook lijkt het alsof e.e.a. niet helemaal uitgenormaliseerd/gestructureerd is. Mogelijk kun je daar ook nog winst pakken, het ziet er nu naar uit dat data min of meer geëncodeerd staat opgeslagen in kolommen?


Waaruit leid je dit af?
De tabel bevat alle verplichte info van de spelers 14 kolommen en 1 kolom "opmerking". Voor 1 kolom maak ik geen extra tabel :)

@Aad B: Sommige sites schrijven een oplossing welke ik dus niet werkende kreeg.

Ik heb het probleem opgelost via javascript.
Beiden bedankt om mee te denken.
Thomas van den Heuvel op 01/05/2019 22:45:27

En de enige manier om te garanderen dat de geSELECTeerde gegevens niet wijzigen (of liever gezegd, de enige manier om te garanderen dat jouw huidige batch queries de enige partij is die records kan wijzigen (write lock)) is SELECT ... FOR UPDATE binnen een transactie.

Ook dan lukt het je niet en krijg je de foutmelding: You can't specify target table for update in FROM clause. Je kan eenvoudig niet de target table ook nog eens in de FROM clause gebruiken. Ook niet in transacties. Elke SQL engine weigert dat. MySQL, Oracle, MicrosoftSQL, MariaDB maakt niet uit.
Onderstaand wordt wel een aardige oplossing geboden:http://logic.edchen.org/how-to-resolve-error-1093-hy000-you-cant-specify-target-table-xxxx-for-update-in-from-clause/
Maak een temporary table die aan het einde van de transactie automatisch wordt verwijderd.

enne "Ik heb het probleem opgelost via javascript." Hoe doe je dat? javascript draait in de browser, oplossen je data naar de client halen en dan verwerken?
Hier oplossingen die werken.

https://7php.com/mysql-update-select-statement-1093/

Solution 1 toegepast in mijn knopenwinkel middels een procedure :

CREATE PROCEDURE `Pennies`(IN `Rekening` smallint(12), IN `Pennies` bigint(12))
UPDATE
	account p1,
	(
		SELECT
			( sp.amount_pennies + Pennies ) AS new_pennies
		FROM
			account sp
		WHERE
			acct_num = Rekening
	) AS p2
SET
	p1.amount_pennies = p2.new_pennies
WHERE
	acct_num = Rekening;


Die kan je dan met een CALL oproepen met een + of - waarde :

CALL `Pennies`('137', '-50');

@John D uiteraard in twee aparte queries. Eén met een SELECT ... FOR UPDATE, en dan een UPDATE query. Beide binnen een transactie.

@Adoptive, dat werkt misschien, maar vormt dat een ondeelbaar geheel? En mogelijk hangt het atomair zijn van een query af van de database engine. Misschien gaat het toch mis in een MyISAM opstelling waarbij die procedure heel vaak parallel wordt aangeroepen? Het zijn juist die randgevallen die je wilt vermijden.

Wat mij betreft is de enige manier om te garanderen dat informatie niet verandert gedurende een wijziging de gebruikmaking van een transactie.

Reageren