Mise à jour SQL d'une table à une autre en fonction d'une correspondance d'ID


929

J'ai une base de données avec account numberset card numbers. Je les associe à un fichier à updaten'importe quel numéro de carte au numéro de compte, de sorte que je ne travaille qu'avec des numéros de compte.

J'ai créé une vue reliant la table à la base de données de compte / carte pour renvoyer le Table IDet le numéro de compte associé, et maintenant je dois mettre à jour les enregistrements où l'ID correspond au numéro de compte.

Voici le Sales_Importtableau, où le account numberchamp doit être mis à jour:

LeadID  AccountNumber
147         5807811235
150         5807811326
185         7006100100007267039

Et voici le RetrieveAccountNumbertableau, où je dois mettre à jour à partir de:

LeadID  AccountNumber
147         7006100100007266957
150         7006100100007267039

J'ai essayé ci-dessous, mais pas de chance jusqu'à présent:

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

Il met à jour les numéros de carte en numéros de compte, mais les numéros de compte sont remplacés par NULL

Réponses:


1369

Je crois qu'un UPDATE FROMavec une JOINvolonté aidera:

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 et MariaDB

UPDATE
    Sales_Import SI,
    RetrieveAccountNumber RAN
SET
    SI.AccountNumber = RAN.AccountNumber
WHERE
    SI.LeadID = RAN.LeadID;

18
Vous souhaiterez peut-être utiliser l'alias de table dans la clause UPDATE, sinon cela causera des problèmes si vous vous joignez vous-même à la table à tout moment.
Tom H

15
Dans la clause set, vous devez passer SI.AccountNumberà AccountNumbersinon il échouera.
AaronLS

1
MS-Access utilise une instruction UPDATE différente avec JOIN. Jetez un œil à: sql-und-xml.de/sql-tutorial/…
Christian Ammer

92
cela semble bien pour mssql mais ne semble pas fonctionner dans mysql. Cela semble faire l'affaire cependant UPDATE Sales_Import, RetrieveAccountNumber SET Sales_Import.AccountNumber = RetrieveAccountNumber.AccountNumber where Sales_Import.LeadID = RetrieveAccountNumber.LeadID;. Légèrement hors sujet mais peut être utile
Edd

7
Je pense qu'il n'y a pas besoin de la jointure intérieure. La solution Vonki ci-dessous fonctionne: UPDATE [Sales_Lead]. [Dbo]. [Sales_Import] SET [AccountNumber] = RetrieveAccountNumber.AccountNumber FROM RetrieveAccountNumber WHERE [Sales_Lead]. [Dbo]. [Sales_Import] .LeadID = RetrieveAccountNumber.LeadID
Gutt

289

La manière simple de copier le contenu d'une table à une autre est la suivante:

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

Vous pouvez également ajouter la condition pour copier les données particulières.


2
Cela fonctionne, mais vous n'avez pas besoin de table2 dans le SET UPDATE table2 SET table2.col1 = table1.col1, table2.col2 = table1.col2, ... FROM table1 WHERE table1.memberid = table2.memberid
Sirentec

2
Cela n'a pas fonctionné, mais UPDATE table2, table1 SET table2.col1 = table1.col1, ... WHERE table1.memberid = table2.memberid (mysql et phpmyadmin)
Tom Kuschel

156

Pour SQL Server 2008 + L'utilisation MERGEplutôt que la UPDATE ... FROMsyntaxe propriétaire a un certain attrait.

En plus d'être un SQL standard et donc plus portable, il soulèvera également une erreur en cas de plusieurs lignes jointes du côté source (et donc plusieurs valeurs différentes possibles à utiliser dans la mise à jour) plutôt que d'avoir le résultat final indéterministe .

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

Malheureusement, le choix de celui à utiliser peut ne pas se résumer uniquement au style préféré. L'implémentation de MERGEdans SQL Server a été affectée par divers bogues. Aaron Bertrand a compilé une liste de ceux rapportés ici .


11
Je me dirige vers MERGE .
Jakub Januszkiewicz

2
Je n'ai jamais connu la syntaxe de fusion. C'est tellement plus propre que Update + Join.
Tony Ashworth

+1 pour le rapport sur l'implémentation de MERGE SQL Server
AFract

1
Les arguments pour utiliser MERGE (y compris ceux dans le post de sqlblog.com lié ci-dessus) peuvent être convaincants, mais une chose à considérer pourrait être que selon MSDN : ... L'instruction MERGE fonctionne mieux lorsque les deux tables ont un mélange complexe de correspondance des caractéristiques ... Lors de la simple mise à jour d'une table en fonction des lignes d'une autre table, des performances et une évolutivité améliorées peuvent être obtenues avec les instructions de base INSERT, UPDATE et DELETE
Tony Pulokas

1
@ jkp1187 Cette question est étiquetée SQL Server. Donc RE: FWIW - environ zéro.
Martin Smith

104

Réponse générique pour les futurs développeurs.

serveur SQL

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

Oracle (et 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;

2
À noter au moins pour SQL Server, utilisez l'alias plutôt que le nom de la table dans la clause de mise à jour supérieure ( update t1...plutôt que update Table1...)
gordon

2
La version Oracle ne fonctionne pas. Obtenir ORA-00933
ka3ak

35

Pour PostgreSQL:

UPDATE Sales_Import SI
SET AccountNumber = RAN.AccountNumber
FROM RetrieveAccountNumber RAN
WHERE RAN.LeadID = SI.LeadID; 

34

Semble que vous utilisez MSSQL, alors, si je me souviens bien, cela se fait comme ceci:

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

33

J'ai eu le même problème avec la foo.newdéfinition de nulllignes fooqui n'avaient pas de clé correspondante bar. J'ai fait quelque chose comme ça dans Oracle:

mettre à jour foo
set foo.new = (sélectionnez bar.new
                  du bar 
                  où foo.key = bar.key)
où existe (sélectionnez 1
              du bar
              où foo.key = bar.key)

4
Pourquoi le WHERE EXISTS est-il requis?
Georg Schölly

6
Parce que chaque ligne de foo n'ayant pas de correspondance dans la barre a fini par être nulle, car l'instruction select a produit null. J'espère que c'était plus clair que ma première tentative de l'expliquer.
Kjell Andreassen

vérifiez cette réponse ci-dessous stackoverflow.com/questions/224732/…
Basheer AL-MOMANI

@KjellAndreassen Vous avez résolu mon problème. Merci pour votre code.
Bhavin Thummar

27

Pour MySql qui fonctionne bien:

UPDATE
    Sales_Import SI,RetrieveAccountNumber RAN
SET
    SI.AccountNumber = RAN.AccountNumber
WHERE
    SI.LeadID = RAN.LeadID

26

Voici ce qui a fonctionné pour moi dans SQL Server:

UPDATE [AspNetUsers] SET

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

FROM [AspNetUsers], [UserProfile]
WHERE [AspNetUsers].[Id] = [UserProfile].[Id];

18

Merci pour les réponses. J'ai trouvé une solution.

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)  

17
Que le code fonctionne ici ou non, vous devriez probablement regarder les deux autres solutions publiées. Ils sont beaucoup plus clairs et beaucoup moins sujets aux erreurs et presque certainement plus rapides.
Tom H

3
Juste une note sur cette solution, UPDATE ... FROM est propriétaire donc, si vous ne pouvez pas utiliser l'instruction MERGE parce que vous utilisez SQL 2005 ou une version antérieure, il s'agit d'une méthode compatible ANSI pour effectuer des mises à jour avec une source de table dans MSSQL. Source: sqlblog.com/blogs/hugo_kornelis/archive/2008/03/10/…
pseudocoder

1
la seule solution qui fonctionne pour moi car c'est une instruction de mise à jour SQL standard (UPDATE SET WHERE), merci beaucoup
Basheer AL-MOMANI

13

Dans le cas où les tables se trouvent dans des bases de données différentes. (MSSQL)

update database1..Ciudad
set CiudadDistrito=c2.CiudadDistrito

FROM database1..Ciudad c1
 inner join 
  database2..Ciudad c2 on c2.CiudadID=c1.CiudadID

10

Utilisez le bloc de requête suivant pour mettre à jour Table1 avec Table2 en fonction de l'ID:

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

C'est le moyen le plus simple de résoudre ce problème.


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  ;

3

mise à jour dans le même tableau:

  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

3

Le SQL ci-dessous suggéré par quelqu'un, ne fonctionne PAS dans SQL Server. Cette syntaxe me rappelle ma classe de vieille école:

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

Toutes les autres requêtes utilisant NOT INou NOT EXISTSne sont pas recommandées. Les valeurs NULL apparaissent car OP compare l'ensemble de données complet avec un sous-ensemble plus petit, alors bien sûr il y aura un problème de correspondance. Cela doit être corrigé en écrivant le bon SQL avec correct JOINau lieu d'esquiver le problème en utilisant NOT IN. Vous pourriez rencontrer d'autres problèmes en utilisant NOT INouNOT EXISTS dans ce cas.

Mon vote pour celui du haut, qui est une manière conventionnelle de mettre à jour une table basée sur une autre table en se joignant à SQL Server. Comme je l'ai dit, vous ne pouvez pas utiliser deux tables dans la même UPDATEinstruction dans SQL Server, sauf si vous les joignez d'abord.


2
Je peux seulement dire que dans SQL Server 2017, cela fonctionne parfaitement bien. Juste comme une note pour les futurs passants. Pas besoin de les rejoindre.
SharpShade

3

cela fonctionne avec 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
);

1

Je pensais que c'était un exemple simple si quelqu'un pouvait le faire plus facilement,

        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

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;

-1

Cela vous permettra de mettre à jour une table en fonction de la valeur de colonne introuvable dans une autre table.

    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
    )

Cela mettra à jour une table en fonction de la valeur de colonne trouvée dans les deux tables.

    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
    )

-1

essaye ça :

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

-2

Je voudrais ajouter une chose supplémentaire.

Ne mettez pas à jour une valeur avec la même valeur, cela génère une journalisation supplémentaire et une surcharge inutile. Voir l'exemple ci-dessous - il effectuera uniquement la mise à jour sur 2 enregistrements malgré la liaison sur 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

-3

Si les réponses ci-dessus ne fonctionnent pas pour vous, essayez ceci

Update Sales_Import A left join RetrieveAccountNumber B on A.LeadID = B.LeadID
Set A.AccountNumber = B.AccountNumber
where A.LeadID = B.LeadID 
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.