使用连接的 SQL 更新查询
Posted
技术标签:
【中文标题】使用连接的 SQL 更新查询【英文标题】:SQL update query using joins 【发布时间】:2009-06-11 18:49:33 【问题描述】:我必须使用 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
我想更新表item_master
的mf_item_number
字段值,并使用在上述条件中加入的其他值。
如何在 MS SQL Server 中执行此操作?
【问题讨论】:
请停止使用那些隐含的连接开始。这是一种糟糕的技术,由于意外的交叉连接而导致不正确的结果。这种代码风格已经过时了 18 年 另见 SO 问题 ...***.com/questions/1293330/… 【参考方案1】: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 ...
【讨论】:
仅供参考这将不在 mysql 中工作(不同的语法)!对于 MySQL,请查看 gcbenison 的答案 @Sliq 谢谢。无论如何,这不是 MySQL 问题。【参考方案2】:将此适应 MySQL —— UPDATE
中没有 FROM
子句,但这有效:
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
【讨论】:
【参考方案3】:最简单的方法之一是使用通用表表达式(因为您已经使用 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>
查询执行引擎会自行决定如何更新记录。
【讨论】:
太好了,使用 CTE 可以很容易地将原始 SELECT 转换为 UPDATE 只要您的 SELECT 查询没有任何聚合、DISTINCT 等,就可以工作。 我通常以分号开头来终止之前的语句(如果有的话)。 CTE 摇滚!简单设计复杂的查询/连接更新。我一直在使用它...【参考方案4】:上面没有使用你的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%'
【讨论】:
【参考方案5】:您可以使用 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子句中,需要提供条件和join操作将这些表绑定在一起。
马克
【讨论】:
..或在 FROM 子句中使用 ANSI JOINS 是的,请使用 ansi 连接,如果你不小心得到了交叉连接,你可能会在更新中遇到麻烦。【参考方案6】:MySQL:一般来说,根据您的要求进行必要的更改:
UPDATE
shopping_cart sc
LEFT JOIN
package pc ON sc. package_id = pc.id
SET
sc. amount = pc.amount
【讨论】:
这不是 MySQL 问题【参考方案7】:试试这样...
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;
【讨论】:
这甚至在语法上都不正确,而更早的公认答案不仅在语法上正确,而且解决了所提出的确切问题。【参考方案8】:您可以使用以下查询:
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`
【讨论】:
【参考方案9】:在 SQL 中使用连接查询进行更新非常简单。无需 使用 FROM
子句即可。这是一个例子:
UPDATE customer_table c
JOIN
employee_table e
ON c.city_id = e.city_id
JOIN
anyother_ table a
ON a.someID = e.someID
SET c.active = "Yes"
WHERE c.city = "New york";
【讨论】:
【参考方案10】:如果您使用的是 SQL Server,您可以从另一个表更新一个表,而无需指定连接,只需从 where 子句链接这两个表。这使得 SQL 查询更加简单:
UPDATE Table1
SET Table1.col1 = Table2.col1,
Table1.col2 = Table2.col2
FROM
Table2
WHERE
Table1.id = Table2.id
【讨论】:
【参考方案11】:您可以使用MERGE
命令进行更新,从而更好地控制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
【讨论】:
不是,我很确定,在 SQL Server 2005 中,问题被标记为,但这是现代 SQL Server 版本上最好(即更标准)的方式【参考方案12】:让我在所有现有答案中添加一个警告:
当使用 SELECT ... FROM 语法时,您应该记住它是 T-SQL 的专有语法并且是非确定性的。最糟糕的是,您没有收到任何警告或错误,它只是顺利执行。
完整的例子解释在documentation:
在指定 FROM 子句以提供更新操作的条件时要小心。如果 UPDATE 语句包含未指定的 FROM 子句,则该语句的结果未定义,该子句的指定方式为每个更新的列出现只有一个值可用,也就是说,如果 UPDATE 语句不是确定性的。
【讨论】:
【参考方案13】:我一直在尝试做这样的事情,我突然想到尝试使用以下语法(使用元组)
update dstTable T
set (T.field1, T.field2, T.field3) =
(select S.value1, S.value2, S.value3
from srcTable S
where S.key = T.Key);
令人惊讶的是,它奏效了。我正在使用 Oracle(我认为是 12c)。这是标准 SQL 还是 Oracle 特定的?
注意:在我的示例中,我正在更新整个表格(填充新列)。更新没有 where 子句,因此所有行都将被更新。当子查询不返回行时,您的字段将设置为 NULL。 (并且它不能返回超过一行)。
【讨论】:
以上是关于使用连接的 SQL 更新查询的主要内容,如果未能解决你的问题,请参考以下文章
JPQL 到 SQL 使用 Hibernate 更新查询交叉连接问题