假设我有以下语句,内部联接产生 3 行,其中 a.Id = b.Id,但 3 行中的每一行都有不同的 b.Value。 由于只更新 tableA 中的一行,因此更新中使用 3 个值中的哪一个?
UPDATE a
SET a.Value = b.Value
FROM tableA AS a
INNER JOIN tableB as b
ON a.Id = b.Id
我认为这种情况没有规则,你不能依赖特定的结果。
如果您要查找特定行,例如最新的一行,您可以使用
apply
,例如:
UPDATE a
SET a.Value = b.Value
FROM tableA AS a
CROSS APPLY
(
select top 1 *
from tableB as b
where b.id = a.id
order by
DateColumn desc
) as b
通常,在这种情况下,您最终得到的结果是按表上物理索引的顺序出现的第一行。在实际实践中,您应该将其视为不确定性,并包含一些将结果缩小到一行的内容。
这是我使用 SQL Server 2008 得出的结论
--drop table #b
--drop table #a
select 1 as id, 2 as value
into #a
select 1 as id, 5 as value
into #b
insert into #b
select 1, 3
insert into #b
select 1, 6
select * from #a
select * from #b
UPDATE #a
SET #a.Value = #b.Value
FROM #a
INNER JOIN #b
ON #a.Id = #b.Id
它似乎每次都使用基本选择的顶部值(select * from #b 的第 1 行)。因此,这可能取决于索引。然而,我不会依赖 SQL 的实现集,因为它有可能改变。相反,我建议使用 Andomar 提供的解决方案来确保您知道要选择什么值。
简而言之,不要相信默认实现,而是创建自己的实现。但是,这是一个有趣的学术问题:)
就我而言,更新多条记录的最佳选择是使用合并查询(从 SQL Server 2008 支持),在此查询中您可以完全控制要更新的内容。 您也可以使用输出查询进行进一步处理。
示例:不带输出子句(仅更新)
;WITH cteB AS
( SELECT Id, Col1, Col2, Col3
FROM B WHERE Id > 10 ---- Select Multiple records
)
MERGE A
USING cteB
ON(A.Id = cteB.Id) -- Update condition
WHEN MATCHED THEN UPDATE
SET
A.Col1 = cteB.Col1, --Note: Update condition i.e; A.Id = cteB.Id cant appear here again.
A.Col2 = cteB.Col2,
A.Col3 = cteB.Col3;
示例:使用 OputPut 子句
CREATE TABLE #TempOutPutTable
{
PkId INT NOT NULL,
Col1 VARCHAR(50),
Col2 VARCHAR(50)
}
;WITH cteB AS
( SELECT Id, Col1, Col2, Col3
FROM B WHERE Id > 10
)
MERGE A
USING cteB
ON(A.Id = cteB.Id)
WHEN MATCHED THEN UPDATE
SET
A.Col1 = cteB.Col1,
A.Col2 = cteB.Col2,
A.Col3 = cteB.Col3
OUTPUT
INSERTED.Id, cteB.Col1, A.Col2 INTO #TempOutPutTable;
--Do what ever you want with the data in temporary table
SELECT * FROM #TempOutPutTable; -- you can check here which records are updated.
是的,我想出了一个与 Justin Pihony 类似的实验:
IF OBJECT_ID('tempdb..#test') IS NOT NULL DROP TABLE #test ;
SELECT
1 AS Name, 0 AS value
INTO #test
IF OBJECT_ID('tempdb..#compare') IS NOT NULL DROP TABLE #compare ;
SELECT 1 AS name, 1 AS value
INTO #compare
INSERT INTO #compare
SELECT 1 AS name, 0 AS value;
SELECT * FROM #test
SELECT * FROM #compare
UPDATE t
SET t.value = c.value
FROM #test t
INNER JOIN #compare c
ON t.Name = c.name
占据右侧比较表中的最上面一行。您可以将 #compare.value 值反转为 0 和 1,您将得到相反的结果。 我同意上面的海报...很奇怪的是,这个操作没有抛出错误消息,因为它完全隐藏这个操作忽略辅助值
合并到表1 A 使用表2 U ON(较低(修剪(A.src_OwnerAlias))=较低(修剪(U.ALIAS))) 当匹配时 更新集 A.scout_OwnerId = U.ID WHERE lower(trim(A.src_OwnerAlias)) = lower(trim(U.ALIAS)) AND U.SCT_COUNTRY__C ='DE' AND U.Org_name = 'EMEA2QA' ;