Consulta de atualização SQL usando junções

664

Eu tenho que atualizar um campo com um valor que é retornado por uma junção de 3 tabelas.

Exemplo:

select
    im.itemid
    ,im.sku as iSku
    ,gm.SKU as GSKU
    ,mm.ManufacturerId as ManuId
    ,mm.ManufacturerName
    ,im.mf_item_number
    ,mm.ManufacturerID
from 
    item_master im, group_master gm, Manufacturer_Master mm 
where
    im.mf_item_number like 'STA%'
    and im.sku=gm.sku
    and gm.ManufacturerID = mm.ManufacturerID
    and gm.manufacturerID=34

Eu quero atualizar os mf_item_numbervalores do campo da tabela item_mastercom algum outro valor que esteja associado à condição acima.

Como posso fazer isso no MS SQL Server?

Shyju
fonte
124
Pare de usar essas junções implícitas para começar. É uma técnica ruim que leva a resultados incorretos devido a junções cruzadas inesperadas. Esse estilo de código está desatualizado em 18 anos
HLGEM 03/02
2
Veja também SO pergunta ... stackoverflow.com/questions/1293330/...
SteveC

Respostas:

1251
UPDATE im
SET mf_item_number = gm.SKU --etc
FROM item_master im
JOIN group_master gm
    ON im.sku = gm.sku 
JOIN Manufacturer_Master mm
    ON gm.ManufacturerID = mm.ManufacturerID
WHERE im.mf_item_number like 'STA%' AND
      gm.manufacturerID = 34

Para deixar claro ... A UPDATEcláusula pode se referir a um alias de tabela especificado na FROMcláusula. Portanto im, neste caso, é válido

Exemplo genérico

UPDATE A
SET foo = B.bar
FROM TableA A
JOIN TableB B
    ON A.col1 = B.colx
WHERE ...
gbn
fonte
9
O Postgres reclama UPDATE im; im é um apelido que Postgres não reconhece: /
fatuhoku
10
Para sua informação, isso NÃO funcionará no MySQL (sintaxe diferente)! Para o MySQL, dê uma olhada na resposta de
gcbenison
67

Uma das maneiras mais fáceis é usar uma expressão de tabela comum (já que você já está no SQL 2005):

with cte as (
select
    im.itemid
    ,im.sku as iSku
    ,gm.SKU as GSKU
    ,mm.ManufacturerId as ManuId
    ,mm.ManufacturerName
    ,im.mf_item_number
    ,mm.ManufacturerID
    , <your other field>
from 
    item_master im, group_master gm, Manufacturer_Master mm 
where
    im.mf_item_number like 'STA%'
    and im.sku=gm.sku
    and gm.ManufacturerID = mm.ManufacturerID
    and gm.manufacturerID=34)
update cte set mf_item_number = <your other field>

O mecanismo de execução da consulta descobrirá por si próprio como atualizar o registro.

Remus Rusanu
fonte
8
Excelente, o uso do CTE facilita a conversão do SELECT original em uma atualização
SteveC 14/13/13
4
Funciona, desde que sua consulta SELECT não tem nenhum agregados, distinto, etc.
Baodad
1
Normalmente começo com ponto e vírgula para finalizar a declaração anterior (se houver). Rochas CTE! Simples de projetar consultas complicadas / atualizações associadas. Eu uso isso o tempo todo ...
Adam W
64

Adaptando isso ao MySQL - não há FROMcláusula UPDATE, mas funciona:

UPDATE
    item_master im
    JOIN
    group_master gm ON im.sku=gm.sku 
    JOIN
    Manufacturer_Master mm ON gm.ManufacturerID=mm.ManufacturerID
SET
    im.mf_item_number = gm.SKU --etc
WHERE
    im.mf_item_number like 'STA%'
    AND
    gm.manufacturerID=34
gcbenison
fonte
12

Não usou seu sql acima, mas aqui está um exemplo de atualização de uma tabela com base em uma instrução de junção.

UPDATE p
SET    p.category = c.category
FROM   products p
       INNER JOIN prodductcatagories pg
            ON  p.productid = pg.productid
       INNER JOIN categories c
            ON  pg.categoryid = c.cateogryid
WHERE  c.categories LIKE 'whole%'
Gratzy
fonte
8

Você pode especificar tabelas adicionais usadas para determinar como e o que atualizar com a cláusula "FROM" na instrução UPDATE, desta forma:

update item_master
set mf_item_number = (some value)
from 
   group_master as gm
   join Manufacturar_Master as mm ON ........
where
 .... (your conditions here)

Na cláusula WHERE, você precisa fornecer as condições e unir operações para ligar essas tabelas.

Marc

marc_s
fonte
5
..ou use ANSI JOINS na cláusula FROM
gbn em 11/06/2009
5
Sim, por favor, use as ansi joins, você pode estar com problemas em uma atualização se acidentalmente tiver uma junção cruzada.
11119 HLGEM
7

MySQL: Em geral, faça as alterações necessárias de acordo com seus requisitos:

UPDATE
    shopping_cart sc
    LEFT JOIN
    package pc ON sc. package_id = pc.id    
SET
    sc. amount = pc.amount
Vinod Joshi
fonte
3

Tente assim ...

Update t1.Column1 = value 
from tbltemp as t1 
inner join tblUser as t2 on t2.ID = t1.UserID 
where t1.[column1]=value and t2.[Column1] = value;
Ankitkumar Tandel
fonte
2

Você pode usar a seguinte consulta:

UPDATE im
SET mf_item_number = (some value) 
FROM item_master im
JOIN group_master gm
    ON im.sku = gm.sku 
JOIN Manufacturer_Master mm
    ON gm.ManufacturerID = mm.ManufacturerID
WHERE im.mf_item_number like 'STA%' AND
      gm.manufacturerID = 34    `sql`
Prasan Karunarathna
fonte
1

Você pode atualizar com o MERGECommand com muito mais controle sobre MATCHEDe NOT MATCHED: (alterei levemente o código-fonte para demonstrar meu argumento)

USE tempdb;
GO
IF(OBJECT_ID('target') > 0)DROP TABLE dbo.target
IF(OBJECT_ID('source') > 0)DROP TABLE dbo.source
CREATE TABLE dbo.Target
    (
      EmployeeID INT ,
      EmployeeName VARCHAR(100) ,
      CONSTRAINT Target_PK PRIMARY KEY ( EmployeeID )
    );
CREATE TABLE dbo.Source
    (
      EmployeeID INT ,
      EmployeeName VARCHAR(100) ,
      CONSTRAINT Source_PK PRIMARY KEY ( EmployeeID )
    );
GO
INSERT  dbo.Target
        ( EmployeeID, EmployeeName )
VALUES  ( 100, 'Mary' );
INSERT  dbo.Target
        ( EmployeeID, EmployeeName )
VALUES  ( 101, 'Sara' );
INSERT  dbo.Target
        ( EmployeeID, EmployeeName )
VALUES  ( 102, 'Stefano' );

GO
INSERT  dbo.Source
        ( EmployeeID, EmployeeName )
VALUES  ( 100, 'Bob' );
INSERT  dbo.Source
        ( EmployeeID, EmployeeName )
VALUES  ( 104, 'Steve' );
GO

SELECT * FROM dbo.Source
SELECT * FROM dbo.Target

MERGE Target AS T
USING Source AS S
ON ( T.EmployeeID = S.EmployeeID )
WHEN MATCHED THEN
    UPDATE SET T.EmployeeName = S.EmployeeName + '[Updated]';
GO 
SELECT '-------After Merge----------'
SELECT * FROM dbo.Source
SELECT * FROM dbo.Target
Yashar Aliabbasi
fonte