update set CASE WHEN - wie geht das?

michaldo

Benutzer
Beiträge
6
Ich habe ein Problem das ich einfach nicht in den Griff bekomme.
In einer MySQL 5 DB sollen Datensätze upgedated werden.
Es gibt einen Array von ids und ein anderes Array mit Werten.
Alles soll mit einem Zugriff gemacht werden also ohne Schleife.

Mein bisheriger code sieht folgendermaßen aus.

Code:
sprintf("UPDATE `%s` SET sumL = CASE WHEN '%s' THEN '%s' ELSE '0' END WHERE id '%s'", $db,  implode("', '", $id), implode("', '", $anzL ),  implode("', '", $id) );

und so wie unten sieht der daraus entstehende Aufruf aus. Ich habe hier viele Werte herausgenommen wegen der bessern Lesbarkeit. Es sind in Wirklichkeit viele Datensätze.

Code:
UPDATE `besucher` SET sumL = CASE WHEN '1', '5', '7', '12', '19', '32' THEN '11', '2', '3', '24', '5', '1', ELSE '0' END WHERE id '1', '5', '7', '12', '19', '32'

Ich habe schon alle Varianten mit Klammer und Hochkomma und ohne alle ausprobiert aber es funktioniert nicht.
 
Werbung:

ukulele

Datenbank-Guru
Beiträge
4.579
Ich denke mal das das mit der Werteliste im THEN Bereich nicht funktioniert, da wird vermutlich nur ein Wert gehen der gesetzt wird, wenn die Bedingung davor wahr ist. Probiers mal so, auch wenn es zur Erstellung aufwendiger ist:
Code:
UPDATE    `besucher`
SET        sumL = (    CASE sumL
                    WHEN '1'    THEN '11'
                    WHEN '5'    THEN '2'
                    WHEN '7'    THEN '3'
                    WHEN '12'    THEN '24'
                    WHEN '19'    THEN '5'
                    WHEN '32'    THEN '1'
                    ELSE '0'
                    END )
WHERE    id IN ( '1', '5', '7', '12', '19', '32')
 

michaldo

Benutzer
Beiträge
6
Hallo ukulele,
Das sieht zwar cool aus aber ich habe keine Ahnung wie ich das in einem Aufruf hinbekommen soll.
Beide Werte, also das WHEN das die betroffenen ids darstellt und auch das THEN das den neuen Wert enthält sind so gut wie bei jedem Aufruf verschieden. Da es im schlimmsten Fall gut 800 Einträge wäre möchte ich es wenn möglich nicht in einer Schleife machen. Mit einer Schleife wäre es leicht das zu machen allerdings wird eben dabei die DB regelrecht bomadiert und dass wohl alle paar Minuten.
Das IN funktioniert in diesem Fall wohl nur im WHERE clause soviel ich jetzt erkannt habe.
Wenn ich also den Aufruf so schreibe funktioniert er nicht.
Code:
sprintf("UPDATE `%s` SET sumL = (CASE sumL
                               WHEN '%s' THEN '%s' ELSE '0' END)
                               WHERE id IN '%s'",
                               $db,  implode("', '", $id), implode("', '", $anzL ),  implode("', '", $id)  );
Wie könnte ich das doch noch in einem Aufruf ohne Schleife realisieren?
 

ukulele

Datenbank-Guru
Beiträge
4.579
Das IN funktioniert auch im WHEN Teil, allerdings muss man bei der CASE Anweisung eine Sache beachten:

Schreibe ich CASE feld WHEN wertalt THEN wertneu END, geht das. Ist meine Bedingung irgendetwas anderes als =, z.B. IN, muss ich das anders aufbauen: CASE WHEN feld = wertalt THEN wertneu END oder CASE WHEN feld != wertalt THEN wertneu END oder CASE WHEN feld IN werteliste THEN wertneu END, etc.

Es müsste also folgendes gehen:
Code:
UPDATE    `besucher`
SET        sumL = (    CASE
                    WHEN sumL = '1'        THEN '11'
                    WHEN sumL = '5'        THEN '2'
                    WHEN sumL = '7'        THEN '3'
                    WHEN sumL = '12'    THEN '24'
                    WHEN sumL = '19'    THEN '5'
                    WHEN sumL = '32'    THEN '1'
                    ELSE '0'
                    END )
WHERE    id IN ( '1', '5', '7', '12', '19', '32')
oder auch
Code:
UPDATE    `besucher`
SET        sumL = (    CASE
                    WHEN sumL IN ( '1', '5', '7', '12', '19', '32')    THEN '11'
                    ELSE '0'
                    END )
WHERE    id IN ( '1', '5', '7', '12', '19', '32')
Allerdings hast du bei letzterm natürlich immer nur einen Wert der bei wahrer Bedingung gesetzt werden kann. Einen anderen Weg, mit Hilfe der CASE Anweisung, kenne ich nicht.

Alternativ kannst du vieleicht einfach 800 Update Befehle durchlaufen, das sollte ähnlich schnell sein.
 

volvisti

Benutzer
Beiträge
7
Hallo zusammen,
ich hab hier einen ähnlichen Fall ...
Hab mich beim Import der Kategorie-IDs vertan und will nun die Kategorie-ID entsprechend einer Liste ändern ändern.
Gemäß dem hier von Ukele angegebeben Beispiel hab ich mein Statement (hier gekürzt) folgendermaßen aufgebaut:

UPDATE `xt_products_to_categories` SET `categories_id`= (case `categories_id` when '3' then '2' when '4' then '14' end)

Jetzt sagt mir phpMyAdmin bei der Eingabe des Statements

upload_2016-6-16_11-35-8.png

Wo liegt mein Fehler, oder liegt es an phpMyAdmin?

Danke Euch
 

akretschmer

Datenbank-Guru
Beiträge
9.420
in PG geht:

Code:
test=# create table volvisti as select * from generate_series(1, 10) s;
SELECT 10
test=*# select * from volvisti ;
 s  
----
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
(10 Zeilen)

test=*# update volvisti set s = case when s=2 then 22 when s= 5 then 55 else s end;
UPDATE 10
test=*# select * from volvisti ;
 s  
----
  1
 22
  3
  4
 55
  6
  7
  8
  9
 10
(10 Zeilen)

test=*#
 

ukulele

Datenbank-Guru
Beiträge
4.579
Also es gibt zwei Möglichkeiten CASE-Schleifen aufzubauen:
Code:
CASE a WHEN b THEN c END
oder
Code:
CASE WHEN a=b THEN c END
Probier mal die zweite, möglicherweise kennt MySQL oder PHPmyAdmin die erste nicht. Die zweite hat auch den Vorzug das man nicht nur = als Operator verwenden kann sondern auch IN, LIKE, etc., der einzige Nachteil ist die etwas längere Schreibweise da jedesmal a= dort stehen muss.
 

volvisti

Benutzer
Beiträge
7
Hallo,
danke Euch für die Hilfe.
Hab die Meldung einfach mal in einer Testtabelle ignoriet und es hat auch mit den roten Punkten vor der Zeile geklappt.:rolleyes:

Hat mich zuerst verunsichert. :confused:

Schönen Tag noch. :)
 

volvisti

Benutzer
Beiträge
7
zu früh gefreut :(

Leider liegt auf der Spalte categories_id ein Primärschlüssel und ein Index.
upload_2016-6-16_13-23-32.png

Das war in meiner Test-Tabelle natürlich nicht so.

Geht es dann überhaupt?
Was kann ich tun?
 

ukulele

Datenbank-Guru
Beiträge
4.579
Indexe kann man löschen und neu anlegen.

Primary Keys kann man auch ändern aber hierbei darf der PK natürlich zu keinem Zeitpunkt doppelt sein. Falls der PK irgendwo als FK dient muss ich dir dringend abraten da MySQL referentielle Intigrität meines Wissens nach nicht durchsetzt. Das wird dann ein Blindflug über die PKs.
 
Werbung:
Oben