SQL Server: полное внешнее соединение, включено или где
Я искал это и не могу найти ответ. Я заранее извиняюсь, так как уверен, что этот ответ уже есть, но я не могу его найти.
Я работаю с БД SQL Server 2005 и знаю, что приведенный ниже запрос не представляет нормализованную БД, поскольку поле numPlacements находится как в таблице сведений, так и в сводной таблице. Я не создал БД.
Приведенный ниже SQL дает ожидаемый результат при использовании предложения where. Ожидаемый результат - все строки, в которых совпадающее значение отсутствует в любой из таблиц или два значения не совпадают.
Однако, если я прокомментирую предложение where и раскомментирую окончательное AND в предложении ON, он вернет более 200 тыс. Строк вместо ожидаемых 120 результатов.
SELECT CASE WHEN A.ID is NULL THEN B.ID ELSE A.ID END,
A.numPlacements AS 'AnumPlacements',
B.numPlacements AS 'bnumPlacements',
B.numPlacements - A.numPlacements as 'Variance'
FROM (SELECT ID,
Sum(numPlacements) AS 'numPlacements'
FROM PlacementDetailLevel
GROUP BY ID) A
FULL OUTER JOIN (SELECT ID,
Sum(numPlacements) AS 'numPlacements'
FROM PlacementRollupLevel
GROUP BY ID) B
ON A.ID = B.ID
--AND B.numPlacements <> A.numPlacements
WHERE A.numPlacements <> B.numPlacements or A.numPlacements is null or B.numPlacements is null
Есть идеи, почему?
Более подробно ниже на основе предложения ypercube:
Я создал TableA и TableB. Они выглядят так:
TableA
ID numPlacements
1 10
2 20
3 30
4 40
TableB
ID numPlacements
2 20
3 31
4 40
5 50
Обратите внимание, что различия состоят в том, что у TableA нет #5, у TableB нет #1, и у #3 есть различные numPlacements в обоих.
SELECT CASE WHEN A.ID is NULL THEN B.ID ELSE A.ID END AS 'ID',
A.numPlacements AS 'AnumPlacements',
B.numPlacements AS 'BnumPlacements',
B.numPlacements - A.numPlacements as 'Variance'
FROM (SELECT ID,
Sum(numPlacements) AS 'numPlacements'
FROM TableA
GROUP BY ID) A
FULL OUTER JOIN (SELECT ID,
Sum(numPlacements) AS 'numPlacements'
FROM TableB
GROUP BY ID) B
ON A.ID = B.ID
Выше приведено именно то, что я ожидал:
ID AnumPlacements BnumPlacements Variance
1 10 NULL NULL
2 20 20 0
3 30 31 1
4 40 40 0
5 NULL 50 NULL
Давайте попробуем добавить предложение WHERE.
SELECT CASE WHEN A.ID is NULL THEN B.ID ELSE A.ID END AS 'ID',
A.numPlacements AS 'AnumPlacements',
B.numPlacements AS 'BnumPlacements',
B.numPlacements - A.numPlacements as 'Variance'
FROM (SELECT ID,
Sum(numPlacements) AS 'numPlacements'
FROM TableA
GROUP BY ID) A
FULL OUTER JOIN (SELECT ID,
Sum(numPlacements) AS 'numPlacements'
FROM TableB
GROUP BY ID) B
ON A.ID = B.ID
WHERE A.numPlacements <> B.numPlacements or A.numPlacements is null or B.numPlacements is null
С помощью где мы получаем три ожидаемых строки:
ID AnumPlacements BnumPlacements Variance
1 10 NULL NULL
3 30 31 1
5 NULL 50 NULL
Давайте попробуем добавить AND.
SELECT CASE WHEN A.ID is NULL THEN B.ID ELSE A.ID END AS 'ID',
A.numPlacements AS 'AnumPlacements',
B.numPlacements AS 'BnumPlacements',
B.numPlacements - A.numPlacements as 'Variance'
FROM (SELECT ID,
Sum(numPlacements) AS 'numPlacements'
FROM TableA
GROUP BY ID) A
FULL OUTER JOIN (SELECT ID,
Sum(numPlacements) AS 'numPlacements'
FROM TableB
GROUP BY ID) B
ON A.ID = B.ID
AND B.numPlacements <> A.numPlacements
Теперь, если мы попробуем это с вышеуказанным AND в соединении, я ожидаю получить строку #3. Вместо этого я получаю это:
ID AnumPlacements BnumPlacements Variance
1 10 NULL NULL
2 NULL 20 NULL
2 20 NULL NULL
3 30 31 1
4 NULL 40 NULL
4 40 NULL NULL
5 NULL 50 NULL