が実際に製品ごとに一意である場合、一意であるserial_number
にもかかわらず複数の行を取得する理由はSerial_Number
、列を適切にエイリアス化していないためです。要約すると、次のものがあります。
SELECT ( select distinct left(product, 6)
from dbo.QS_WIP_Errors2 err
where err.SERIAL_NUMBER = serial_number) -- NO ALIAS ON serial_number
FROM dbo.QS_defects def
相関サブクエリでは、 への 2 番目の参照にエイリアスがありません。これは、外部テーブル ( )serial_number
を参照するか内部テーブル ( ) を参照するかが曖昧であることを意味します。名前の競合が発生した場合、SQL Server は内部テーブルを意味すると想定するため、基本的には次のようになります。def
err
WHERE err.serial_number = err.serial_number
すべてがそれ自体に等しいため、もちろんすべての行が返されます。問題の簡単なデモ:
DECLARE @T TABLE (ID INT, Name VARCHAR(20));
INSERT @T (ID, Name) VALUES (1, 'Test 1'), (2, 'Test 2');
SELECT *
FROM @T AS T1
OUTER APPLY
( SELECT CorrelatedName = Name
FROM @T AS T2
WHERE T2.ID = ID
) AS T3
WHERE T1.ID = 1;
この出力は、"Test 1" と "Test 2" の両方が相関名として返されることを示しています。
ID Name CorrelatedName
----------------------------------
1 Test 1 Test 1
1 Test 1 Test 2
正しいエイリアスを使用すると、単一の行のみが得られます。
DECLARE @T TABLE (ID INT, Name VARCHAR(20));
INSERT @T (ID, Name) VALUES (1, 'Test 1'), (2, 'Test 2');
SELECT *
FROM @T AS T1
OUTER APPLY
( SELECT CorrelatedName = Name
FROM @T AS T2
WHERE T2.ID = T1.ID
) AS T3
WHERE T1.ID = 1;
ID Name CorrelatedName
----------------------------------
1 Test 1 Test 1
したがって、最終的なクエリはおそらく次のようになります。
SELECT CASE WHEN def.serial_number LIKE '550092%' THEN
( SELECT LEFT(err.Product, 6)
FROM dbo.QS_WIP_Errors2 AS err
WHERE err.serial_number = def.serial_number
)
ELSE LEFT(def.serial_number, 6)
END AS IdentNumber
FROM dbo.QS_defects AS def
WHERE def.inspect_time >= '2015-08-01'
AND def.inspect_time <= '2015-08-10';
もう少し手間がかかりますが、クエリを作成するときにすべてを修飾します1。このようにして、各列がどのテーブルからのものであるかがすぐに明確になり、このようなエラーを見つけやすくなります。
1. 1 つのテーブルから単純に選択する場合は、エイリアスや修飾列参照に煩わされることはありませんが、後でテーブルを追加する必要がある場合に備えて、それでもそうしようとします。