此脚本中的结果是正确的,但我似乎不明白为什么列BetaStatus仍为'NOK'
关于'Beta',第一行(Beta = NOK)会将@Summary.BetaStatus
更新为NOK。但后来我认为@testTable
中的最后两行会将BetaStatus从NOK更新回OK。我只是想确定'NOK'实际上是要处理的最后一行并因此是值。这不是巧合。
declare @testTable table
(
id int,
Pgroup varchar(10),
Pstatus varchar(3)
)
insert into @testTable select 3, 'Alpha', 'OK'
insert into @testTable select 3, 'Beta', 'NOK'
insert into @testTable select 3, 'Gamma', 'OK'
insert into @testTable select 3, 'Beta', 'OK'
insert into @testTable select 3, 'Beta', 'OK'
declare @Summary table
(
id int,
AlphaStatus varchar(3),
BetaStatus varchar(3),
GammaStatus varchar(3)
)
insert into @Summary (id) select 3
update @Summary
set
AlphaStatus = ISNULL(rA.Pstatus, AlphaStatus),
BetaStatus = ISNULL(rB.Pstatus, BetaStatus),
GammaStatus = ISNULL(rG.Pstatus, GammaStatus)
from @Summary t
left join @testTable rA on rA.id = t.ID AND rA.Pgroup = 'Alpha'
left join @testTable rB on rB.id = t.ID AND rB.Pgroup = 'Beta'
left join @testTable rG on rG.id = t.ID AND rG.Pgroup = 'Gamma'
select * from @summary
我问的原因是,对于每个id,AlphaStatus,BetaStatus,GammaStatus如果以前是'NOK',则不应该改回'OK'。一旦它更新为'NOK',无论下一步是什么,它都会保持这种状态。
另一种方法是使用'OK'值更新@Summary,然后使用'NOK'进行另一次更新。这样我就知道'NOK'不会被取代。但如果这样可行,那么我宁愿使用它。
作为第二个问题,如果我使用INNER JOIN,为什么UPDATE不能正常工作?
感谢。
答案 0 :(得分:6)
让我们看看返回select
而不是update
select
AlphaStatus = ISNULL(rA.Pstatus, AlphaStatus),
BetaStatus = ISNULL(rB.Pstatus, BetaStatus),
GammaStatus = ISNULL(rG.Pstatus, GammaStatus)
from @Summary t
left join @testTable rA on rA.id = t.ID AND rA.Pgroup = 'Alpha'
left join @testTable rB on rB.id = t.ID AND rB.Pgroup = 'Beta'
left join @testTable rG on rG.id = t.ID AND rG.Pgroup = 'Gamma'
结果:
AlphaStatus BetaStatus GammaStatus
OK NOK OK
OK OK OK
OK OK OK
现在您尝试UPDATE
update @Summary
set
AlphaStatus = ISNULL(rA.Pstatus, AlphaStatus),
BetaStatus = ISNULL(rB.Pstatus, BetaStatus),
GammaStatus = ISNULL(rG.Pstatus, GammaStatus)
from @Summary t
left join @testTable rA on rA.id = t.ID AND rA.Pgroup = 'Alpha'
left join @testTable rB on rB.id = t.ID AND rB.Pgroup = 'Beta'
left join @testTable rG on rG.id = t.ID AND rG.Pgroup = 'Gamma'
更新后的表@Summary包含:
id AlphaStatus BetaStatus GammaStatus
3 OK NOK OK
我想你想得到:
id AlphaStatus BetaStatus GammaStatus
3 OK OK OK
但UPDATE
不起作用,当它们是多个匹配时,结果可能不一致,部分基于表排序或实际执行计划。
另请参阅:Let's deprecate UPDATE FROM!
<强>正确性?巴,谁在乎?
嗯,大多数人都这么做。这就是我们测试的原因。
如果我在SELECT查询中弄乱了连接条件,那么行太多了 从第二场比赛开始,我会在考试时看到它,因为我 获得更多的行然后预期。如果我弄乱了子查询标准 在ANSI标准UPDATE查询中,我以类似的方式查看它 越早,因为如果子查询SQL Server将返回错误 返回多个值。但使用专有的UPDATE FROM 语法,我可以弄乱连接,从不注意 - SQL Server会 如果匹配更多,请一遍又一遍地更新同一行 连接表中的一行,只有最后一行的结果 那些更新坚持。而且无法知道哪一行 将来,因为这取决于发生的查询执行计划 被选中。最坏的情况是执行的情况 计划恰好在所有测试期间产生预期结果 在单处理器开发服务器上 - 然后,在之后 部署到四路双核生产服务器,我们的宝贵 数据突然袭击了粉丝...
看到这种不一致而不是表变量使用表并创建聚簇索引:
<强> SqlFiddleDemo 强>
CREATE TABLE testTable(id int,
Pgroup varchar(10),
Pstatus varchar(3));
CREATE CLUSTERED INDEX clx_name
ON testTable(PStatus DESC);
/* or */
CREATE CLUSTERED INDEX clx_name
ON testTable(PStatus ASC);
例如,如果您使用MERGE:
;WITH cte as
(SELECT
ra.id
,AlphaStatus = rA.Pstatus
,BetaStatus = rB.Pstatus
,GammaStatus = rG.Pstatus
from @Summary t
left join @testTable rA on rA.id = t.ID AND rA.Pgroup = 'Alpha'
left join @testTable rB on rB.id = t.ID AND rB.Pgroup = 'Beta'
left join @testTable rG on rG.id = t.ID AND rG.Pgroup = 'Gamma'
)
MERGE @Summary AS TGT
USING (SELECT * FROM cte ) AS SRC
ON TGT.id = SRC.id
WHEN MATCHED THEN
UPDATE
SET
AlphaStatus = ISNULL(src.AlphaStatus, tgt.AlphaStatus),
BetaStatus = ISNULL(src.BetaStatus, tgt.BetaStatus),
GammaStatus = ISNULL(src.GammaStatus, tgt.GammaStatus);
您将收到明确的错误消息,指出这是不允许的:
MERGE语句尝试多次更新或删除同一行。当目标行与多个源行匹配时会发生这种情况。 MERGE语句不能多次更新/删除目标表的同一行。优化ON子句以确保目标行最多匹配一个源行,或使用GROUP BY子句对源行进行分组。