Mettre à jour la table à l'aide des valeurs d'une autre table dans SQL Server

13

J'ai 2 tables dans ma base de données.

Tableau 1

-------------------------------------------------------------------------
| name | family | phone | email | gender | phone2 | address | birthdate |
-------------------------------------------------------------------------

Tableau 2

-----------------------------------------
| gender | address | phone | birthdate |
-----------------------------------------

dans le tableau # 1, l' adresse des colonnes et phone2 est vide et les valeurs de sexe et de date de naissance des colonnes sont les mêmes que dans le tableau # 2.

Comment puis-je lire les données du tableau n ° 2 et mettre à jour l' adresse et le téléphone 2 dans le tableau n ° 1 avec les valeurs des colonnes de l' adresse et du téléphone du tableau n ° 2 lorsque le sexe et la date de naissance sont les mêmes dans chaque ligne?

par exemple: voici quelques données du tableau n ° 1

-------------------------------------------------------------------------
| name | family | phone | email | gender | phone2 | address | birthdate |
-------------------------------------------------------------------------
| john | doe    | 12345| t@t.com| Male  |         |         | 1980-01-01|
-------------------------------------------------------------------------
| mike | clark  | 65432| x@y.com| Male  |         |         | 1990-01-01|
-------------------------------------------------------------------------
| Sara | King   | 875465| a@b.com|Female|         |         | 1970-01-01|
-------------------------------------------------------------------------

et voici quelques données dans le tableau # 2

-----------------------------------------
| gender | address | phone | birthdate  |
-----------------------------------------
| Male   | 1704test|0457852|1980-01-01  |
-----------------------------------------
| Female | 1705abcs|0986532|1970-01-01  |
-----------------------------------------
| Male   | 1602cyzd|0326589|1990-01-01  |
-----------------------------------------

Je veux mettre à jour le tableau # 1 avec les données du tableau # 2 et vérifier le sexe et la date de naissance et rendre le tableau # 1 comme

-------------------------------------------------------------------------
| name | family | phone | email | gender | phone2 | address | birthdate |
-------------------------------------------------------------------------
| john | doe    | 12345| t@t.com| Male   |0457852 |1704test | 1980-01-01|
-------------------------------------------------------------------------
| mike | clark  | 65432| x@y.com| Male   |0326589  |1602cyzd| 1990-01-01|
-------------------------------------------------------------------------
| Sara | King   | 875465| a@b.com|Female |0986532  |1705abcs| 1970-01-01|
-------------------------------------------------------------------------

Comment puis-je faire ceci?

John Doe
la source
1
Et si deux personnes ou plus ont le même sexe et la même date de naissance? Quel téléphone et quelle adresse (parmi les nombreux) doivent être copiés?
ypercubeᵀᴹ
ce n'est pas possible, c'est juste une table de test, dans mes données réelles ce n'est pas possible que la même personne ait les mêmes valeurs.
John Doe
Si ce n'est vraiment pas possible, c'est-à-dire s'il y a une UNIQUEcontrainte table2 (gender, birthdate), vous devez ajouter cette information dans la question.
ypercubeᵀᴹ

Réponses:

26

Il existe plusieurs façons d'obtenir les résultats souhaités.

Méthodes non déterministes

(dans le cas où de nombreuses lignes du tableau 2 correspondent à une dans le tableau 1)

UPDATE T1
SET    address = T2.address,
       phone2 = T2.phone
FROM   #Table1 T1
       JOIN #Table2 T2
         ON T1.gender = T2.gender
            AND T1.birthdate = T2.birthdate

Ou une forme un peu plus concise

UPDATE #Table1
SET    address = #Table2.address,
       phone2 = #Table2.phone
FROM   #Table2
WHERE  #Table2.gender = #Table1.gender
       AND #Table2.birthdate = #Table1.birthdate 

Ou avec un CTE

WITH CTE
     AS (SELECT T1.address AS tgt_address,
                T1.phone2  AS tgt_phone,
                T2.address AS source_address,
                T2.phone   AS source_phone
         FROM   #Table1 T1
                INNER JOIN #Table2 T2
                  ON T1.gender = T2.gender
                     AND T1.birthdate = T2.birthdate)
UPDATE CTE
SET    tgt_address = source_address,
       tgt_phone = source_phone 

Méthodes déterministes

MERGE lancerait une erreur plutôt que d'accepter des résultats non déterministes

MERGE #Table1 T1
USING #Table2 T2
ON T1.gender = T2.gender
   AND T1.birthdate = T2.birthdate
WHEN MATCHED THEN
  UPDATE SET address = T2.address,
             phone2 = T2.phone; 

Ou vous pouvez choisir un enregistrement spécifique s'il y a plus d'une correspondance

Avec APPLY

UPDATE T1
SET    address = T2.address,
       phone2 = T2.phone
FROM   #Table1 T1
       CROSS APPLY (SELECT TOP 1 *
                    FROM   #Table2 T2
                    WHERE  T1.gender = T2.gender
                           AND T1.birthdate = T2.birthdate
                    ORDER  BY T2.PrimaryKey) T2 

.. Ou un CTE

WITH T2
     AS (SELECT *,
                ROW_NUMBER() OVER (PARTITION BY gender, birthdate ORDER BY primarykey) AS RN
         FROM   #Table2)
UPDATE T1
SET    address = T2.address,
       phone2 = T2.phone
FROM   #Table1 T1
       JOIN T2
         ON T1.gender = T2.gender
            AND T1.birthdate = T2.birthdate
            AND T2.RN = 1;
Martin Smith
la source
Merci pour votre grande aide! J'ai 2 questions: 1) Je pense que c'est un moyen simple de le faire, je pense que cette façon est de diminuer les performances et si j'ai un enregistrement d'environ 50 millions, c'est très lent, êtes-vous d'accord? 2) de cette façon, si je veux rejoindre la table 2 et que certaines colonnes du tableau # 2 n'existent pas dans le tableau # 1, j'ai une erreur? par exemple, si j'ai une colonne de couleur dans le tableau # 2 et qu'elle n'existe pas dans le tableau # 1, le processus de jointure a une erreur ou simplement les colonnes de jointure existent dans 2tables? Merci encore ...
John Doe
1
@JohnDoe si vous avez une question sur les performances, posez une nouvelle question et fournissez des détails sur les tailles de table, les structures, les index et les plans d'exécution. Je ne comprends pas ce que vous demandez au point 2, veuillez modifier votre question et fournir des exemples de structures de tableau qui illustrent le problème que vous posez.
Martin Smith
1
@JohnDoe: Si vous entendez par colonne, vous voulez dire une valeur de colonne (en d'autres termes, une ligne correspondante ) - lorsqu'il n'y a pas de ligne correspondante, aucune erreur n'est générée. Dans le cas d'une jointure interne (comme ici), les lignes inégalées ne seront tout simplement pas mises à jour, mais si vous vouliez en effet une colonne qui existe dans une table et n'existe pas dans l'autre, alors je pense que c'est une plus de nouvelle question à poser séparément.
Andriy M
Sur ce premier CTE, comment SQL Server sait-il quelle table mettre à jour?
RonJohn
@RonJohn Il connaît la source des colonnes. c'est-à-dire que les deux tgt_addresset tgt_phonesont des alias pour les colonnes #Table1- c'est donc la cible de la mise à jour.
Martin Smith
0
UPDATE TS
SET TS.TaskFullAddress = L.FullAddress
FROM [dbo].[TaskOrders]   TS
INNER JOIN Locations L
ON  TS.ClientId  = L.ClientId;
David Fawzy
la source
Les noms de champs dans la réponse ne correspondent pas aux noms de champs dans la question, mais la technique fonctionne.
RonJohn
Merci Ron, juste en donnant l'idée
David Fawzy
Il est , cependant, pourquoi votre réponse a été rejetée.
RonJohn
Merci pas sûr, car j'ai copié du code fonctionnait dans mon application en direct
David Fawzy