Como posso fazer uma instrução UPDATE com JOIN no SQL Server?

1314

Preciso atualizar esta tabela no SQL Server com dados da tabela 'pai', veja abaixo:

Tabela: venda

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

Tabela: ud

id  (int)
assid  (int)

sale.assidcontém o valor correto para atualizar ud.assid.

Que consulta fará isso? Estou pensando em um, joinmas não tenho certeza se é possível.

Ant Swift
fonte
3
Qual RDBMS você está usando? MySQL, SQL Server, Oracle, PostgreSQL ou algo mais?
Chris J
algumas relações entre as tabelas? Como alguém pode saber qual registro da venda corresponde a qual registro do ud? É baseado no ID como chave primária nas duas tabelas?
Cătălin Pitis
Como você pode atualizar o UD? Ele só tem o assid e seu próprio ID. Você poderia dar um exemplo em termos de valores reais existentes e os registros que você gostaria que fossem alterados ou adicionados como resultado do script?
Bernhard Hofmann
2
Alias ​​de usuário em consultas como stackoverflow.com/questions/982919/sql-update-query-using-joins
Imran Muhammad

Respostas:

2383

A sintaxe depende estritamente do SQL DBMS que você está usando. Aqui estão algumas maneiras de fazer isso em ANSI / ISO (também conhecido como DBMS), MySQL, SQL Server e Oracle. Esteja ciente de que meu método ANSI / ISO sugerido normalmente será muito mais lento que os outros dois métodos, mas se você estiver usando um DBMS SQL diferente do MySQL, SQL Server ou Oracle, esse poderá ser o único caminho a seguir (por exemplo, se o seu DBMS do SQL não suportar 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

Servidor SQL:

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;

Observe que a tabela de destino não deve ser repetida na FROMcláusula do Postgres.

Oráculo:

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
fonte
3
Parece-me que o MySQL set assid = s.assiddeveria ser set u.assid = s.assid.
dotancohen
2
Na sintaxe ANSI, o que acontece se o SELECT após o =retorno mais de uma linha?
Jogue fora a conta
2
@ ThrowawayAccount3Million Provavelmente falharia. AFAIK, esse tipo de operação espera um valor escalar e gera um erro se receber um conjunto de resultados.
Francis Lord
6
Desejo que o OP escolha alguns nomes melhores para sua tabela e colunas !! não é tão legível / intuitiva ...
S.Serpooshan
4
Postgre 9.3 trabalhou apenas usandoupdate ud set assid = s.assid
StackUnder
143

Isso deve funcionar no SQL Server:

update ud 
set assid = sale.assid
from sale
where sale.udid = id
edosoft
fonte
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 
user1154043
fonte
20
A resposta seria mais útil se usasse os nomes de tabela / coluna usados ​​na pergunta. Por que existem 3 tabelas em sua resposta?
alfonx
50

Uma abordagem SQL padrão seria

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

No SQL Server, você pode usar uma associação

UPDATE ud
SET assid = s.assid
FROM ud u
JOIN sale s ON u.id=s.id
MattH
fonte
1
Com o primeiro, você não pode corresponder em mais de 2 colunas, mas a junção funciona muito bem.
makciook
6
@makciook: hein? Você pode adicionar mais condições na WHEREcláusula se desejar corresponder em colunas adicionais.
Siride
2
Apenas um detalhe ... mas acho que o OP significava sale.udid = ud.id. E não sale.id.
precisa saber é o seguinte
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
fonte
26

Consulta de atualização simplificada usando JOIN - em várias tabelas.

   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

Nota - first_table, second_table, third_table e some_column como 123456 são nomes de tabelas de demonstração, nomes de colunas e IDs. Substitua-os pelos nomes válidos.

Vinit Kadkol
fonte
16

Outro exemplo de por que o SQL não é realmente portátil.

Para o MySQL seria:

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

Para obter mais informações, leia a atualização de várias tabelas: 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
fonte
2
+1 no comentário "por que o SQL não é realmente portátil"! A portabilidade é tão frágil que apenas declarar uma variável interromperá a portabilidade entre muitos dos mecanismos populares de banco de dados.
precisa saber é o seguinte
8

O Teradata Aster oferece outra maneira interessante de como atingir o objetivo:

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

Eu estava pensando que o SQL Server na primeira publicação funcionaria para o Sybase, pois ambos são T-SQL, mas infelizmente não.

Para a Sybase, achei que a atualização precisa estar na própria tabela e não no alias:

update ud
set u.assid = s.assid
from ud u
    inner join sale s on
        u.id = s.udid
Ken Goh
fonte
7

A instrução a seguir com a palavra-chave FROM é usada para atualizar várias linhas com uma junção

UPDATE users 
set users.DivisionId=divisions.DivisionId
from divisions join users on divisions.Name=users.Division
Sheryar Nizar
fonte
7

MySQL

Você obterá o melhor desempenho se esquecer a cláusula where e colocar todas as condições na expressão ON.

Eu acho que isso ocorre porque a consulta primeiro tem que se juntar às tabelas e depois executa a cláusula where, portanto, se você pode reduzir o que é necessário para se juntar, essa é a maneira mais rápida de obter os resultados / fazer a atualização.

Exemplo

Cenário

Você tem uma tabela de usuários. Eles podem fazer login usando seu nome de usuário ou email ou número de conta. Essas contas podem estar ativas (1) ou inativas (0). Esta tabela possui 50000 linhas

Você tem uma tabela de usuários para desativar de uma só vez, porque descobre que todos fizeram algo ruim. Esta tabela, no entanto, possui uma coluna com nomes de usuário, e-mails e números de contas misturados. Ele também possui um indicador "has_run" que precisa ser definido como 1 (verdadeiro) quando executado

Inquerir

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;

Raciocínio

Se tivéssemos que ingressar apenas nas condições OR, essencialmente seria necessário verificar cada linha quatro vezes para ver se deveria ingressar e, potencialmente, retornar muito mais linhas. No entanto, ao oferecer mais condições, ele pode "pular" muitas linhas se elas não atenderem a todas as condições ao ingressar.

Bônus

É mais legível. Todas as condições estão em um só lugar e as linhas a serem atualizadas estão em um só lugar

Luke Watts
fonte
4

E no MS ACCESS:

UPDATE ud 
INNER JOIN sale ON ud.id = sale.udid
SET ud.assid = sale.assid;
Richard
fonte
1
Como cuidado, o SET deve vir imediatamente após a definição do conjunto de registros! Eu apenas estava tentando elaborar um cenário semelhante em um banco de dados do Access, que precisava de uma cláusula WHERE (não aceitaria como uma condição ON válida). ONDE teve que vir por último para evitar erros de sintaxe.
Dodecaphone
4

A maneira mais simples é usar a Common Table Expression (CTE) introduzida no 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
fonte
3
UPDATE tblAppraisalBasicData
SET tblAppraisalBasicData.ISCbo=1
FROM tblAppraisalBasicData SI INNER JOIN  aaa_test RAN ON SI.EmpID = RAN.ID
Abdullah Yousuf
fonte
3

Experimente este, acho que isso funcionará para você

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

Para SQLite, use a propriedade RowID para fazer a atualização:

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
fonte
1
Você poderia explicar isso um pouco?
Mohammed Noureldin
1
@MohammedNoureldin vou tentar explicar. O problema é como atualizar uma tabela com um resultado de uma consulta em um Join usando a mesma tabela. A instrução (sub-seleção) atua como uma junção e retorna um campo do sistema, RowID, que é um número exclusivo para cada linha em uma tabela. Como a sub-seleção pode retornar várias linhas, o "where RowID =" seleciona uma única linha correta da sub-seleção resultante e faz a atualização para a coluna. Deixe-me saber se você precisa de mais esclarecimentos ou precisa descobrir uma variação sobre esse tema.
KeithTheBiped