Jak mogę wykonać instrukcję UPDATE z JOIN w SQL Server?

1314

Muszę zaktualizować tę tabelę w programie SQL Server danymi z jej tabeli „nadrzędnej”, patrz poniżej:

Tabela: sprzedaż

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

Tabela: ud

id  (int)
assid  (int)

sale.assidzawiera poprawną wartość do aktualizacji ud.assid.

Jakie zapytanie to zrobi? Myślę o, joinale nie jestem pewien, czy to możliwe.

Ant Swift
źródło
3
Jakiego RDBMS używasz? MySQL, SQL Server, Oracle, PostgreSQL czy coś innego?
Chris J,
jakieś relacje między stołami? Skąd można wiedzieć, który rekord ze sprzedaży odpowiada, który rekord z ud? Czy jest oparty na id jako kluczu podstawowym w obu tabelach?
Cătălin Pitiș
Jak możesz zaktualizować UD? Ma tylko asystenta i własny identyfikator. Czy możesz podać przykład istniejących wartości oraz rekordów, które chciałbyś zmienić lub dodać w wyniku skryptu?
Bernhard Hofmann,
2
Alias ​​użytkownika w zapytaniu, taki jak stackoverflow.com/questions/982919/sql-update-query-using-joins
Imran Muhammad

Odpowiedzi:

2383

Składnia ściśle zależy od używanego SQL DBMS. Oto kilka sposobów, aby to zrobić w ANSI / ISO (aka powinien działać na dowolnym SQL DBMS), MySQL, SQL Server i Oracle. Należy pamiętać, że moja sugerowana metoda ANSI / ISO będzie zwykle znacznie wolniejsza niż dwie pozostałe metody, ale jeśli używasz SQL DBMS innego niż MySQL, SQL Server lub Oracle, może to być jedyna droga (np. jeśli Twój SQL DBMS nie obsługuje 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;

Pamiętaj, że tabeli docelowej nie wolno powtarzać w FROMklauzuli dotyczącej Postgres.

Wyrocznia:

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
źródło
3
Wydaje mi się, że MySQL set assid = s.assidpowinien być set u.assid = s.assid.
dotancohen
2
W składni ANSI, co się stanie, jeśli SELECT po =zwróci więcej niż jeden wiersz?
Wyrzuć konto
2
@ ThrowawayAccount3Million Prawdopodobnie się nie powiedzie. AFAIK, tego rodzaju operacja oczekiwałaby wartości skalarnej i wyrzuci błąd, jeśli zamiast tego otrzyma zestaw wyników.
Francis Lord
6
Chciałbym, żeby OP wybrał lepsze nazwy dla swojej tabeli i kolumn !! nie jest tak czytelny / intuicyjny ...
S.Serpooshan,
4
Postgre 9.3 działał tylko przy użyciuupdate ud set assid = s.assid
StackUnder
143

Powinno to działać w programie SQL Server:

update ud 
set assid = sale.assid
from sale
where sale.udid = id
edosoft
źródło
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 
użytkownik1154043
źródło
20
Odpowiedź byłaby bardziej przydatna, gdyby używał nazw tabel / kolumn użytych w pytaniu. Dlaczego w twojej odpowiedzi są 3 tabele?
alfonx
50

Byłoby to standardowe podejście SQL

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

Na SQL Server możesz użyć sprzężenia

UPDATE ud
SET assid = s.assid
FROM ud u
JOIN sale s ON u.id=s.id
MattH
źródło
1
W pierwszym przypadku nie można dopasować do ponad 2 kolumn, ale dołączenie działa świetnie.
makciook
6
@makciook: huh? Możesz po prostu dodać więcej warunków w WHEREklauzuli, jeśli chcesz dopasować dodatkowe kolumny.
siride,
2
Tylko nit ... ale myślę, że OP oznaczało sale.udid = ud.id. I nie 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
źródło
26

Uproszczone zapytanie o aktualizację przy użyciu JOIN -ing wielu tabel.

   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

Uwaga - pierwsza_tabela, druga_tabela, trzecia_tabela i jakaś kolumna jak 123456 to nazwy tabel demonstracyjnych, nazwy kolumn i identyfikatory. Zastąp je prawidłowymi nazwami.

Vinit Kadkol
źródło
16

Kolejny przykład, dlaczego SQL nie jest tak naprawdę przenośny.

W przypadku MySQL byłoby to:

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

Aby uzyskać więcej informacji, przeczytaj aktualizację wielu tabel: 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
źródło
2
+1 do komentarza „dlaczego SQL nie jest tak naprawdę przenośny”! Przenośność jest tak delikatna, że ​​samo zadeklarowanie zmiennej przerwie przenośność wśród wielu popularnych silników baz danych.
Jeff Moden
8

Teradata Aster oferuje kolejny ciekawy sposób na osiągnięcie celu:

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
źródło
8

Myślałem, że SQL Server z pierwszego posta będzie działał dla Sybase, ponieważ oba są T-SQL, ale niestety nie.

W przypadku Sybase zauważyłem, że aktualizacja musi znajdować się w tabeli, a nie w aliasie:

update ud
set u.assid = s.assid
from ud u
    inner join sale s on
        u.id = s.udid
Ken Goh
źródło
7

Poniższa instrukcja ze słowem kluczowym FROM służy do aktualizacji wielu wierszy za pomocą sprzężenia

UPDATE users 
set users.DivisionId=divisions.DivisionId
from divisions join users on divisions.Name=users.Division
Sheryar Nizar
źródło
7

MySQL

Najlepsze wyniki uzyskasz, jeśli zapomnisz klauzulę where i umieścisz wszystkie warunki w wyrażeniu ON.

Myślę, że dzieje się tak, ponieważ zapytanie najpierw musi dołączyć do tabel, a następnie uruchamia na nim klauzulę where, więc jeśli możesz zmniejszyć liczbę wymaganych elementów do przyłączenia, jest to najszybszy sposób na uzyskanie wyników / wykonanie udpate.

Przykład

Scenariusz

Masz tabelę użytkowników. Mogą zalogować się przy użyciu swojej nazwy użytkownika lub adresu e-mail lub numeru konta. Te konta mogą być aktywne (1) lub nieaktywne (0). Ta tabela ma 50000 wierszy

Następnie masz tabelę użytkowników do wyłączenia za jednym razem, ponieważ dowiadujesz się, że wszyscy zrobili coś złego. Ta tabela ma jednak jedną kolumnę zawierającą nazwy użytkowników, e-maile i numery kont. Ma także wskaźnik „has_run”, który należy ustawić na 1 (prawda) po uruchomieniu

Pytanie

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;

Rozumowanie

Gdybyśmy musieli dołączyć tylko warunki OR, w zasadzie musielibyśmy sprawdzać każdy wiersz 4 razy, aby zobaczyć, czy powinien się połączyć, i potencjalnie zwracać znacznie więcej wierszy. Jednak dając mu więcej warunków, może „pominąć” wiele wierszy, jeśli nie spełniają wszystkich warunków podczas łączenia.

Premia

Jest bardziej czytelny. Wszystkie warunki są w jednym miejscu, a wiersze do aktualizacji są w jednym miejscu

Luke Watts
źródło
4

I w MS ACCESS:

UPDATE ud 
INNER JOIN sale ON ud.id = sale.udid
SET ud.assid = sale.assid;
Richard
źródło
1
Uwaga: SET musi przyjść natychmiast po zdefiniowaniu zestawu rekordów! Właśnie próbowałem wypracować podobny scenariusz w bazie danych Access, który wymagał klauzuli WHERE (nie zaakceptowałby jej jako prawidłowego warunku WŁĄCZENIA). GDZIE musiało przyjść jako ostatnie, aby uniknąć błędów składniowych.
Dodekafon
4

Najprostszym sposobem jest użycie Common Table Expression (CTE) wprowadzonego w SQL 2005

with cte as
(select u.assid col1 ,s.assid col2 from ud u inner join sale s on u.id = s.udid)
update cte set col1=col2
Kemal AL GAZZAH
źródło
3
UPDATE tblAppraisalBasicData
SET tblAppraisalBasicData.ISCbo=1
FROM tblAppraisalBasicData SI INNER JOIN  aaa_test RAN ON SI.EmpID = RAN.ID
Abdullah Yousuf
źródło
3

Spróbuj tego, myślę, że to zadziała dla ciebie

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
źródło
2

W przypadku SQLite użyj właściwości RowID, aby dokonać aktualizacji:

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
źródło
1
Czy mógłbyś to trochę wyjaśnić?
Mohammed Noureldin
1
@MohammedNoureldin Spróbuję wyjaśnić. Problem polega na tym, jak zaktualizować tabelę, uzyskując wynik z zapytania dotyczącego sprzężenia przy użyciu tej samej tabeli. Instrukcja (sub-select) działa jak łączenie i zwraca pole systemowe RowID, które jest unikalnym numerem dla każdego wiersza w tabeli. Ponieważ zaznaczenie podrzędne może zwrócić wiele wierszy, „gdzie RowID =” wybiera pojedynczy poprawny wiersz z wynikowego wyboru podrzędnego i wykonuje aktualizację do kolumny. Daj mi znać, jeśli potrzebujesz więcej wyjaśnień lub musisz znaleźć odmianę tego tematu.
KeithTheBiped