У меня есть 3 таблицы, к которым я пытаюсь присоединиться. Давайте назовем их TableA, TableB и TableC:
DECLARE @TableA TABLE
(
Key1 int,
PRIMARY KEY
(
Key1
)
)
DECLARE @TableB TABLE
(
Key1 int,
Key2 int,
PRIMARY KEY
(
Key1,
Key2
)
)
DECLARE @TableC TABLE
(
Key3 int NOT NULL,
Key1 int NOT NULL,
Key2 int NULL,
PRIMARY KEY
(
Key3
)
)
Вот некоторые примеры данных:
INSERT INTO @TableA (Key1) VALUES (1);
INSERT INTO @TableB (Key1, Key2) VALUES (1, 1), (1, 2), (1, 3), (1, 4)
INSERT INTO @TableC (Key3, Key1, Key2) VALUES (1, 1, NULL), (2, 1, NULL), (3, 1, 1), (4, 1, 3)
TableB и TableC оба имеют внешние ключи к TableA через Key1. На практике TableC также может ссылаться на TableB через Key1 и Key2 вместе, если Key2 не нуль, но нет фактического внешнего ключа. Key3 не имеет значения, за исключением того факта, что Key1 и Key2 не являются частью первичного ключа TableC.
Я пытаюсь написать запрос, который объединяет таблицы и таблицы:
SELECT
TableA.Key1 AS [A1],
TableB.Key1 AS [B1],
TableB.Key2 AS [B2],
TableC.Key1 AS [C1],
TableC.Key2 AS [C2],
TableC.Key3 AS [C3]
FROM @TableA AS TableA
FULL OUTER JOIN @TableC AS TableC
ON TableC.Key1 = TableA.Key1
FULL OUTER JOIN @TableB AS TableB
ON (TableB.Key1 = TableA.Key1 AND TableC.Key1 IS NULL)
OR (TableC.Key1 = TableB.Key1 AND TableC.Key2 = TableB.Key2)
WHERE (TableA.Key1 = TableB.Key1 OR TableA.Key1 = TableC.Key1)
ORDER BY TableB.Key2, TableC.Key2
Я ожидаю, что TableB и TableC должны включать все свои строки, совпадая с теми, которые совпадают на обоих ключах, и NULLS, где они не совпадают.
Я ожидаю получить это:
A1 B1 B2 C1 C2 C3
1 NULL NULL 1 NULL 1
1 NULL NULL 1 NULL 2
1 1 1 1 1 3
1 1 2 NULL NULL NULL -- THIS ROW IS MISSING
1 1 3 1 3 4
1 1 4 NULL NULL NULL -- THIS ROW IS MISSING
Но вместо этого я получаю это:
A1 B1 B2 C1 C2 C3
1 NULL NULL 1 NULL 1
1 NULL NULL 1 NULL 2
1 1 1 1 1 3
1 1 3 1 3 4
Если я закомментирую предложение WHERE, я получу все ожидаемые строки, за исключением того, что A1 равно NULL для отсутствующих строк:
A1 B1 B2 C1 C2 C3
1 NULL NULL 1 NULL 1
1 NULL NULL 1 NULL 2
1 1 1 1 1 3
NULL 1 2 NULL NULL NULL -- A1 should be 1
1 1 3 1 3 4
NULL 1 4 NULL NULL NULL -- A1 should be 1
Почему TableAU.Key1 возвращается NULL и заставляет его исключать строки, в которых отсутствует Table.Key2?
РЕДАКТИРОВАТЬ:
Вот последний исправленный запрос после того, как я узнал, что я делал неправильно:
SELECT
TableA.Key1 AS A1,
Subquery.*
FROM @TableA AS TableA
INNER JOIN
(
SELECT
TableB.Key1 AS [B1],
TableB.Key2 AS [B2],
TableC.Key1 AS [C1],
TableC.Key2 AS [C2],
TableC.Key3 AS [C3]
FROM @TableC AS TableC
FULL OUTER JOIN @TableB AS TableB
ON TableB.Key1 = TableC.Key1 AND TableB.Key2 = TableC.Key2
) AS Subquery
ON Subquery.B1 = TableA.Key1 OR Subquery.C1 = TableA.Key1
ORDER BY Subquery.B2, Subquery.C2
3 ответа
Почему TableAU.Key1 возвращается NULL и заставляет его исключать строки, в которых отсутствует Table.Key2?
Полное внешнее объединение такое же, как INNER JOIN
, но любые несопоставленные строки с любой стороны добавляются обратно с NULL
для столбцов с другой стороны.
Ваш запрос сначала выполняет полное внешнее объединение A
и C
, поэтому начните с просмотра результата этого.
SELECT
TableA.Key1 AS [A1],
TableC.Key1 AS [C1],
TableC.Key2 AS [C2],
TableC.Key3 AS [C3]
FROM @TableA AS TableA
FULL OUTER JOIN @TableC AS TableC
ON TableC.Key1 = TableA.Key1
Это возвращает следующую виртуальную таблицу (VT1), переходящую к следующему этапу. Поскольку это тот же результат, что и INNER JOIN
, я сомневаюсь, что оно нуждается в каких-либо объяснениях. Каждая строка в @TableC
успешно соответствует отдельной строке в @TableA
.
+----+----+------+----+
| A1 | C1 | C2 | C3 |
+----+----+------+----+
| 1 | 1 | NULL | 1 |
| 1 | 1 | NULL | 2 |
| 1 | 1 | 1 | 3 |
| 1 | 1 | 3 | 4 |
+----+----+------+----+
Затем это полное внешнее соединение на B
. Содержимое B
+------+------+
| Key1 | Key2 |
+------+------+
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 1 | 4 |
+------+------+
INNER JOIN
этих двух наборов результатов с предикатом ON (TableB.Key1 = [A1] AND [C1] IS NULL) OR ([C1] = TableB.Key1 AND [C2] = TableB.Key2)
возвращает только 2 строки.
+----+----+----+----+----+----+
| A1 | B1 | B2 | C1 | C2 | C3 |
+----+----+----+----+----+----+
| 1 | 1 | 1 | 1 | 1 | 3 |
| 1 | 1 | 3 | 1 | 3 | 4 |
+----+----+----+----+----+----+
Несоответствующие строки из VT1
добавляются обратно согласно LEFT JOIN
(это те, где C3
равен 1
или 2
)
+----+------+------+----+------+----+
| A1 | B1 | B2 | C1 | C2 | C3 |
+----+------+------+----+------+----+
| 1 | NULL | NULL | 1 | NULL | 1 |
| 1 | NULL | NULL | 1 | NULL | 2 |
| 1 | 1 | 1 | 1 | 1 | 3 |
| 1 | 1 | 3 | 1 | 3 | 4 |
+----+------+------+----+------+----+
И несопоставленные строки из B
согласно RIGHT JOIN
(это были те, где B2
равен 2
или 4
)
Давая вам окончательный результат
+------+------+------+------+------+------+
| A1 | B1 | B2 | C1 | C2 | C3 |
+------+------+------+------+------+------+
| 1 | NULL | NULL | 1 | NULL | 1 |
| 1 | NULL | NULL | 1 | NULL | 2 |
| 1 | 1 | 1 | 1 | 1 | 3 |
| 1 | 1 | 3 | 1 | 3 | 4 |
| NULL | 1 | 2 | NULL | NULL | NULL |
| NULL | 1 | 4 | NULL | NULL | NULL |
+------+------+------+------+------+------+
Вот что вы хотите - обратите внимание ... вам нужен полный ауттер на B и C, так что A не имеет значения - он даже не нужен в запросе с вашим примером, но вы можете присоединиться к нему слева или внутри как Вы хотите (я использовал левое соединение)
SELECT
TableA.Key1 AS [A1], -- Probably not needed
TableB.Key1 AS [B1],
TableB.Key2 AS [B2],
TableC.Key1 AS [C1],
TableC.Key2 AS [C2],
TableC.Key3 AS [C3]
FROM @TableB AS TableB
FULL OUTER JOIN @TableC AS TableC ON TableB.Key1 = TableC.Key1 and TableB.Key2 = TableC.Key2
LEFT JOIN @TableA AS TableA ON TableB.Key1 = TableA.Key1 -- Probably not needed
SELECT
a.Key1 AS [A1],
b.Key1 AS [B1],
b.Key2 AS [B2],
c.Key1 AS [C1],
c.Key2 AS [C2],
c.Key3 AS [C3]
FROM @TableB b
LEFT JOIN @TableC c
ON c.Key2 = b.Key2
INNER JOIN @TableA a
ON b.Key1 = a.Key1
UNION
SELECT
a.Key1 AS [A1],
b.Key1 AS [B1],
b.Key2 AS [B2],
c.Key1 AS [C1],
c.Key2 AS [C2],
c.Key3 AS [C3]
FROM @TableC c
LEFT JOIN @TableB b
ON c.Key2 = b.Key2
INNER JOIN @TableA a
ON c.Key1 = a.Key1
Выход:
A1 B1 B2 C1 C2 C3
1 NULL NULL 1 NULL 1
1 NULL NULL 1 NULL 2
1 1 1 1 1 3
1 1 2 NULL NULL NULL
1 1 3 1 3 4
1 1 4 NULL NULL NULL
Сначала я получил сторону B, а затем сторону C и использовал соединение, чтобы собрать их вместе.
Надеюсь, это поможет вам ...
Похожие вопросы
Новые вопросы
sql
Язык структурированных запросов (SQL) - это язык запросов к базам данных. Вопросы должны включать примеры кода, структуру таблицы, примеры данных и тег для используемой реализации СУБД (например, MySQL, PostgreSQL, Oracle, MS SQL Server, IBM DB2 и т. Д.). Если ваш вопрос относится исключительно к конкретной СУБД (использует определенные расширения / функции), используйте вместо этого тег этой СУБД. Ответы на вопросы, помеченные SQL, должны использовать стандарт ISO / IEC SQL.