Aktualizacja SQL z jednej tabeli do drugiej na podstawie dopasowania identyfikatora

929

Mam bazę danych z account numbersi card numbers. Dopasowuję je do pliku do updatedowolnych numerów kart do numeru konta, dzięki czemu pracuję tylko z numerami kont.

Utworzyłem widok łączący tabelę z bazą danych kont / kart, aby zwrócić Table IDi powiązany numer konta, a teraz muszę zaktualizować te rekordy, w których identyfikator jest zgodny z numerem konta.

To jest Sales_Importtabela, w której account numberpole wymaga aktualizacji:

LeadID  AccountNumber
147         5807811235
150         5807811326
185         7006100100007267039

A to jest RetrieveAccountNumbertabela, z której muszę zaktualizować:

LeadID  AccountNumber
147         7006100100007266957
150         7006100100007267039

Próbowałem poniżej, ale jak dotąd nie miałem szczęścia:

UPDATE [Sales_Lead].[dbo].[Sales_Import] 
SET    [AccountNumber] = (SELECT RetrieveAccountNumber.AccountNumber 
                          FROM   RetrieveAccountNumber 
                          WHERE  [Sales_Lead].[dbo].[Sales_Import]. LeadID = 
                                                RetrieveAccountNumber.LeadID) 

Aktualizuje numery kart do numerów kont, ale numery kont zostają zastąpione przez NULL

DineshDB
źródło

Odpowiedzi:

1368

Wierzę UPDATE FROMz JOINpomocy będą:

MS SQL

UPDATE
    Sales_Import
SET
    Sales_Import.AccountNumber = RAN.AccountNumber
FROM
    Sales_Import SI
INNER JOIN
    RetrieveAccountNumber RAN
ON 
    SI.LeadID = RAN.LeadID;

MySQL i MariaDB

UPDATE
    Sales_Import SI,
    RetrieveAccountNumber RAN
SET
    SI.AccountNumber = RAN.AccountNumber
WHERE
    SI.LeadID = RAN.LeadID;
Mark S. Rasmussen
źródło
18
Możesz użyć aliasu tabeli w klauzuli UPDATE, w przeciwnym razie spowoduje to problemy, jeśli sam dołączysz do tabeli w dowolnym momencie.
Tom H
15
W klauzuli set powinieneś zmienić SI.AccountNumberna po prostu AccountNumberinaczej, to się nie powiedzie.
AaronLS
1
MS-Access używa innej aktualizacji z instrukcją JOIN. Spójrz na: sql-und-xml.de/sql-tutorial/…
Christian Ammer
92
wydaje się to być w porządku dla mssql, ale wydaje się, że nie działa w mysql. Wydaje się to jednak wykonać zadanie: UPDATE Sales_Import, RetrieveAccountNumber SET Sales_Import.AccountNumber = RetrieveAccountNumber.AccountNumber where Sales_Import.LeadID = RetrieveAccountNumber.LeadID;. Nieco tematyczny, ale może być pomocny
Edd
7
Myślę, że nie ma potrzeby łączenia wewnętrznego. Roztwór Vonki poniżej pracach: Update [Sales_Lead] [dbo] [Sales_Import] SET [ACCOUNTNUMBER] = RetrieveAccountNumber.AccountNumber Z RetrieveAccountNumber gdzie [Sales_Lead] [dbo] [Sales_Import] .LeadID = RetrieveAccountNumber.LeadID....
Gutti
289

Prosty sposób kopiowania zawartości z jednej tabeli do drugiej jest następujący:

UPDATE table2 
SET table2.col1 = table1.col1, 
table2.col2 = table1.col2,
...
FROM table1, table2 
WHERE table1.memberid = table2.memberid

Możesz także dodać warunek, aby skopiować określone dane.

Shivkant
źródło
2
To działa, ale nie potrzebujesz table2 w FROM UPDATE table2 SET table2.col1 = table1.col1, table2.col2 = table1.col2, ... FROM table1 WHERE table1.memberid = table2.memberid
Sirentec
2
To nie działało, ale AKTUALIZACJA table2, table1 SET table2.col1 = table1.col1, ... GDZIE table1.memberid = table2.memberid (mysql i phpmyadmin)
Tom Kuschel
156

W przypadku SQL Server 2008 + używanie MERGEraczej niż zastrzeżona UPDATE ... FROMskładnia ma pewien urok.

Oprócz tego, że jest to standardowy SQL, a zatem bardziej przenośny, spowoduje także błąd w przypadku wielu połączonych wierszy po stronie źródłowej (a tym samym wielu możliwych różnych wartości do zastosowania w aktualizacji), a nie końcowy wynik będzie nieokreślony .

MERGE INTO Sales_Import
   USING RetrieveAccountNumber
      ON Sales_Import.LeadID = RetrieveAccountNumber.LeadID
WHEN MATCHED THEN
   UPDATE 
      SET AccountNumber = RetrieveAccountNumber.AccountNumber;

Niestety wybór, którego użyć, może nie sprowadzać się wyłącznie do preferowanego stylu. Implementacja MERGEw SQL Server została dotknięta różnymi błędami. Aaron Bertrand opracował tutaj listę zgłoszonych .

Martin Smith
źródło
11
Heads up for MERGE.
Jakub Januszkiewicz
2
Nigdy nie wiedziałem o składni scalania. Jest o wiele czystszy niż Update + Join.
Tony Ashworth,
+1 za raportowanie implementacji MERGE SQL Server
AFract
1
Argumenty przemawiające za użyciem MERGE (w tym w poście z linku powyżej sqlblog.com ) mogą być przekonujące, ale jedną rzeczą do rozważenia może być to, że według MSDN : ... Instrukcja MERGE działa najlepiej, gdy dwie tabele zawierają złożoną mieszaninę dopasowanie cech ... Po prostu aktualizując jedną tabelę na podstawie wierszy innej tabeli, można uzyskać lepszą wydajność i skalowalność dzięki podstawowym instrukcjom INSERT, UPDATE i DELETE
Tony Pulokas,
1
@ jkp1187 To pytanie jest oznaczone jako SQL Server. Więc RE: FWIW - w przybliżeniu zero.
Martin Smith
104

Ogólna odpowiedź dla przyszłych programistów.

SQL Server

UPDATE 
     t1
SET 
     t1.column = t2.column
FROM 
     Table1 t1 
     INNER JOIN Table2 t2 
     ON t1.id = t2.id;

Oracle (i SQL Server)

UPDATE 
     t1
SET 
     t1.colmun = t2.column 
FROM 
     Table1 t1, 
     Table2 t2 
WHERE 
     t1.ID = t2.ID;

MySQL

UPDATE 
     Table1 t1, 
     Table2 t2
SET 
     t1.column = t2.column 
WHERE
     t1.ID = t2.ID;
Tigerjz32
źródło
2
Co najmniej w przypadku programu SQL Server, użyj aliasu zamiast nazwy tabeli w górnej klauzuli aktualizacji ( update t1...zamiast update Table1...)
Gordon
2
Wersja Oracle nie działa. Pierwsze ORA-00933
ka3ak
35

W przypadku PostgreSQL:

UPDATE Sales_Import SI
SET AccountNumber = RAN.AccountNumber
FROM RetrieveAccountNumber RAN
WHERE RAN.LeadID = SI.LeadID; 
Peter
źródło
34

Wygląda na to, że używasz MSSQL, a jeśli dobrze pamiętam, robi się to tak:

UPDATE [Sales_Lead].[dbo].[Sales_Import] SET [AccountNumber] = 
RetrieveAccountNumber.AccountNumber 
FROM RetrieveAccountNumber 
WHERE [Sales_Lead].[dbo].[Sales_Import].LeadID = RetrieveAccountNumber.LeadID
Vinko Vrsalovic
źródło
33

Miałem ten sam problem z foo.newustawieniem nulldla wierszy, w fooktórych nie było pasującego klucza bar. Zrobiłem coś takiego w Oracle:

aktualizacja foo
set foo.new = (wybierz bar.new
                  z baru 
                  gdzie foo.key = bar.key)
gdzie istnieje (wybierz 1
              z baru
              gdzie foo.key = bar.key)
Kjell Andreassen
źródło
4
Dlaczego wymagana jest GDZIE ISTNIEJE ?
Georg Schölly,
6
Ponieważ każdy wiersz w foo niepasujący do paska kończy się na null, ponieważ instrukcja select produkuje null. Mam nadzieję, że to było jaśniejsze niż moja pierwsza próba wyjaśnienia.
Kjell Andreassen
sprawdź tę odpowiedź poniżej stackoverflow.com/questions/224732/…
Basheer AL-MOMANI
@KjellAndreassen Rozwiązałeś mój problem. Dziękuję za Twój kod.
Bhavin Thummar
27

W przypadku MySql, który działa dobrze:

UPDATE
    Sales_Import SI,RetrieveAccountNumber RAN
SET
    SI.AccountNumber = RAN.AccountNumber
WHERE
    SI.LeadID = RAN.LeadID
marsanvi
źródło
26

Oto, co działało dla mnie w SQL Server:

UPDATE [AspNetUsers] SET

[AspNetUsers].[OrganizationId] = [UserProfile].[OrganizationId],
[AspNetUsers].[Name] = [UserProfile].[Name]

FROM [AspNetUsers], [UserProfile]
WHERE [AspNetUsers].[Id] = [UserProfile].[Id];
Abhimanyu
źródło
18

Dziękuję za odpowiedzi. Znalazłem rozwiązanie.

UPDATE Sales_Import 
SET    AccountNumber = (SELECT RetrieveAccountNumber.AccountNumber 
                          FROM   RetrieveAccountNumber 
                          WHERE  Sales_Import.leadid =RetrieveAccountNumber.LeadID) 
WHERE Sales_Import.leadid = (SELECT  RetrieveAccountNumber.LeadID 
                             FROM   RetrieveAccountNumber 
                             WHERE  Sales_Import.leadid = RetrieveAccountNumber.LeadID)  
Martin Smith
źródło
17
Niezależnie od tego, czy kod tutaj działa, prawdopodobnie powinieneś sprawdzić pozostałe dwa opublikowane rozwiązania. Są znacznie wyraźniejsze i znacznie mniej podatne na błędy, a także prawie na pewno szybsze.
Tom H
3
Tylko uwaga na temat tego rozwiązania, UPDATE ... FROM jest zastrzeżona, dlatego jeśli nie możesz użyć instrukcji MERGE, ponieważ używasz SQL 2005 lub wcześniejszej wersji, jest to zgodna z ANSI metoda wykonywania aktualizacji ze źródłem tabeli w MSSQL. Źródło: sqlblog.com/blogs/hugo_kornelis/archive/2008/03/10/…
pseudocoder
1
jedyne rozwiązanie, które działa dla mnie, ponieważ jest to standardowa instrukcja aktualizacji SQL (UPDATE SET WHERE), dziękuję bardzo
Basheer AL-MOMANI
13

W przypadku, gdy tabele znajdują się w różnych bazach danych. (MSSQL)

update database1..Ciudad
set CiudadDistrito=c2.CiudadDistrito

FROM database1..Ciudad c1
 inner join 
  database2..Ciudad c2 on c2.CiudadID=c1.CiudadID
Maurico Bello
źródło
10

Użyj następującego bloku zapytania, aby zaktualizować tabelę 1 z tabelą 2 na podstawie identyfikatora:

UPDATE Sales_Import, RetrieveAccountNumber 
SET Sales_Import.AccountNumber = RetrieveAccountNumber.AccountNumber 
where Sales_Import.LeadID = RetrieveAccountNumber.LeadID;

To najprostszy sposób na rozwiązanie tego problemu.

Gil Baggio
źródło
8

MS Sql

UPDATE  c4 SET Price=cp.Price*p.FactorRate FROM TableNamea_A c4
inner join TableNamea_B p on c4.Calcid=p.calcid 
inner join TableNamea_A cp on c4.Calcid=cp.calcid 
WHERE c4..Name='MyName';

Oracle 11g

        MERGE INTO  TableNamea_A u 
        using
        (
                SELECT c4.TableName_A_ID,(cp.Price*p.FactorRate) as CalcTot 
                FROM TableNamea_A c4
                inner join TableNamea_B p on c4.Calcid=p.calcid 
                inner join TableNamea_A cp on c4.Calcid=cp.calcid 
                WHERE p.Name='MyName' 
        )  rt
        on (u.TableNamea_A_ID=rt.TableNamea_B_ID)
        WHEN MATCHED THEN
        Update set Price=CalcTot  ;
Salman Samadi
źródło
3

aktualizacja w tej samej tabeli:

  DECLARE @TB1 TABLE
    (
        No Int
        ,Name NVarchar(50)
        ,linkNo int
    )

    DECLARE @TB2 TABLE
    (
        No Int
        ,Name NVarchar(50)
        ,linkNo int
    )

    INSERT INTO @TB1 VALUES(1,'changed person data',  0);
    INSERT INTO @TB1 VALUES(2,'old linked data of person', 1);

INSERT INTO @TB2 SELECT * FROM @TB1 WHERE linkNo = 0


SELECT * FROM @TB1
SELECT * FROM @TB2


    UPDATE @TB1 
        SET Name = T2.Name
    FROM        @TB1 T1
    INNER JOIN  @TB2 T2 ON T2.No = T1.linkNo

    SELECT * FROM @TB1
NCP
źródło
3

Poniższy SQL sugerowany przez kogoś NIE działa w SQL Server. Ta składnia przypomina mi klasę ze starej szkoły:

UPDATE table2 
SET table2.col1 = table1.col1, 
table2.col2 = table1.col2,
...
FROM table1, table2 
WHERE table1.memberid = table2.memberid

Wszystkie inne zapytania używające NOT INlub NOT EXISTSniezalecane. Pojawiają się wartości NULL, ponieważ OP porównuje cały zestaw danych z mniejszym podzbiorem, wtedy oczywiście wystąpi problem z dopasowaniem. Należy to naprawić, pisząc odpowiedni SQL z poprawnym JOINzamiast unikając problemu przy użyciu NOT IN. Możesz napotkać inne problemy, używając NOT INlub NOT EXISTSw tym przypadku.

Głosuję na najwyższy, który jest konwencjonalnym sposobem aktualizacji tabeli opartej na innej tabeli, dołączając do programu SQL Server. Jak powiedziałem, nie możesz używać dwóch tabel w tej samej UPDATEinstrukcji w SQL Server, chyba że dołączysz do nich w pierwszej kolejności.

Dr Inner Join
źródło
2
Mogę tylko powiedzieć, że w SQL Server 2017 działa to doskonale. Tak jak uwaga dla przyszłych ludzi. Nie musisz do nich dołączać.
SharpShade,
3

działa z postgresql

UPDATE application
SET omts_received_date = (
    SELECT
        date_created
    FROM
        application_history
    WHERE
        application.id = application_history.application_id
    AND application_history.application_status_id = 8
);
jakentus
źródło
1

Myślałem, że to prosty przykład, że ktoś może to ułatwić,

        DECLARE @TB1 TABLE
        (
            No Int
            ,Name NVarchar(50)
        )

        DECLARE @TB2 TABLE
        (
            No Int
            ,Name NVarchar(50)
        )

        INSERT INTO @TB1 VALUES(1,'asdf');
        INSERT INTO @TB1 VALUES(2,'awerq');


        INSERT INTO @TB2 VALUES(1,';oiup');
        INSERT INTO @TB2 VALUES(2,'lkjhj');

        SELECT * FROM @TB1

        UPDATE @TB1 SET Name =S.Name
        FROM @TB1 T
        INNER JOIN @TB2 S
                ON S.No = T.No

        SELECT * FROM @TB1
użytkownik824910
źródło
0

Oracle 11g

merge into Sales_Import
using RetrieveAccountNumber
on (Sales_Import.LeadId = RetrieveAccountNumber.LeadId)
when matched then update set Sales_Import.AccountNumber = RetrieveAccountNumber.AccountNumber;
Bruno
źródło
-1

Umożliwi to aktualizację tabeli na podstawie wartości kolumny, której nie znaleziono w innej tabeli.

    UPDATE table1 SET table1.column = 'some_new_val' WHERE table1.id IN (
            SELECT * 
            FROM (
                    SELECT table1.id
                    FROM  table1 
                    LEFT JOIN table2 ON ( table2.column = table1.column ) 
                    WHERE table1.column = 'some_expected_val'
                    AND table12.column IS NULL
            ) AS Xalias
    )

Spowoduje to zaktualizowanie tabeli na podstawie wartości kolumny znalezionej w obu tabelach.

    UPDATE table1 SET table1.column = 'some_new_val' WHERE table1.id IN (
            SELECT * 
            FROM (
                    SELECT table1.id
                    FROM  table1 
                    JOIN table2 ON ( table2.column = table1.column ) 
                    WHERE table1.column = 'some_expected_val'
            ) AS Xalias
    )
CG_DEV
źródło
-1

Spróbuj tego :

UPDATE
    Table_A
SET
    Table_A.AccountNumber = Table_B.AccountNumber ,
FROM
    dbo.Sales_Import AS Table_A
    INNER JOIN dbo.RetrieveAccountNumber AS Table_B
        ON Table_A.LeadID = Table_B.LeadID 
WHERE
    Table_A.LeadID = Table_B.LeadID
Oriel.F
źródło
-2

Chciałbym dodać jeszcze jedną rzecz.

Nie aktualizuj wartości o tej samej wartości, generuje to dodatkowe rejestrowanie i niepotrzebne koszty ogólne. Zobacz przykład poniżej - przeprowadzi aktualizację tylko na 2 rekordach, pomimo łączenia na 3.

DROP TABLE #TMP1
DROP TABLE #TMP2
CREATE TABLE #TMP1(LeadID Int,AccountNumber NVarchar(50))
CREATE TABLE #TMP2(LeadID Int,AccountNumber NVarchar(50))

INSERT INTO #TMP1 VALUES
(147,'5807811235')
,(150,'5807811326')
,(185,'7006100100007267039');

INSERT INTO #TMP2 VALUES
(147,'7006100100007266957')
,(150,'7006100100007267039')
,(185,'7006100100007267039');

UPDATE A
SET A.AccountNumber = B.AccountNumber
FROM
    #TMP1 A 
        INNER JOIN #TMP2 B
        ON
        A.LeadID = B.LeadID
WHERE
    A.AccountNumber <> B.AccountNumber  --DON'T OVERWRITE A VALUE WITH THE SAME VALUE

SELECT * FROM #TMP1
spokojnie
źródło
-3

Jeśli powyższe odpowiedzi nie działają, spróbuj tego

Update Sales_Import A left join RetrieveAccountNumber B on A.LeadID = B.LeadID
Set A.AccountNumber = B.AccountNumber
where A.LeadID = B.LeadID 
Shaw
źródło