Kurztipp: UPDATE mit ORDER BY in SQL

Heute stand ein kleines Datenbank-Problem an, das eine „kreative“ Lösung erforderte. Die Sortierung von ein paar Elementen basierte auf der Datenbank-ID, aber ein neues Element musste unbedingt in die Mitte. Da es als letztes eingefügt wurde, hatte es aber natürlich die höchste ID (man stelle sich eine typische MySQL-Datenbank mit AUTO_INCREMENT-Feld als Primary Key vor). Zeit für eine „richtige“ Lösung war nicht, also mussten ein paar IDs in der Datenbank verschoben werden: Jeder Kurs rückt eine ID weiter, dann kann später der letzte auf das leere Feld aufrücken. Gesagt, getan:

update courses set id=id+1 where and id>=3041 and id<=3052

Ergebnis: Primary Key Konflikt, es gibt schon eine Zeile mit der ID 3042. Bei genauerer Überlegung ist das ja auch klar: Die Reihenfolge, in der die Updates durchgeführt werden, ist nicht weiter spezifiziert, von daher wird vermutlich die physische Reihenfolge der Zeilen verwendet, was mehr oder weniger den IDs entspricht (gerade bei AUTO_INCREMENT Keys). Es geht also mit Zeile 3041 los, die zu 3042 geändert wird. Die gibt es aber schon –> Fehler. Natürlich wäre das Update prinzipiell durchführbar, weil nach dem Update ja alles wieder passt, und kein Key doppelt vorhanden ist, aber leider müssen Primary Keys auch während des Updates konsistent sein.

Was also tun? Ganz einfach, die Reihenfolge der Update mit angeben:

update courses set id=id+1 where and id>=3041 and id<=3052 order by id desc

Man beachte das „ORDER BY id DESC“ am Ende! Mir war ehrlich gesagt neu, das man in einer UPDATE-Anfrage ein ORDER BY verwenden kann, aber das ist erlaubt, sagt auch die Doku. Auf diese Weise funktioniert es dann, denn jetzt wird als erstes der letztes Datensatz einen weitergeschoben, und dann der vorletzte etc. MySQL passt dabei übrigens auch den Counter für den nächsten AUTO_INCREMENT Wert automatisch an, so dass dort auch keine Probleme entstehen.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.