假設我有以下語句,並且內部連接結果爲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
假設我有以下語句,並且內部連接結果爲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提供的解決方案來確保你知道你將選擇什麼樣的價值。
總之,不要相信默認實現,創建自己的。但是,這是一個有趣的學術問題:)
我很想知道爲什麼我爲那些低估了我的答案的人得到了滿意的結果? :) – 2012-02-29 16:51:26
通常情況下,您在這種情況下最終會出現在表上物理索引的順序。在實際操作中,您應該將其視爲非確定性的,並且包含將結果縮小爲一行的內容。
絕對,這是我現在學到的東西。我只是很想知道我的問題在我修復之前做了什麼。 – sooprise 2012-02-29 16:49:16
在我的情況下,更新多個記錄的最佳選擇是使用合併查詢(支持從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.
爲了完整起見,'UPDATE'也支持'OUTPUT',並且給你「完全控制你正在更新的內容」:主要區別在於這個更新的唯一上下文是* MERGE將會失敗if多行匹配,而不是隨機選擇一個(有效)* – 2014-01-29 13:50:25
我同意簡單的更新語句可以有輸出子句知道更新記錄, 和MERGE查詢將失敗,當我們多次更新單個記錄。 在通常情況下,我們應該嘗試更新一次記錄,因爲更新多次只會保留最後一個值。 – sudhAnsu63 2014-01-30 02:04:22
是的,我想出了一個類似的實驗,以賈斯汀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,您會得到相反的結果。我同意上面的海報......奇怪的是,這個操作沒有拋出錯誤信息,因爲它完全隱藏了這個操作IGNORES二級值
@bluefeet - 總是?我原以爲這種行爲將會依賴於索引優化。也就是說,除非指定了ORDER BY'子句,否則在SELECT語句中不保證SQL中的排序。而且不幸的是,這種行爲並不是微不足道的。事實上,它不會拋出一個錯誤(對於像'語句返回多個結果'之類的東西),我也會產生錯誤。因爲這個原因,我對'UPDATE'上的'JOIN'有點懷疑,儘管它可能簡化了我在DB2中需要做的一些事情。 – 2012-02-29 16:37:00
您沒有可測試的數據?似乎你應該能夠告訴其他人。 – JeffO 2012-02-29 16:49:29
@ X-Zero,我可以確認在多行上加入一行的更新是非確定性的。這怎麼可能?當我想到計算機時,我認爲是確定性的,這對我來說是不尋常的。 – sooprise 2012-02-29 19:18:09