SQL-Aktualisierungsfelder einer Tabelle aus Feldern einer anderen

124

Ich habe zwei Tabellen:

A [ID, column1, column2, column3]
B [ID, column1, column2, column3, column4]

Awird immer eine Teilmenge von sein B(dh alle Spalten von Asind auch in B).

Ich möchte einen Datensatz mit einem bestimmten IDIn Bmit ihren Daten aus Afür alle Spalten von aktualisieren A. Dies IDexistiert sowohl in Aals auch B.

Gibt es eine UPDATESyntax oder eine andere Möglichkeit, dies zu tun, ohne die Spaltennamen anzugeben und nur "Alle Spalten von A setzen" zu sagen ?

Ich verwende PostgreSQL, daher wird auch ein bestimmter nicht standardmäßiger Befehl akzeptiert (jedoch nicht bevorzugt).

Nir
quelle
Ich denke, das ist, was Sie tun wollen, dba.stackexchange.com/a/58383
zubair-0

Antworten:

234

Sie können die nicht standardmäßige FROM- Klausel verwenden.

UPDATE b
SET column1 = a.column1,
  column2 = a.column2,
  column3 = a.column3
FROM a
WHERE a.id = b.id
AND b.id = 1
Scott Bailey
quelle
9
Die Frage ist, wie es geht, ohne alle Spaltennamen anzugeben. (Und ich auch.)
Hinweis
2
Ich stimme @cluesque zu, aber diese Antwort ist eine hervorragende Möglichkeit, Werte in einer Spalte in einer Tabelle als Nachschlagetabelle zum Ersetzen von Werten in einer Spalte in einer anderen Tabelle zu verwenden (siehe SO 21657475 ), also +1 ...
Victoria Stuart
1
Warum wird b.id = 1 benötigt?
YasirAzgar
1
@YasirAzgar die b.id = 1 soll begrenzen, welche Zeilen in b aktualisiert werden. Andernfalls würden wir jede Zeile in der Tabelle aktualisieren. Gelegentlich könnte es das sein, was Sie wollen. Die ursprüngliche Frage war jedoch, eine bestimmte Zeile in b zu aktualisieren.
Scott Bailey
Dies war das, was ich für mein spezielles Problem benötigte: Aktualisieren der Spalte einer Tabelle mit Werten aus der anders benannten Spalte einer anderen Tabelle.
Muad-Dweeb
49

Die Frage ist alt, aber ich hatte das Gefühl, dass die beste Antwort noch nicht gegeben wurde.

Gibt es eine UPDATESyntax ... ohne Angabe der Spaltennamen ?

Allgemeine Lösung mit dynamischem SQL

Sie müssen keine Spaltennamen kennen, außer einigen eindeutigen Spalten, an denen Sie teilnehmen möchten (id im Beispiel). Funktioniert zuverlässig für jeden möglichen Eckfall, den ich mir vorstellen kann.

Dies ist spezifisch für PostgreSQL. Ich erstelle dynamischen Code basierend auf dem information_schema , insbesondere der Tabelle information_schema.columns, die im SQL-Standard definiert ist und von den meisten wichtigen RDBMS (außer Oracle) verwendet wird. Eine DOAnweisung mit PL / pgSQL- Code, der dynamisches SQL ausführt, ist jedoch keine PostgreSQL-Syntax.

DO
$do$
BEGIN

EXECUTE (
SELECT
  'UPDATE b
   SET   (' || string_agg(        quote_ident(column_name), ',') || ')
       = (' || string_agg('a.' || quote_ident(column_name), ',') || ')
   FROM   a
   WHERE  b.id = 123
   AND    a.id = b.id'
FROM   information_schema.columns
WHERE  table_name   = 'a'       -- table name, case sensitive
AND    table_schema = 'public'  -- schema name, case sensitive
AND    column_name <> 'id'      -- all columns except id
);

END
$do$;

Angenommen, bfür jede Spalte eine passende Spalte a, aber nicht umgekehrt.bkann zusätzliche Spalten haben.

WHERE b.id = 123 ist optional, um eine ausgewählte Zeile zu aktualisieren.

SQL Fiddle.

Verwandte Antworten mit mehr Erklärung:

Teillösungen mit einfachem SQL

Mit Liste der freigegebenen Spalten

Sie müssen noch die Liste der Spaltennamen kennen, die beide Tabellen gemeinsam haben. Mit einer Syntaxverknüpfung zum Aktualisieren mehrerer Spalten - auf jeden Fall kürzer als die anderen bisher vorgeschlagenen Antworten.

UPDATE b
SET   (  column1,   column2,   column3)
    = (a.column1, a.column2, a.column3)
FROM   a
WHERE  b.id = 123    -- optional, to update only selected row
AND    a.id = b.id;

SQL Fiddle.

Diese Syntax wurde 2006 mit Postgres 8.2 eingeführt, lange bevor die Frage gestellt wurde. Details im Handbuch.

Verbunden:

Mit Liste der Spalten in B

Wenn alle Spalten Adefiniert sind NOT NULL(aber nicht unbedingt B),
und Sie kennen die Spaltennamen von B(aber nicht unbedingt A).

UPDATE b
SET   (column1, column2, column3, column4)
    = (COALESCE(ab.column1, b.column1)
     , COALESCE(ab.column2, b.column2)
     , COALESCE(ab.column3, b.column3)
     , COALESCE(ab.column4, b.column4)
      )
FROM (
   SELECT *
   FROM   a
   NATURAL LEFT JOIN  b -- append missing columns
   WHERE  b.id IS NULL  -- only if anything actually changes
   AND    a.id = 123    -- optional, to update only selected row
   ) ab
WHERE b.id = ab.id;

Der NATURAL LEFT JOINverbindet eine Zeile, aus der balle gleichnamigen Spalten dieselben Werte enthalten. In diesem Fall benötigen wir kein Update (nichts ändert sich) und können diese Zeilen zu Beginn des Prozesses entfernen ( WHERE b.id IS NULL).
Wir müssen noch eine passende Zeile finden, also b.id = ab.idin der äußeren Abfrage.

db <> hier fummeln
Alte sqlfiddle.

Dies ist Standard-SQL mit Ausnahme der FROMKlausel .
Es funktioniert unabhängig davon, in welcher der Spalten tatsächlich vorhanden ist A, aber die Abfrage kann nicht zwischen tatsächlichen NULL-Werten und fehlenden Spalten in unterscheiden. Daher Aist es nur dann zuverlässig, wenn alle Spalten in Adefiniert sind NOT NULL.

Es gibt mehrere mögliche Variationen, je nachdem, was Sie über beide Tabellen wissen .

Erwin Brandstetter
quelle
Die Kraft von SQL! Gerade bemerkt, wenn Sie Klammern in die set-Klausel SET (column1) = (a.column)einfügen ( ) Postgres wird es als eine andere Art von Update behandeln und geben und Fehler wie folgt:source for a multiple-column UPDATE item must be a sub-SELECT or ROW() expression
Edgar Ortega
26

Ich arbeite seit mehr als zehn Jahren mit der IBM DB2-Datenbank und versuche nun, PostgreSQL zu lernen.

Es funktioniert unter PostgreSQL 9.3.4, aber nicht unter DB2 10.5:

UPDATE B SET
     COLUMN1 = A.COLUMN1,
     COLUMN2 = A.COLUMN2,
     COLUMN3 = A.COLUMN3
FROM A
WHERE A.ID = B.ID

Hinweis: Das Hauptproblem ist die FROM-Ursache, die in DB2 und auch nicht in ANSI SQL nicht unterstützt wird.

Es funktioniert unter DB2 10.5, aber NICHT unter PostgreSQL 9.3.4:

UPDATE B SET
    (COLUMN1, COLUMN2, COLUMN3) =
               (SELECT COLUMN1, COLUMN2, COLUMN3 FROM A WHERE ID = B.ID)

ENDLICH! Es funktioniert sowohl mit PostgreSQL 9.3.4 als auch mit DB2 10.5:

UPDATE B SET
     COLUMN1 = (SELECT COLUMN1 FROM A WHERE ID = B.ID),
     COLUMN2 = (SELECT COLUMN2 FROM A WHERE ID = B.ID),
     COLUMN3 = (SELECT COLUMN3 FROM A WHERE ID = B.ID)
Jochan
quelle
3
Beachten Sie, dass die zweite und dritte Abfrage der ersten nicht vollständig entsprechen. Wenn keine übereinstimmende Zeile gefunden wird B, führt die erste Anweisung nichts aus (die ursprüngliche Zeile bleibt unberührt), während die anderen beiden Spalten mit NULL-Werten überschreiben.
Erwin Brandstetter
7

Das ist eine große Hilfe. Der Code

UPDATE tbl_b b
SET   (  column1,   column2,   column3)
    = (a.column1, a.column2, a.column3)
FROM   tbl_a a
WHERE  b.id = 1
AND    a.id = b.id;

funktioniert perfekt.

Beachten Sie, dass Sie eine Klammer "" in benötigen

From "tbl_a" a

damit es funktioniert.

user2493970
quelle
5

Nicht unbedingt das, was Sie gefragt haben, aber vielleicht hilft die Verwendung der Postgres-Vererbung?

CREATE TABLE A (
    ID            int,
    column1       text,
    column2       text,
    column3       text
);

CREATE TABLE B (
    column4       text
) INHERITS (A);

Dadurch wird vermieden, dass B aktualisiert werden muss.

Lesen Sie jedoch unbedingt alle Details .

Andernfalls wird das, wonach Sie fragen, nicht als bewährte Methode angesehen. Dynamische SELECT * ...Dinge wie Ansichten mit werden nicht empfohlen (da eine solche leichte Bequemlichkeit mehr Dinge zerstören als helfen kann), und was Sie verlangen, wäre für den UPDATE ... SETBefehl gleichwertig .

Unvernunft
quelle
Ich bin mir nicht sicher, wie die Vererbung dies lösen wird. Meinen Sie damit, einen Update-Trigger für A hinzuzufügen, der auch B aktualisiert? Ich möchte A nicht immer mit B synchronisieren, nur auf Anfrage. In diesem Fall kann ich die Trigger nicht verwenden.
Nir
2
Ja, wenn dies nur in bestimmten Fällen der Fall ist, funktioniert die Vererbung nicht. In diesem Fall rate ich von einem dynamischen Abfrageansatz ab. (Es gibt immer noch Möglichkeiten, dies mithilfe von Postgres-Prozedursprachen zu erreichen. Auch wenn Sie Trigger verwenden möchten, können Sie diese verwenden - indem Sie ein Synchronisierungsfeld hinzufügen, z. B. nur einen Trigger auslösen, wenn dieser festgelegt ist.)
Unvernunft
0

Sie können dazu dynamisches SQL erstellen und ausführen, aber es ist wirklich nicht ideal

Daniel Brink
quelle
Ich habe darüber nachgedacht. Ich dachte, ich könnte meine Abfrage mit späteren Änderungen an beiden Tabellen kompatibel machen, aber dynamisches SQL scheint zu kompliziert zu sein, als nur alle Felder anzugeben und die Vorwärtskompatibilität zu vergessen.
Nir
Ja, es wird kompliziert sein, sollte aber vorwärtskompatibel mit späteren Spalten sein, die hinzugefügt oder entfernt werden. Sie müssen zuerst eine Abfrage durchführen, um die Spaltennamen aus beiden Tabellen abzurufen, dann die Spaltennamen abgleichen und dann die dynamische SQL schreiben, um die Aktualisierung basierend auf den übereinstimmenden Spaltennamen durchzuführen. Eigentlich ein lustiges Projekt :)
Daniel Brink
-4

Versuchen Sie Folgendes

Update A a, B b, SET a.column1=b.column1 where b.id=1

BEARBEITET: - Aktualisieren Sie mehr als eine Spalte

Update A a, B b, SET a.column1=b.column1, a.column2=b.column2 where b.id=1
Salil
quelle
Ich verstehe nicht, wie es Spalte1, Spalte2 und Spalte3 kopiert. Und ich muss Spalte 1 ausdrücklich erwähnen.
Nir
Funktioniert bei mir nicht Ich erhalte den folgenden Fehler: FEHLER: Syntaxfehler bei oder in der Nähe von ","
melbic
1
Diese nicht standardmäßige Syntax würde UPDATEin MySQL funktionieren , ist jedoch für PostgreSQL ungültig.
Erwin Brandstetter