mmofacts.com

MySQL - Update mit Left Join: Vergleichswert verändern

gepostet vor 19 Jahre, 1 Monat von Krisch
Hallo,

ich versuche verzweifelt ein Update mit Left Join hinzubekommen.

Die Funktion soll die Priorität einer Aktion herabsetzten und die der (direkt) darunterliegenden Aktionen erhöhen. Wegen Nebenläufigkeit kann ich nicht einfach Limit 1 machen. Beispiel: ich will wenn eine Aktion mit Priorität 5 herabgesetzt wird, alle mit Priorität 4 erhöht werden.

Problem ist, dass die Priorität die herabgesetzt wird, auch in den Auswahlbedingungen vorkommt und MySQL scheint auch Zeilen zu verändern, die erst nach dem Verändern der herabzusetzenden Priorität in die Auswahl kommen würden.


Database::query(

'UPDATE actions AS a1
LEFT JOIN actions AS a2
ON a1.sorcererId = a2.sorcererId
SET
a2.priority = a2.priority + 1,
a1.priority = a1.priority - 1
WHERE
a1.id = "' . (int)$actionId . '" AND
a2.id
"' . (int)$actionId . '" AND
a1.sorcererId = "' . (int)$sorcererId . '" AND
a2.sorcererId = "' . (int)$sorcererId . '" AND
a1.priority > 1 AND
a1.priority - 1 = a2.priority');Verändert, wenn a1.priority=5, alle a2 mit priority 3 oder 4. Richtig wäre nur die mit priority 4.


Eventuell kann man da was mit Benutzervariablen machen, aber ich weiss nicht ob das innerhalb einer Abfrage möglich ist.

Vielleicht hab ich auch einen ganz anderen Denkfehler drin, ich bin für jede Hilfe dankbar.
gepostet vor 19 Jahre, 1 Monat von felix
Hab zwar keine Ahnung aber ich geb mal folgende Prognose, welche aber auch total falsch sein kann.

a2.id
"' . (int)$actionId . '" AND


Das < > bedeuted automatisch ein "OR" ein und macht dein ganzes Statement kaputt
gepostet vor 19 Jahre, 1 Monat von Krisch
Ne, das steht eindeutig für ungleich(, auch wenn man != schreiben könnte).
gepostet vor 19 Jahre, 1 Monat von The_Alien
Da ich annehme das der so oder so beide ändert glaube ich nicht das man das so in der Art machen kann. Hast du es mal mit IF versucht quasi:
"If 4 then 5 else 4"
Den genauen Syntax der If anweisung für Mysql müßte ich jetzt raussuchen da ich sie selber noch nicht genutzt habe.
gepostet vor 19 Jahre, 1 Monat von Krisch
Das Limit der Aktionen liegt im zweistelligen, wenn ich für für jeden Wert eine andere (Teil-)Abfrage nehmen würde, wäre die Gesamtabfrage etwas überladen.

Oder hast du was anderes gemeint?

---
Ich kann notfalls auch 2 Abfragen darausmachen, aber dann könnte ab und zu eine falsche Reihenfolge angezeigt werden. Und jetzt interessiert mich auch was den Fehler verursacht.
gepostet vor 19 Jahre, 1 Monat von Krisch
hmm.. wenn ich's mir recht überlege, kann ich das doch nicht in 2 Abfragen aufsplitten, weil es dann mit der umgekehrten Aktion (Priorität hochsetzen) in Konflikt kommt.

Also wenn jemand eine Idee hat, wäre ich echt dankbar.
gepostet vor 19 Jahre, 1 Monat von The_Alien
Nein - ich meinte eine wirkliche IF Then abfrage im SQL Query - ungefähr so *buchrauswühl*

UPDATE `actions` IF (`priority`=4) THEN (SET `priority`=5) ELSE (SET `priority`=4) END IF WHERE `priority`=4 OR `priority`=5;


Keine Ahnung ob das so hinhaut - habe sie wie gesagt selber noch nie gebraucht oder benutzt. Ist mir nur so beim überlegen eingefallen das es evtl. damit gehen könnte.

Hier der Syntax von MySQL:
http://dev.mysql.com/doc/mysql/en/if-statement.html

Was auch noch eine Möglichkeit wäre ein auto_increment Spalte hinzufügen und erst alle betroffenen Spalten selektieren und dann nach den ID's Updaten - würde aber ein paar querys erfordern
gepostet vor 19 Jahre, 1 Monat von Kampfhoernchen
Ich bin nicht sicher, ob man in Updates joinen kann. Bei Deletes gehts jedenfalls nicht, wie ich nach ner 30 Zeilen-Query und 2 Stunden leider feststellen musste.
IF sieht so aus:
IF( a, b, c)
Wenn a true ist, mache b, sonst c
gepostet vor 19 Jahre, 1 Monat von The_Alien
Original von Kampfhoernchen
Ich bin nicht sicher, ob man in Updates joinen kann. Bei Deletes gehts jedenfalls nicht, wie ich nach ner 30 Zeilen-Query und 2 Stunden leider feststellen musste.
IF sieht so aus:
IF( a, b, c)
Wenn a true ist, mache b, sonst c


So hatte ich das auch in meinem Büchlein stehen - aber auf der MySQL Homepage steht das so:

IF search_condition THEN statement_list

[ELSEIF search_condition THEN statement_list] ...
[ELSE statement_list]
END IF

Wie gesagt weiß ich nicht wie es richtig geht bzw welches von beiden funktioniert.
gepostet vor 19 Jahre, 1 Monat von The_Alien
Hab grade nochmal weiter geschjaut. Das was ich oben habe ist ein Statemant - die function geht doch so wie Kampfhörnchen es geschrieben hatte. (Und ich dachte mein Buch spinnt )

Habe dann auch ein bsp. zu einer Updatefunktion mit IF gefunden:

UPDATE test

SET
field1 = 'nico',
test = IF(valid=0,test + 10,test + 0),
valid = 1
WHERE email = '[email protected]'";

Je mehr ich mich damit befasse desto interesannter finde ich das bzw finde ich gute einsatzmöglichkeiten.

Anders scheint es aber auch zu gehen:
UPDATE tbl_name SET fld2 = CASE fld1

WHEN val1 THEN data1
WHEN val2 THEN data2
ELSE fld2 END
(auch von der MySQL HP)
gepostet vor 19 Jahre, 1 Monat von Krisch
Also ich bin mir nahezu sicher, dass das Problem so aussieht:
MySQL nimmt eine Zeile nach der anderen und verändert sie
- Zuerst werden ein paar a2 Zeilen verändert,
- dann die a1 Zeile
- und dann wieder a2 Zeilen, wobei sich jetzt der Wert von a1 schon geändert hat.

Leider kann man bei Updates über mehrere Tabellen keine Sortierung angeben.

@Kampfhoernchen: Ja, man kann in Updates joinen, sonst würde ich sicher eine Fehlermeldung bekommen.

@The_Alien: Okay, aber wenn es so abläuft wie ich meine, bringt mir das nichts. Aber ich versuch es heute abend mal.

P.S: Ich hab die Frage jetzt auch mal auf www.mysql.com gestellt. (MySQL Forum)
gepostet vor 19 Jahre, 1 Monat von Hubble
Was ich noch nicht verstanden habe ist, wozu der JOIN da ist?
Es wird doch nur auf eine Tabelle zugegriffen.
Wenn diese nicht intern referenziert, brauchts normalerweise keinen JOIN.

Der letzte Vorschlag von The_Alien schein mir durchaus angemessen. Hast Du den mal getestet?

Hubble
gepostet vor 19 Jahre, 1 Monat von Krisch
Ich brauche die Joins damit ich a1.priority=a2.priority-1 machen kann. Wenn du weisst wie man das mit MySQL-Variablen macht, dann her damit.

Wie das mit IFs gehen soll weiss ich immer noch nicht..
gepostet vor 19 Jahre, 1 Monat von Hubble
Geht nicht einfach
priority=priority-1 ??

Ich mach das immer so in meinen Abfragen.
(oder eben a2.priority=a2.priority-1 )

Versuch mal:
UPDATE actions 

SET priority = CASE priority
WHEN 1 THEN 2
WHEN 2 THEN 1
ELSE priority+2 END

Oder so ählich. Damit wird 1 bei allen priotity =2 gesetzt und umgegeht.
Ansonsten wird priority um 2 erhöht.

Hubble
gepostet vor 19 Jahre, 1 Monat von Krisch
Ich mach doch "priority=priority-1" im meinem letzten Beitrag hab ich die WHERE-Bedingunge gemeint.

Ich kann keine Zahlen einsetzen, weil ich diese dann erst aus der Datenbank lesen müsste und dann könnten die Zahlen ja schon wieder veraltet sein. Und wenn ich das mit JOIN löse, brauch ich da keine Fallunterscheidung mehr machen, weil ich die praktisch schon durch JOIN und WHERE habe.

Also natürlich gibt es die Möglichkeit das über mehrere Abfragen zu machen, aber ich hätte gerne nur eine (und eine bei der ich nicht die komplette Tabelle locken muss).
gepostet vor 19 Jahre, 1 Monat von Hubble
Aha ich hab das Problem missvertanden

Also Versuch 2. Mit welcher Version arbeitest Du? Ab Version 4.1 gibt es SUBSELECTS. Bischen tricky die Dinger aber ganz praktisch.
http://dev.mysql.com/doc/mysql/en/subqueries.html

UPDATE actions 

SET priority = IF( id = "' . (int)$actionId . '" , priority - 1 , priority + 1)
WHERE id = "' . (int)$actionId . '" OR
id IN
(
SELECT id FROM actions
WHERE .....
)



Wenn Du im Subselect alle id's (ich nehme an die sind eindeutig) zurückgibst dann sollte dies in der Art funzen.
Dieser Subselect gibt alle id's zurück deren priorität um 1 erhöht werden soll und in der IF() Funktion gibts du an für welche Spalten die priority erhöht und erniedrigt werden soll. (also in allen Spalten außer der Referenzspalte.)

Bei einem Subselect wird (soweit ich weiß) erst eine Ergebnismenge gebildet und dann alle Werte zurückgegeben, dies schließt eventuelle Rückwirkungen aus.

Ich hoffe ich hab diesmal das Prob richtig interpretiert.

Hubble
gepostet vor 19 Jahre, 1 Monat von Krisch
Leider hat mein Lieblingshoster, die MySQL Datenbank immer noch nicht geupdatet, weil sie die Server auf irgendwas umstellen. ;(

Naja, ich hab's jetzt erstmal auf Eis gelegt. "Das Ändern der Reihenfolge erfolgt dann auf eigene Gefahr"...
gepostet vor 19 Jahre, 1 Monat von Krisch
Email von heute: "Seit gestern haben wir MySQL auf Version 4.1.14 geupdated. Dies wurde auf Grund einer Sicherheitslücke in MySQL 4.0.20 nötig."

... da hätte ich mir das auch sparen könnnen.

Auf diese Diskussion antworten