Если бы мы избавились от INNER JOIN
, LEFT JOIN
. RIGHT JOIN
и FULL JOIN
завтра, можем ли мы полностью заменить их функционал на CROSS JOIN
и фильтры на нем? Сначала я думал, что мы, очевидно, можем, но крайние случаи, такие как этот, вызвали у меня сомнения.
Зачем тебе CROSS JOIN
???
Старый синтаксис ANSI-89 для достижения этой цели был объявлен устаревшим в 2008 году и удален в 2012 году; зачем нам снова возвращаться в 1989 год?
Вы, вероятно, можете с некоторыми союзами, но почему вы хотите, можете также удалить соединения и использовать курсоры
Я просто рассматриваю это как вопрос, мотивированный тем, чтобы выяснить, правильно ли они понимают соединения. Не фактическое предложение просто использовать перекрестное соединение везде. Хотя результат перекрестного соединения пустой таблицы, упомянутый в вопросе, уже доказывает, что мы не могли, поэтому не уверены, почему это было задано
LEFT JOIN
нельзя заменить на CROSS JOIN
a
_
1
2
b
_
1
4
a left join b is
1,1
2,null
который не является подмножеством a cross join b
a b
1 1
2 4
ПРИСОЕДИНИТЬСЯ
1, 1
ЛЕВОЕ СОЕДИНЕНИЕ
1, 1
2, NULL
ПРАВОЕ ПРИСОЕДИНЕНИЕ
1, 1
NULL, 4
ПОЛНОЕ СОЕДИНЕНИЕ
1, 1
2, NULL
NULL, 4
ПЕРЕКРЕСТНОЕ СОЕДИНЕНИЕ
1, 1
1, 4
2, 1
2, 4
Как вы собираетесь получить LEFT JOIN от CROSS JOIN?
«Как вы собираетесь получить LEFT JOIN от CROSS JOIN?» - здесь невозможно. Оцените результат a = b
по всем строкам перекрестного соединения. Это возвращает 1, 1
- отслеживайте все отдельные строки слева, соответствуют ли они чему-либо, обратите внимание, что a = 2
никогда ничему не соответствует, поэтому его необходимо сохранить для семантики внешнего соединения и что нам нужно вывести 2, NULL
.
Нет, это не логически «все, что нам нужно».
Логически INNER JOIN
— это просто CROSS JOIN
с предикатом соединения, оцениваемым во всех строках.
В большинстве случаев, если бы вам был представлен результат CROSS JOIN
между таблицами A и B, и он содержал бы идентификатор строки для обеих таблиц A и B, тогда он содержал бы достаточно информации, чтобы вычислить, каким должен быть результат внешнего соединения для определенного предиката соединения ( хотя SQL для этого был бы неэффективен)
Например для
DECLARE @A TABLE
(
A_ID INT PRIMARY KEY,
A_N INT
)
DECLARE @B TABLE
(
B_ID INT PRIMARY KEY,
B_N INT
)
INSERT @A
VALUES (1, 101),
(2, 101),
(3, 102),
(4, 102);
INSERT @B
VALUES (1, 101),
(2, 101);
Тогда один из способов имитации
SELECT *
FROM @A A
LEFT JOIN @B B ON A.A_N = B.B_N;
будет (DB Fiddle)
WITH A_cross_join_B AS
(
SELECT *
FROM @A A
CROSS JOIN @B B
), A_cross_join_B_with_loj_flag AS
(
SELECT *,
/*2 if Join predicate matches, 1 if we are preserving a single instance of this row for outer join purposes, 0 otherwise*/
Flag = CASE WHEN A_N = B_N THEN 2 ELSE CASE WHEN 1 = ROW_NUMBER() OVER (PARTITION BY A_ID ORDER BY CASE WHEN A_N = B_N THEN 0 ELSE 1 END) THEN 1 ELSE 0 END END
FROM A_cross_join_B
)
SELECT A_ID,
A_N,
B_ID = CASE WHEN Flag = 2 THEN B_ID END,
B_N = CASE WHEN Flag = 2 THEN B_N END
FROM A_cross_join_B_with_loj_flag
WHERE Flag <> 0
Приведенное выше действительно основано на том, что все строки из таблицы A и все строки из таблицы B присутствуют в результате перекрестного соединения.
В общем случае каждая строка из таблицы A будет представлена b_card
раз, где b_card
— количество строк в таблице B. Аналогичным образом каждая строка из таблицы B будет представлена a_card
раз.
Если и a_card
, и b_card
равны >=1
, то присутствуют все исходные строки.
Однако случай, когда это падает, - это когда одним из них является 0
, то есть соединение выполняется с пустой таблицей, тогда результат перекрестного соединения пуст, и это было бы невозможно.
Да, это было бы хорошо. Старый синтаксис запятой, который появился до того, как объединение стало словом, именно таков.
select *
from
tableA A, tableB B
where
A.Id = B.Id
Я не вижу ничего, что вы не можете сделать с этим
это плохая идея, перекрестное соединение требует много памяти и времени, чтобы заменить, например, внутреннее соединение, а также ЛЕВОЕ и ПРАВОЕ СОЕДИНЕНИЕ не могут быть заменены перекрестным соединением.