使用联接的SQL更新查询


664

我必须更新一个值,该值由3个表的联接返回。

例:

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

我想用其他在上述条件下加入的mf_item_number值更新表的字段值item_master

如何在MS SQL Server中执行此操作?


124
首先,请停止使用那些隐含的联接。这是一项糟糕的技术,由于意外的交叉连接而导致错误的结果。此代码风格为18岁过时
HLGEM

2
还看到如此问题... stackoverflow.com/questions/1293330/...
SteveC

Answers:


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

为了清楚起见...该UPDATE子句可以引用该子句中指定的表别名FROM。所以im在这种情况下是有效的

通用示例

UPDATE A
SET foo = B.bar
FROM TableA A
JOIN TableB B
    ON A.col1 = B.colx
WHERE ...

9
Postgres抱怨UPDATE im; im是Postgres无法识别的别名:/
fatuhoku

10
仅供参考,这将不是在MySQL(不同的语法)工作!对于MySQL,请查看gcbenison的答案
1

67

最简单的方法之一是使用公用表表达式(因为您已经在使用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>

查询执行引擎将自行找出如何更新记录。


8
太好

4
只要您的SELECT查询没有任何聚合,DISTINCT等
它就可以工作。– Baodad 2015年

1
我通常以分号开头来终止上一条语句(如果有的话)。CTE摇滚!设计简单,复杂的查询/合并更新。我一直都用它...
亚当W

64

使它适应MySQL-在中没有FROM子句UPDATE,但这有效:

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

12

上面没有使用您的sql,但这是基于join语句更新表的示例。

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

8

您可以指定其他表,这些表用于确定如何以及通过UPDATE语句中的“ FROM”子句进行更新的内容,如下所示:

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

在WHERE子句中,您需要提供条件和联接操作以将这些表绑定在一起。


5
..或在FROM子句中使用ANSI JOINS
gbn

5
是的,请使用ansi联接,如果不小心出现交叉联接,可能会在更新中遇到真正的麻烦。
HLGEM,2009年



2

您可以使用以下查询:

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`

1

您可以使用MERGECommand进行更新,从而对MATCHED和进行更多控制NOT MATCHED(我稍微更改了源代码以说明我的观点)

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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.