这个模糊的UPDATE语句为什么/如何工作?

Mar*_*las 3 sql database theory sql-server-2005

假设您在表上运行UPDATE语句,但是您在此基表中放入的信息来自其他一些辅助表.通常,您将加入数据并且不期望UPDATE语句的FROM子句中的行相乘,从而保持一个新行映射到基表中的一个旧行.

但是我想知道如果你的JOIN表在某种程度上是模棱两可的会发生什么,就像你无法将每个基本实体映射到一个连接的实体一样.或者,如果你做了一些荒谬的事情,比如将基表连接到其子表,并使用该信息更新基表.它会如何选择?现在每个基表行有多行.

我在SQL Server 2005中运行了这样的语句,它似乎是在每个集合中选择第一行.但这对我来说似乎不对.不应该发错吗?为什么这是理想的行为?

示例代码

-- normal
-- categories are one-to-many bundles

update bundles_denormalized set category = c.description

from bundles_denormalized b
left join categories c
on b.category_id = c.id

-- ambiguous
-- bundles are one-to-many products

update bundles_denormalized set category = p.description

from bundles_denormalized b
left join products p
on b.id = p.bundle_id
Run Code Online (Sandbox Code Playgroud)

HLG*_*GEM 5

实际上,如果我正确地理解了这个问题,它会多次更新该字段,那只是因为只有一条记录,所以最终只有一个值.为什么不出错?因为语法是正确的,并且数据库无法知道您的意图是什么.你想这样做吗?通常情况下,这就是为什么您应该在运行之前选择更新以确保更正记录获得正确的值.

我通常用这种方式写一个更新加入:

update b    
set category = p.description
--select b.category, p.description
from bundles_denormalized b
left join products p on b.id = p.bundle_id
Run Code Online (Sandbox Code Playgroud)

我也会警惕在更新中使用左连接,因为您可能会将值更改为空值.如果这是你想要的,那就没关系,但如果不是,那就没关系.


kri*_*tof 5

从 BOL 更新

将 UPDATE 与 FROM 子句一起使用

如果 UPDATE 语句包含的 FROM 子句未指定为每个更新的列出现只有一个值,即 UPDATE 语句不是确定性的,则该语句的结果是未定义的。例如,在下面脚本的UPDATE语句中,Table1中的两行都满足UPDATE语句中FROM子句的条件;但未定义 Table1 中的哪一行用于更新 Table2 中的行。

USE AdventureWorks;
GO
IF OBJECT_ID ('dbo.Table1', 'U') IS NOT NULL
    DROP TABLE dbo.Table1;
GO
IF OBJECT_ID ('dbo.Table2', 'U') IS NOT NULL
    DROP TABLE dbo.Table2;
GO
CREATE TABLE dbo.Table1 
    (ColA int NOT NULL, ColB decimal(10,3) NOT NULL);
GO
CREATE TABLE dbo.Table2 
    (ColA int PRIMARY KEY NOT NULL, ColB decimal(10,3) NOT NULL);
GO
INSERT INTO dbo.Table1 VALUES(1, 10.0);
INSERT INTO dbo.Table1 VALUES(1, 20.0);
INSERT INTO dbo.Table2 VALUES(1, 0.0);
GO
UPDATE dbo.Table2 
SET dbo.Table2.ColB = dbo.Table2.ColB + dbo.Table1.ColB
FROM dbo.Table2 
    INNER JOIN dbo.Table1 
    ON (dbo.Table2.ColA = dbo.Table1.ColA);
GO
SELECT ColA, ColB 
FROM dbo.Table2;
Run Code Online (Sandbox Code Playgroud)

换句话说,它是一种有效的语法,不会抛出错误或异常。

但同时您不能确定更新值将是您的 FROM 子句中的第一个或最后一个记录,因为它没有定义。