Wie kann ich eine UPDATE-Anweisung mit JOIN in SQL Server ausführen?

1314

Ich muss diese Tabelle in SQL Server mit Daten aus der übergeordneten Tabelle aktualisieren (siehe unten):

Tabelle: Verkauf

id (int)
udid (int)
assid (int)

Tabelle: ud

id  (int)
assid  (int)

sale.assidenthält den richtigen zu aktualisierenden Wert ud.assid.

Welche Abfrage wird dies tun? Ich denke an ein join, bin mir aber nicht sicher, ob es möglich ist.

Ant Swift
quelle
3
Welches RDBMS verwenden Sie? MySQL, SQL Server, Oracle, PostgreSQL oder etwas anderes?
Chris J
einige Beziehungen zwischen den Tabellen? Wie kann man wissen, welcher Datensatz aus dem Verkauf welchem ​​Datensatz aus ud entspricht? Basiert es auf der ID als Primärschlüssel in beiden Tabellen?
Cătălin Pitiș
Wie können Sie UD aktualisieren? Es hat nur den Assid und seine eigene ID. Können Sie ein Beispiel für die tatsächlich vorhandenen Werte und die Datensätze geben, die Sie aufgrund des Skripts ändern oder hinzufügen möchten?
Bernhard Hofmann
2
Benutzer-Alias ​​in Abfrage wie stackoverflow.com/questions/982919/sql-update-query-using-joins
Imran Muhammad

Antworten:

2383

Die Syntax hängt streng davon ab, welches SQL-DBMS Sie verwenden. Hier sind einige Möglichkeiten, dies in ANSI / ISO (auch bekannt als SQL DBMS), MySQL, SQL Server und Oracle zu tun. Beachten Sie, dass meine vorgeschlagene ANSI / ISO-Methode in der Regel viel langsamer ist als die beiden anderen Methoden. Wenn Sie jedoch ein anderes SQL-DBMS als MySQL, SQL Server oder Oracle verwenden, ist dies möglicherweise der einzige Weg (z wenn Ihr SQL DBMS dies nicht unterstützt MERGE):

ANSI / ISO:

update ud 
     set assid = (
          select sale.assid 
          from sale 
          where sale.udid = ud.id
     )
 where exists (
      select * 
      from sale 
      where sale.udid = ud.id
 );

MySQL:

update ud u
inner join sale s on
    u.id = s.udid
set u.assid = s.assid

SQL Server:

update u
set u.assid = s.assid
from ud u
    inner join sale s on
        u.id = s.udid

PostgreSQL:

update ud
  set assid = s.assid
from sale s 
where ud.id = s.udid;

Beachten Sie, dass die Zieltabelle in der FROMKlausel für Postgres nicht wiederholt werden darf .

Orakel:

update
    (select
        u.assid as new_assid,
        s.assid as old_assid
    from ud u
        inner join sale s on
            u.id = s.udid) up
set up.new_assid = up.old_assid

SQLite:

update ud 
     set assid = (
          select sale.assid 
          from sale 
          where sale.udid = ud.id
     )
 where RowID in (
      select RowID 
      from ud 
      where sale.udid = ud.id
 );
Eric
quelle
3
Es sieht für mich so aus, als ob MySQL set assid = s.assidsein sollte set u.assid = s.assid.
Dotancohen
2
Was passiert in der ANSI-Syntax, wenn SELECT nach dem =mehr als eine Zeile zurückgibt?
Konto
2
@ ThrowawayAccount3Million Es würde wahrscheinlich scheitern. AFAIK, diese Art von Operation würde einen skalaren Wert erwarten und einen Fehler auslösen, wenn stattdessen eine Ergebnismenge angegeben wird.
Francis Lord
6
Ich wünschte, der OP würde einige bessere Namen für seine Tabelle und Spalten wählen !! es ist nicht so lesbar / intuitiv ...
S.Serpooshan
4
Postgre 9.3 funktionierte nur mitupdate ud set assid = s.assid
StackUnder
143

Dies sollte in SQL Server funktionieren:

update ud 
set assid = sale.assid
from sale
where sale.udid = id
edosoft
quelle
98

postgres

UPDATE table1
SET    COLUMN = value
FROM   table2,
       table3
WHERE  table1.column_id = table2.id
       AND table1.column_id = table3.id
       AND table1.COLUMN = value
       AND table2.COLUMN = value
       AND table3.COLUMN = value 
user1154043
quelle
20
Die Antwort wäre praktischer, wenn die in der Frage verwendeten Tabellen- / Spaltennamen verwendet würden. Warum enthält Ihre Antwort 3 Tabellen?
Alfonx
50

Ein Standard-SQL-Ansatz wäre

UPDATE ud
SET assid = (SELECT assid FROM sale s WHERE ud.id=s.id)

Unter SQL Server können Sie einen Join verwenden

UPDATE ud
SET assid = s.assid
FROM ud u
JOIN sale s ON u.id=s.id
MattH
quelle
1
Mit der ersten können Sie nicht mit 2+ Spalten übereinstimmen, aber Join funktioniert hervorragend.
Makciook
6
@ Makciook: nicht wahr? Sie können der WHEREKlausel einfach weitere Bedingungen hinzufügen , wenn Sie mit zusätzlichen Spalten übereinstimmen möchten.
Siride
2
Nur eine Kleinigkeit ... aber ich denke, das OP bedeutete sale.udid = ud.id. Und nicht sale.id.
Skippy VonDrake
39

PostgreSQL :

CREATE TABLE ud (id integer, assid integer);
CREATE TABLE sales (id integer, udid integer, assid integer);

UPDATE ud
SET assid = sales.assid
FROM sales
WHERE sales.id = ud.id;
Alfonx
quelle
26

Vereinfachte Update Abfrage mit JOIN mehrere Tabellen -Ing.

   UPDATE
        first_table ft
        JOIN second_table st ON st.some_id = ft.some_id
        JOIN third_table tt  ON tt.some_id = st.some_id
        .....
    SET
        ft.some_column = some_value
    WHERE ft.some_column = 123456 AND st.some_column = 123456

Hinweis - first_table, second_table, Third_table und some_column wie 123456 sind Demo-Tabellennamen, Spaltennamen und IDs. Ersetzen Sie sie durch die gültigen Namen.

Vinit Kadkol
quelle
16

Ein weiteres Beispiel, warum SQL nicht wirklich portabel ist.

Für MySQL wäre es:

update ud, sale
set ud.assid = sale.assid
where sale.udid = ud.id;

Weitere Informationen finden Sie unter Aktualisierung mehrerer Tabellen: http://dev.mysql.com/doc/refman/5.0/en/update.html

UPDATE [LOW_PRIORITY] [IGNORE] table_references
    SET col_name1={expr1|DEFAULT} [, col_name2={expr2|DEFAULT}] ...
    [WHERE where_condition]
Yada
quelle
2
+1 auf den Kommentar "Warum SQL nicht wirklich portabel ist"! Die Portabilität ist so fragil, dass nur das Deklarieren einer Variablen die Portabilität vieler gängiger Datenbank-Engines beeinträchtigt.
Jeff Moden
8

Teradata Aster bietet einen weiteren interessanten Weg, um das Ziel zu erreichen:

MERGE INTO ud --what trable should be updated
USING sale -- from what table/relation update info should be taken
ON ud.id = sale.udid --join condition
WHEN MATCHED THEN 
    UPDATE SET ud.assid = sale.assid; -- how to update
xhudik
quelle
8

Ich dachte, der SQL-Server im oberen Beitrag würde für Sybase funktionieren, da beide T-SQL sind, aber leider nicht.

Für Sybase habe ich festgestellt, dass das Update in der Tabelle selbst und nicht im Alias ​​enthalten sein muss:

update ud
set u.assid = s.assid
from ud u
    inner join sale s on
        u.id = s.udid
Ken Goh
quelle
7

Die folgende Anweisung mit dem Schlüsselwort FROM wird verwendet, um mehrere Zeilen mit einem Join zu aktualisieren

UPDATE users 
set users.DivisionId=divisions.DivisionId
from divisions join users on divisions.Name=users.Division
Sheryar Nizar
quelle
7

MySQL

Sie erzielen die beste Leistung, wenn Sie die where-Klausel vergessen und alle Bedingungen in den ON-Ausdruck einfügen.

Ich denke, das liegt daran, dass die Abfrage zuerst die Tabellen verknüpfen muss und dann die where-Klausel darauf ausführt. Wenn Sie also reduzieren können, was für die Verknüpfung erforderlich ist, ist dies der schnellste Weg, um die Ergebnisse zu erhalten / das udpate auszuführen.

Beispiel

Szenario

Sie haben eine Benutzertabelle. Sie können sich mit ihrem Benutzernamen, ihrer E-Mail-Adresse oder ihrer Kontonummer anmelden. Diese Konten können aktiv (1) oder inaktiv (0) sein. Diese Tabelle enthält 50000 Zeilen

Sie haben dann eine Tabelle mit Benutzern, die Sie auf einmal deaktivieren können, weil Sie herausfinden, dass sie alle etwas Schlechtes getan haben. Diese Tabelle enthält jedoch eine Spalte mit gemischten Benutzernamen, E-Mails und Kontonummern. Es hat auch einen "has_run" Indikator, der auf 1 (true) gesetzt werden muss, wenn es ausgeführt wurde

Abfrage

UPDATE users User
    INNER JOIN
        blacklist_users BlacklistUser
        ON
        (
            User.username = BlacklistUser.account_ref
            OR
            User.email = BlacklistedUser.account_ref
            OR
            User.phone_number = BlacklistUser.account_ref
            AND
            User.is_active = 1
            AND
            BlacklistUser.has_run = 0
        )
    SET
        User.is_active = 0,
        BlacklistUser.has_run = 1;

Argumentation

Wenn wir nur unter den OR-Bedingungen beitreten müssten, müsste im Wesentlichen jede Zeile viermal überprüft werden, um festzustellen, ob sie beitreten sollte, und möglicherweise viel mehr Zeilen zurückgeben. Wenn Sie jedoch mehr Bedingungen festlegen, können viele Zeilen "übersprungen" werden, wenn sie beim Verbinden nicht alle Bedingungen erfüllen.

Bonus

Es ist besser lesbar. Alle Bedingungen befinden sich an einem Ort und die zu aktualisierenden Zeilen befinden sich an einem Ort

Luke Watts
quelle
4

Und in MS ACCESS:

UPDATE ud 
INNER JOIN sale ON ud.id = sale.udid
SET ud.assid = sale.assid;
Richard
quelle
1
Zur Vorsicht muss das SET unmittelbar nach der Recordset-Definition kommen! Ich habe gerade versucht, ein ähnliches Szenario in einer Access-Datenbank zu erarbeiten, für das eine WHERE-Klausel erforderlich war (diese würde nicht als gültige ON-Bedingung akzeptiert). WO musste als letztes kommen, um Syntaxfehler zu vermeiden.
Dodekaphone
3
UPDATE tblAppraisalBasicData
SET tblAppraisalBasicData.ISCbo=1
FROM tblAppraisalBasicData SI INNER JOIN  aaa_test RAN ON SI.EmpID = RAN.ID
Abdullah Yousuf
quelle
3

Versuchen Sie dieses, ich denke, das wird für Sie funktionieren

update ud

set ud.assid = sale.assid

from ud 

Inner join sale on ud.id = sale.udid

where sale.udid is not null
HARSHIT RATHORE
quelle
2

Verwenden Sie für SQLite die RowID-Eigenschaft, um das Update durchzuführen:

update Table set column = 'NewValue'
where RowID = 
(select t1.RowID from Table t1
join Table2 t2 on t1.JoinField = t2.JoinField
where t2.SelectValue = 'FooMyBarPlease');
KeithTheBiped
quelle
1
Könnten Sie das ein bisschen erklären?
Mohammed Noureldin
1
@ MohammedNoureldin Ich werde versuchen zu erklären. Das Problem besteht darin, wie eine Tabelle mit einem Ergebnis einer Abfrage in einem Join unter Verwendung derselben Tabelle aktualisiert wird. Die Anweisung (Unterauswahl) verhält sich wie ein Join und gibt das Systemfeld RowID zurück, eine eindeutige Nummer für jede Zeile in einer Tabelle. Da die Unterauswahl mehrere Zeilen zurückgeben kann, wählt "where RowID =" eine einzelne richtige Zeile aus der resultierenden Unterauswahl aus und aktualisiert die Spalte. Lassen Sie mich wissen, wenn Sie weitere Erläuterungen benötigen oder eine Variation dieses Themas herausfinden möchten.
KeithTheBiped