De volgende methode is gebaseerd op het feit dat de possessions
tabel heeft een primaire sleutel en citizen_id
maakt er geen deel van uit. Dit is het idee:
-
Zet alle parameters van de update (
citizen_id
engood_id
om op te filteren, de nieuwe waarden vancitizen_id
en het aantal rijen dat moet worden bijgewerkt) naar een opslagruimte, een speciale tabel misschien, of een tijdelijke tabel. -
Wijs rijnummers toe aan
possessions
rijen partitioneren op(citizen_id, good_id)
en voeg vervolgens de gerangschikte rijset toe aan de parametertabel om de originele volledige set te filteren opcitizen_id
engood_id
, evenals het aantal rijen. -
Doe mee met
possessions
en het resultaat van de vorige join op de primaire sleutelwaarden en updatecitizen_id
met de nieuwe waarden.
In de SQL van MySQL kan het bovenstaande er als volgt uitzien:
UPDATE possessions AS p
INNER JOIN
(
SELECT
@r := @r * (@c = p.citizen_id AND @g = p.good_id) + 1 AS r,
p.possession_id,
@c := p.citizen_id AS citizen_id,
@g := p.good_id AS good_id
FROM
possessions AS p
CROSS JOIN
(SELECT @r := 0, @c := 0, @g := 0) AS x
ORDER BY
p.citizen_id,
p.good_id
) AS f ON p.possession_id = f.possession_id
INNER JOIN
possession_updates AS u ON u.citizen_id = f.citizen_id AND u.good_id = f.good_id
SET
p.citizen_id = u.new_citizen_id
WHERE
f.r <= u.row_count
;
De possessions_update
is de tabel met de parameterwaarden.
De query maakt gebruik van een bekende methode van rijnummering die gebruikmaakt van variabelen, die is geïmplementeerd in de f
subquery.
Ik heb geen MySQL, dus ik kan dit niet goed testen vanuit het oogpunt van prestaties, maar je kunt het tenminste zien aan deze SQL Fiddle-demo
dat de methode werkt. (De UPDATE-instructie staat in het schemascript, omdat SQL Fiddle geen gegevenswijzigingsinstructies toestaat in het rechterscript voor MySQL. De rechterkant retourneert alleen de post-UPDATE-inhoud van possessions
.)