Como faço para atualizar de um SELECT no SQL Server?

No SQL Server , é possível insert em uma tabela usando uma SELECT :

 INSERT INTO Table (col1, col2, col3) SELECT col1, col2, col3 FROM other_table WHERE sql = 'cool' 

Também é possível atualizar através de um SELECT ? Eu tenho uma tabela temporária contendo os valores e gostaria de atualizar outra tabela usando esses valores. Talvez algo assim:

 UPDATE Table SET col1, col2 SELECT col1, col2 FROM other_table WHERE sql = 'cool' WHERE Table.id = other_table.id 

 UPDATE Table_A SET Table_A.col1 = Table_B.col1, Table_A.col2 = Table_B.col2 FROM Some_Table AS Table_A INNER JOIN Other_Table AS Table_B ON Table_A.id = Table_B.id WHERE Table_A.col3 = 'cool' 

No SQL Server 2008 (ou melhor), use MERGE

 MERGE INTO YourTable T USING other_table S ON T.id = S.id AND S.tsql = 'cool' WHEN MATCHED THEN UPDATE SET col1 = S.col1, col2 = S.col2; 

Alternativamente:

 MERGE INTO YourTable T USING ( SELECT id, col1, col2 FROM other_table WHERE tsql = 'cool' ) S ON T.id = S.id WHEN MATCHED THEN UPDATE SET col1 = S.col1, col2 = S.col2; 
 UPDATE table SET Col1 = i.Col1, Col2 = i.Col2 FROM ( SELECT ID, Col1, Col2 FROM other_table) i WHERE i.ID = table.ID 

Eu alteraria a excelente resposta de Robin para o seguinte:

 UPDATE Table SET Table.col1 = other_table.col1, Table.col2 = other_table.col2 FROM Table INNER JOIN other_table ON Table.id = other_table.id WHERE Table.col1 != other_table.col1 OR Table.col2 != other_table.col2 OR ( other_table.col1 IS NOT NULL AND Table.col1 IS NULL ) OR ( other_table.col2 IS NOT NULL AND Table.col2 IS NULL ) 

Sem uma cláusula WHERE, você afetará as linhas pares que não precisam ser afetadas, o que poderia (possivelmente) causar o recálculo do índice ou acionadores de incêndio que realmente não deveriam ter sido triggersdos.

Mão única

 UPDATE t SET t.col1 = o.col1, t.col2 = o.col2 FROM other_table o JOIN t ON t.id = o.id WHERE o.sql = 'cool' 

Outra possibilidade não mencionada ainda é apenas lançar a própria instrução SELECT em um CTE e, em seguida, atualizar o CTE.

 ;WITH CTE AS (SELECT T1.Col1, T2.Col1 AS _Col1, T1.Col2, T2.Col2 AS _Col2 FROM T1 JOIN T2 ON T1.id = T2.id /*Where clause added to exclude rows that are the same in both tables Handles NULL values correctly*/ WHERE EXISTS(SELECT T1.Col1, T1.Col2 EXCEPT SELECT T2.Col1, T2.Col2)) UPDATE CTE SET Col1 = _Col1, Col2 = _Col2 

Isso tem a vantagem de ser fácil executar a SELECT primeiro para verificar os resultados, mas exige que você aliasse as colunas como acima se elas forem nomeadas da mesma forma nas tabelas de origem e de destino.

Isso também tem a mesma limitação que a syntax proprietária UPDATE ... FROM mostrada em quatro das outras respostas. Se a tabela de origem estiver no lado de muitos de uma junit um-para-muitos, é indeterminável qual dos registros combinados possíveis combinados será usado na Update (um problema que MERGE evita levantando um erro se houver uma tentativa de atualizar a mesma linha mais de uma vez).

Para o registro (e outros procurando como eu era), você pode fazê-lo no MySQL assim:

 UPDATE first_table, second_table SET first_table.color = second_table.color WHERE first_table.id = second_table.foreign_id 

Usando alias:

 UPDATE t SET t.col1 = o.col1 FROM table1 AS t INNER JOIN table2 AS o ON t.id = o.id 

A maneira simples de fazer isso é:

 UPDATE table_to_update, table_info SET table_to_update.col1 = table_info.col1, table_to_update.col2 = table_info.col2 WHERE table_to_update.ID = table_info.ID 

Isso pode ser um motivo de nicho para executar uma atualização (por exemplo, usado principalmente em um procedimento) ou pode ser óbvio para outros, mas também deve ser declarado que você pode executar uma instrução update-select sem usar join (no caso de as tabelas que você está atualizando não têm um campo comum).

 update Table set Table.example = a.value from TableExample a where Table.field = *key value* -- finds the row in Table AND a.field = *key value* -- finds the row in TableExample a 

Aqui está outra syntax útil:

 UPDATE suppliers SET supplier_name = (SELECT customers.name FROM customers WHERE customers.customer_id = suppliers.supplier_id) WHERE EXISTS (SELECT customers.name FROM customers WHERE customers.customer_id = suppliers.supplier_id); 

Ele verifica se é nulo ou não usando “WHERE EXIST”.

Eu adiciono isso apenas para que você possa ver uma maneira rápida de escrevê-lo para que você possa verificar o que será atualizado antes de fazer a atualização.

 UPDATE Table SET Table.col1 = other_table.col1, Table.col2 = other_table.col2 --select Table.col1, other_table.col,Table.col2,other_table.col2, * FROM Table INNER JOIN other_table ON Table.id = other_table.id 

Se você usa o MySQL em vez do SQL Server, a syntax é:

 UPDATE Table1 INNER JOIN Table2 ON Table1.id = Table2.id SET Table1.col1 = Table2.col1, Table1.col2 = Table2.col2 

UPDATE de SELECT com INNER JOIN no database SQL

Como há muitas respostas desta postagem, que são mais bem votadas, eu sugeri minha sugestão aqui também. Embora a questão seja muito interessante, tenho visto em muitos sites do fórum e feito uma solução usando o INNER JOIN com capturas de canvas.

No início, criei uma tabela com o nome schooldown e insira alguns registros com relação aos nomes das colunas e execute-os.

Então eu executei o comando SELECT para visualizar os registros inseridos.

insira a descrição da imagem aqui

Então eu criei uma nova tabela chamada schoolnew e da mesma forma executada acima das ações nela.

insira a descrição da imagem aqui

Então, para ver os registros inseridos nele, eu executo o comando SELECT.

insira a descrição da imagem aqui

Agora, aqui eu quero fazer algumas alterações na terceira e quarta linha, para completar esta ação, eu executo o comando UPDATE com o INNER JOIN .

insira a descrição da imagem aqui

Para visualizar as alterações, executo o comando SELECT .

insira a descrição da imagem aqui

Você pode ver como os registros Third e Fourth da tabela schoolold são facilmente substituídos pela table school new usando INNER JOIN com a instrução UPDATE.

E se você quiser entrar na mesa consigo mesmo (o que não acontece com muita frequência):

 update t1 -- just reference table alias here set t1.somevalue = t2.somevalue from table1 t1 -- these rows will be the targets inner join table1 t2 -- these rows will be used as source on .................. -- the join clause is whatever suits you 

O exemplo a seguir usa uma tabela derivada, uma instrução SELECT após a cláusula FROM, para retornar os valores antigo e novo para atualizações adicionais:

 UPDATE x SET x.col1 = x.newCol1, x.col2 = x.newCol2 FROM (SELECT t.col1, t2.col1 AS newCol1, t.col2, t2.col2 AS newCol2 FROM [table] t JOIN other_table t2 ON t.ID = t2.ID) x 

A atualização através do CTE é mais legível do que as outras respostas aqui:

 ;WITH cte AS (SELECT col1,col2,id FROM other_table WHERE sql = 'cool') UPDATE A SET A.col1 = B.col1, A.col2 = B.col2 FROM table A INNER JOIN cte B ON A.id = B.id 

Se você estiver usando o SQL Server, poderá atualizar uma tabela de outra sem especificar uma junit e simplesmente vincular as duas a partir da cláusula where . Isso faz uma consulta SQL muito mais simples:

 UPDATE Table1 SET Table1.col1 = Table2.col1, Table1.col2 = Table2.col2 FROM Table2 WHERE Table1.id = Table2.id 

A outra maneira é usar uma tabela derivada:

 UPDATE t SET t.col1 = a.col1 ,t.col2 = a.col2 FROM ( SELECT id, col1, col2 FROM @tbl2) a INNER JOIN @tbl1 t ON t.id = a.id 

Dados de amostra

 DECLARE @tbl1 TABLE (id INT, col1 VARCHAR(10), col2 VARCHAR(10)) DECLARE @tbl2 TABLE (id INT, col1 VARCHAR(10), col2 VARCHAR(10)) INSERT @tbl1 SELECT 1, 'a', 'b' UNION SELECT 2, 'b', 'c' INSERT @tbl2 SELECT 1, '1', '2' UNION SELECT 2, '3', '4' UPDATE t SET t.col1 = a.col1 ,t.col2 = a.col2 FROM ( SELECT id, col1, col2 FROM @tbl2) a INNER JOIN @tbl1 t ON t.id = a.id SELECT * FROM @tbl1 SELECT * FROM @tbl2 
 UPDATE TQ SET TQ.IsProcessed = 1, TQ.TextName = 'bla bla bla' FROM TableQueue TQ INNER JOIN TableComment TC ON TC.ID = TQ.TCID WHERE TQ.IsProcessed = 0 

Para certificar-se de que você está atualizando o que deseja, selecione primeiro

 SELECT TQ.IsProcessed, 1 AS NewValue1, TQ.TextName, 'bla bla bla' AS NewValue2 FROM TableQueue TQ INNER JOIN TableComment TC ON TC.ID = TQ.TCID WHERE TQ.IsProcessed = 0 

Usar:

 drop table uno drop table dos create table uno ( uid int, col1 char(1), col2 char(2) ) create table dos ( did int, col1 char(1), col2 char(2), [sql] char(4) ) insert into uno(uid) values (1) insert into uno(uid) values (2) insert into dos values (1,'a','b',null) insert into dos values (2,'c','d','cool') select * from uno select * from dos 

OU:

 update uno set col1 = (select col1 from dos where uid = did and [sql]='cool'), col2 = (select col2 from dos where uid = did and [sql]='cool') 

OU:

 update uno set col1=d.col1,col2=d.col2 from uno inner join dos d on uid=did where [sql]='cool' select * from uno select * from dos 

Se o nome da coluna ID for o mesmo em ambas as tabelas, basta colocar o nome da tabela antes da tabela para ser atualizada e usar um alias para a tabela selecionada, por exemplo:

 update uno set col1 = (select col1 from dos d where uno.[id] = d.[id] and [sql]='cool'), col2 = (select col2 from dos d where uno.[id] = d.[id] and [sql]='cool') 

A solução abaixo funciona para um database MySQL:

 UPDATE table1 a , table2 b SET a.columname = 'some value' WHERE b.columnname IS NULL ; 

Existe até um método mais curto, e pode ser surpreendente para muitos de vocês:

 -- Sample data: --------------------------------------------------------------------------- CREATE TABLE #SOURCE ([ID] INT, [Desc] VARCHAR(10)); CREATE TABLE #DESTINATION ([ID] INT, [Desc] VARCHAR(10)) INSERT INTO #SOURCE VALUES(1,'Desc_1'), (2, 'Desc_2'), (3, 'Desc_3'); INSERT INTO #DESTINATION VALUES(1,'Desc_4'), (2, 'Desc_5'), (3, 'Desc_6'); --------------------------------------------------------------------------- UPDATE #DESTINATION SET #DESTINATION.[Desc] = #SOURCE.[Desc] FROM #SOURCE WHERE #DESTINATION.[ID] = #SOURCE.[ID] AND #Source.[Desc] = 'Desc_2' 

Na resposta aceita, após o:

 SET Table_A.col1 = Table_B.col1, Table_A.col2 = Table_B.col2 

Eu adicionaria:

 OUTPUT deleted.*, inserted.* 

O que eu costumo fazer é colocar tudo em uma transação de roll-backed e usar o "OUTPUT" : desta forma eu vejo tudo o que está prestes a acontecer. Quando estou feliz com o que vejo, mudo o ROLLBACK para COMMIT .

Eu geralmente preciso documentar o que eu fiz, então eu uso a opção "results to Text" quando executo a consulta roll-backed e eu salvo tanto o script quanto o resultado do OUTPUT. (Claro que isso não é prático se eu mudei muitas linhas)

A outra maneira de atualizar a partir de uma instrução select:

 UPDATE A SET A.col = A.col,B.col1 = B.col1 FROM first_Table AS A INNER JOIN second_Table AS B ON A.id = B.id WHERE A.col2 = 'cool' 
 UPDATE table AS a INNER JOIN table2 AS b ON a.col1 = b.col1 INNER JOIN ... AS ... ON ... = ... SET ... WHERE ... 

Consolidando todas as diferentes abordagens aqui.

  1. Selecione atualização
  2. Atualizar com uma expressão de tabela comum
  3. Mesclar

Estrutura da tabela de amostra:

produtos

 CREATE TABLE [dbo].[Product]( [Id] [int] IDENTITY(1, 1) NOT NULL, [Name] [nvarchar](100) NOT NULL, [Description] [nvarchar](100) NULL ) ON [PRIMARY] 

Product_BAK

  CREATE TABLE [dbo].[Product_BAK]( [Id] [int] IDENTITY(1, 1) NOT NULL, [Name] [nvarchar](100) NOT NULL, [Description] [nvarchar](100) NULL ) ON [PRIMARY] 

1. Selecione a atualização

  update P1 set Name = P2.Name from Product P1 inner join Product_Bak P2 on p1.id = P2.id where p1.id = 2 

2. Atualizar com uma expressão de tabela comum

  ; With CTE as ( select id, name from Product_Bak where id = 2 ) update P set Name = P2.name from product P inner join CTE P2 on P.id = P2.id where P2.id = 2 

3. Mesclar

  Merge into product P1 using Product_Bak P2 on P1.id = P2.id when matched then update set p1.[description] = p2.[description], p1.name = P2.Name; 

Na instrução Merge, podemos inserir se não encontrarmos um registro correspondente no destino, mas existir na origem e encontrar a syntax:

  Merge into product P1 using Product_Bak P2 on P1.id = P2.id when matched then update set p1.[description] = p2.[description], p1.name = P2.Name WHEN NOT MATCHED THEN insert (name, description) values(p2.name, P2.description);