次のステートメントがあり、内部結合の結果はa.Id = b.Idの3つの行になりますが、3つの行のそれぞれに異なるb.Valueがあるとします。 tableAの1行のみが更新されているので、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
通常、このシナリオで最終的に発生するのは、テーブルの物理インデックスの順序で表示される最初の行です。実際には、これを非決定論的なものとして扱い、結果を1行に限定するものを含める必要があります。
私の場合、複数のレコードを更新するための最良のオプションは、マージクエリ(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.
ここに私が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が提供するソリューションを使用して、選択する値を確実に把握することをお勧めします。
つまり、デフォルトの実装を信頼せず、独自の実装を作成してください。しかし、これは興味深い学術的な質問でした:)
はい、ジャスティンピホニーと同様の実験を思いつきました。
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に逆にすると、逆になります。私は上記のポスターに同意します...この操作がエラーメッセージをスローしないので、非常に奇妙です完全に非表示この操作は2次値を無視する