Atualizar tabela usando valores de outra tabela no SQL Server

13

Eu tenho 2 tabela no meu banco de dados.

Tabela 1

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

Mesa 2

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

na tabela nº 1, o endereço das colunas e phone2 está vazio e os valores de sexo e data de nascimento das colunas são os mesmos da tabela nº 2.

Como posso ler dados da tabela 2 e atualizar o endereço e telefone2 na tabela 1 com valores das colunas de endereço e telefone da tabela 2 quando sexo e data de nascimento são iguais em cada linha?

por exemplo: esses são alguns dados da Tabela 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|
-------------------------------------------------------------------------

e aqui estão alguns dados na tabela # 2

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

Quero atualizar a tabela 1 com os dados da tabela 2, verificar o sexo e a data de nascimento e criar a tabela 1 como

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

Como posso fazer isso?

John Doe
fonte
11
E se houver 2 ou mais pessoas com o mesmo sexo e data de nascimento? Qual telefone e endereço (dentre muitos) devem ser copiados?
ypercubeᵀᴹ
não é possível, é apenas uma tabela de teste; nos meus dados reais não é possível que a mesma pessoa tenha os mesmos valores.
John Doe
Se isso realmente não for possível, ou seja, se houver uma UNIQUErestrição table2 (gender, birthdate), você deve adicionar essa informação na pergunta.
ypercubeᵀᴹ

Respostas:

26

Existem algumas maneiras de alcançar os resultados desejados.

Métodos indeterministas

(no caso de muitas linhas na tabela 2 corresponderem a uma na tabela 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 uma forma um pouco mais concisa

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

Ou com um 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étodos determinísticos

MERGE lançaria um erro em vez de aceitar resultados não determinísticos

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 você pode escolher um registro específico se houver mais de uma correspondência

Com 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 um 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
fonte
Obrigado pela sua grande ajuda! Eu tenho 2 perguntas: 1) Eu acho que é uma maneira simples de fazer isso, acho que dessa forma diminui o desempenho e se eu tiver cerca de 50milhões de registros dessa maneira, é muito lento, você concorda? 2) dessa forma, se eu quiser ingressar na 2table e algumas colunas da tabela 2 não existirem na tabela 1, obtive algum erro? por exemplo, se eu tiver uma coluna de cores na tabela 2 e não existir na tabela 1, o processo de junção obteve erro ou apenas as colunas de junção existem em 2tables? Obrigado mais uma vez ...
John Doe
11
@JohnDoe se você tiver uma pergunta sobre desempenho, faça uma nova pergunta e forneça detalhes sobre o tamanho da tabela, estruturas, índices e planos de execução. Não entendo o que você está perguntando no ponto 2, edite sua pergunta e forneça estruturas de tabela de exemplo que demonstrem o problema que você está perguntando.
Martin Smith
11
@ JohnDoe: se você quer dizer com coluna, quer dizer um valor de coluna (em outras palavras, uma linha correspondente ) - quando não há linha correspondente, nenhum erro é gerado. No caso de uma junção interna (como aqui), as linhas não correspondentes simplesmente não serão atualizadas. Mas se você realmente quis dizer uma coluna que existe em uma tabela e não existe na outra, acredito que nova pergunta a ser feita separadamente.
Andriy M
Nesse primeiro CTE, como o SQL Server sabe qual tabela atualizar?
RonJohn
@RonJohn Ele conhece a fonte das colunas. ou seja, que ambos tgt_addresse tgt_phonesão aliases para colunas em #Table1- de modo que é o destino da atualização.
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
fonte
Os nomes dos campos na resposta não correspondem aos nomes dos campos na pergunta, mas a técnica funciona.
RonJohn
Graças Ron, apenas dando a ideia
David Fawzy
Ele é , no entanto, por que a sua resposta foi rejeitada.
31419 RonJohn
Graças não tem certeza, código como eu copiei estava trabalhando na minha candidatura ao vivo
David Fawzy