Consulta de actualización SQL utilizando combinaciones

664

Tengo que actualizar un campo con un valor que devuelve una combinación de 3 tablas.

Ejemplo:

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

Quiero actualizar los mf_item_numbervalores de campo de la tabla item_mastercon algún otro valor que se une en la condición anterior.

¿Cómo puedo hacer esto en MS SQL Server?

Shyju
fuente
124
Para empezar, deja de usar esas combinaciones implícitas. Es una técnica pobre que conduce a resultados incorrectos debido a uniones cruzadas inesperadas. Este estilo de código tiene 18 años de
antigüedad
2
Véase también la pregunta SO ... stackoverflow.com/questions/1293330/…
SteveC

Respuestas:

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 que quede claro ... La UPDATEcláusula puede hacer referencia a un alias de tabla especificado en la FROMcláusula. Entonces imen este caso es válido

Ejemplo genérico

UPDATE A
SET foo = B.bar
FROM TableA A
JOIN TableB B
    ON A.col1 = B.colx
WHERE ...
gbn
fuente
99
Postgres se queja UPDATE im; im es un alias que Postgres no reconoce: /
fatuhoku
10
FYI esto NO funcionará en MySQL (sintaxis diferente)! Para MySQL, eche un vistazo a la respuesta de
gcbenison
67

Una de las formas más fáciles es usar una expresión de tabla común (ya que está en 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>

El motor de ejecución de consultas descubrirá por sí mismo cómo actualizar el registro.

Remus Rusanu
fuente
8
Excelente, el uso del CTE simplifica la conversión del SELECT original en una ACTUALIZACIÓN
SteveC
44
Funciona siempre que su consulta SELECT no tenga agregados, DISTINCT, etc.
Baodad
1
Por lo general, comienzo con punto y coma para terminar la declaración anterior (si la hay) CTE rocas! Fácil de diseñar consultas complicadas / actualizaciones unidas. Lo uso todo el tiempo ...
Adam W
64

Adaptando esto a MySQL: no hay una FROMcláusula UPDATE, pero esto 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
fuente
12

No usó su sql anterior, pero aquí hay un ejemplo de actualización de una tabla basada en una declaración de unión.

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

Puede especificar tablas adicionales utilizadas para determinar cómo y qué actualizar con la cláusula "FROM" en la instrucción UPDATE, como esta:

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

En la cláusula WHERE, debe proporcionar las condiciones y unir operaciones para unir estas tablas.

Bagazo

marc_s
fuente
55
..o use ANSI JOINS en la cláusula FROM
gbn
55
Sí, utilice las uniones ansi, podría tener problemas reales en una actualización si accidentalmente obtiene una unión cruzada.
HLGEM
7

MySQL: en general, realice los cambios necesarios según sus requisitos:

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

Intenta así ...

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

Puede usar la siguiente 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
fuente
1

Puede actualizar con MERGECommand con mucho más control sobre MATCHEDy NOT MATCHED: (Cambié ligeramente el código fuente para demostrar mi punto)

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
fuente