Verwenden Sie CASE, um Spalten in der UPDATE-Abfrage auszuwählen.

11

Ich kann verwenden, CASEum auszuwählen, welche Spalten in einer SELECTAbfrage angezeigt werden sollen (Postgres), wie folgt:

SELECT CASE WHEN val = 0 THEN column_x
            WHEN val = 1 THEN column_y
            ELSE 0
       END AS update, ...

Ist etwas Ähnliches überhaupt möglich, wenn eine UPDATEAbfrage in Postgres ausgeführt wird (dh wählen Sie aus, welche Spalten aktualisiert werden sollen)? Ich nehme nicht an, da ich nichts darüber finden konnte, aber vielleicht hat jemand eine clevere Alternative (außer eine Prozedur zu verwenden oder jede Spalte mit a CASEzu aktualisieren, um zu bestimmen, ob dem Wert der Spalte ein neuer Wert zugewiesen oder einfach der vorhandene neu zugewiesen werden soll Wert). Wenn es keine einfache Alternative gibt, akzeptiere ich das natürlich auch als Antwort.

Zusätzliche Informationen : In meinem Fall habe ich 14 potenzielle Spalten, die aktualisiert werden können, wobei nur eine pro übereinstimmender Zeile aktualisiert wird (die zu aktualisierende Tabelle wird mit einer anderen in der Abfrage verknüpft). Die Anzahl der zu aktualisierenden Zeilen wird höchstwahrscheinlich variieren und Dutzende oder Hunderte betragen. Ich glaube, dass Indizes für die Beitrittsbedingungen vorhanden sind.

Newenglander
quelle

Antworten:

24

Wenn Sie angeben, dass eine Spalte aktualisiert werden soll, wird sie immer aktualisiert. Sie können jedoch den von Ihnen eingegebenen Wert bedingt ändern und die ursprünglichen Werte abhängig von Ihren Bedingungen zurücksetzen. Etwas wie:

UPDATE some_table
SET    column_x = CASE WHEN should_update_x THEN new_value_for_x ELSE column_x END
     , column_y = CASE WHEN should_update_y THEN new_value_for_y ELSE column_y END
     , column_z = CASE WHEN should_update_z THEN new_value_for_z ELSE column_z END
FROM   ...

Wenn die Bedingungen für eine Aktualisierung einer bestimmten Spalte nicht stimmen, geben Sie einfach den aktuellen Wert zurück.

Beachten Sie, dass für jede übereinstimmende Zeile eine Aktualisierung angezeigt wird (auch wenn alle Spalten auf die bereits vorhandenen Werte gesetzt werden), es sei denn, Sie berücksichtigen diesen Umstand explizit , indem Sie ON- und WHERE-Klauseln filtern, was ein Leistungsproblem sein kann (dies wird der Fall sein) Wenn Sie schreiben, werden die Indizes aktualisiert, die entsprechenden Trigger werden ausgelöst, ...) wenn sie nicht gemildert werden.

David Spillett
quelle
Vielen Dank für den Tipp, dass alles aktualisiert wird. Wenn dies langsam ist, nehme ich möglicherweise den Vorschlag von @Colin 't Hart an, mehrere Aktualisierungsanweisungen zu haben.
Newenglander
Sie können dieses Problem vollständig beheben, indem Sie sicherstellen, dass Ihre ON- und WHERE-Klauseln alle Zeilen herausfiltern, in denen keine Änderungen erforderlich sind. Dies kann jedoch bedeuten, dass Sie alle Ihre Bedingungen sowohl in der SET-Klausel als auch in der WHERE-Klausel wiederholen (es sei denn, es gibt eine einfachere Gesamtprüfung, die dies überprüft ist 100% äquivalent zu all diesen Bedingungen zusammen). Zu diesem Zeitpunkt ist diese Methode möglicherweise noch effizienter, die Methode für mehrere Aktualisierungen ist jedoch möglicherweise einfacher zu warten.
David Spillett
Beachten
Colin 't Hart
@Colin: Ja, jedes Update wird durch das Transaktionsprotokoll der Datenbank geleitet, einschließlich Updates, die im Wesentlichen NoOps sind, da Felder aktualisiert werden, um dieselben Werte wie zuvor zu haben. Neben dem Potenzial für ein sofortiges Leistungsproblem kann dies ein wichtiger Faktor bei der Verwendung von Replikation, differenziellen Sicherungen, Protokollversand usw. sein, da die zusätzlichen Zeilenaktualisierungsvorgänge den dafür benötigten Speicherplatz / die erforderliche Bandbreite erhöhen.
David Spillett
Vielen Dank an euch beide für die Tipps, in meinem Fall hat die einzelne Update-Anweisung gut funktioniert.
Newenglander
5

Wie viele verschiedene Kombinationen von Spalten müssen aktualisiert werden? Wie viele Zeilen der gesamten Tabelle werden aktualisiert? Sind Indizes für den schnellen Zugriff auf zu aktualisierende Zeilen vorhanden?

Abhängig von den Antworten auf diese Fragen können Sie möglicherweise mehrere Aktualisierungsanweisungen ausführen, eine für jede Spalte, die Sie aktualisieren möchten, und die Bedingung für den Wert dieser Spalte in der where-Klausel der Aktualisierung platzieren, sodass in dieser Spalte keine Zeilen aktualisiert werden hat den falschen Wert.

Versuchen Sie, satzbasiert zu denken. Gehen Sie nicht davon aus, dass für die Aktualisierung eine einzelne Zeile aktualisiert werden muss, die vom Primärschlüssel gefunden wurde.

Colin 't Hart
quelle
Danke für die Antwort. Ich habe meiner Frage weitere Informationen hinzugefügt. Ich hoffe, sie sind verständlich. Das ist eine gute Alternative mit mehreren Update-Anweisungen (ich würde eine Update-Anweisung bevorzugen, aber ich sehe, dass es dort einen Vorteil gibt).
Newenglander
Dies mag die Antwort sein, nach der ich suche, aber wollen Sie update column_x = new_value_for_x mit @val = 0 setzen? Ich kann mit so etwas experimentieren. Sieht witzig aus. Ist nicht einfacher zu tun, wenn val = 0 mit der Aktualisierung beginnt column_x = new_value_for_x usw.
CashCow
-1
update Practicing  -- table you will be updating
 set email = case -- column you will be updating
    when FName = 'Glenn' then '[email protected]'
       when FName = 'Riddick' then '[email protected]'
       when FName = 'Jeffrey' then 'sorcerer@wizcom'
       else email
    end
user134695
quelle
Dadurch wird nur eine einzelne Spalte aktualisiert, während der Fragesteller wissen möchte, wie verschiedene Spalten abhängig von den Bedingungen aktualisiert werden können.
Colin 't Hart