Как выполнить полное внешнее соединение, не имея полного внешнего соединения
-
21-09-2019 - |
Вопрос
На прошлой неделе я был удивлен, узнав, что sybase 12 не поддерживает полные внешние соединения.Но мне пришло в голову, что полное внешнее соединение должно быть таким же, как левое внешнее соединение, объединенное с правым внешним соединением того же sql.Может ли кто-нибудь придумать причину, по которой это не соответствует действительности?
Решение
UNION
-два OUTER JOIN
операторы должны приводить к дублированию строк, представляющих данные, которые вы получили бы из INNER JOIN
.Вам, вероятно, придется сделать SELECT DISTINCT
на наборе данных, созданном UNION
.Обычно, если вам нужно использовать SELECT DISTINCT
это означает, что это не очень хорошо продуманный запрос (по крайней мере, я так слышал).
Другие советы
Если вы объедините их с UNION ALL
, вы получите дубликаты.Если вы просто используете UNION
без ALL
, он будет фильтровать дубликаты и, следовательно, будет эквивалентен полному соединению, но запрос также будет намного дороже, поскольку он должен выполнять отдельную сортировку.
UNION ALL
левое соединение с правым соединением, но ограничьте правое соединение только теми строками, которые не существуют в базовой таблице (возвратите значение null при соединении, если бы они не были бы нулевыми в таблице, если бы они существовали).
Для этого кода вам нужно будет создать две таблицы t1 и t2.t1 должен иметь один столбец с именем c1 и пять строк, содержащих значения 1–5.t2 также должен иметь столбец c1 с пятью строками, содержащими значения 2–6.
Полное внешнее соединение:
select * from t1 full outer join t2 on t1.c1=t2.c1 order by 1, 2;
Полный эквивалент внешнего соединения:
select t1.c1, t2.c1 from t1 left join t2 on t1.c1=t2.c1
union all
select t1.c1, t2.c1 from t1 right join t2 on t1.c1=t2.c1
where t1.c1 is null
order by 1, 2;
Обратите внимание на предложениеwhere справа от объединенного выбора, которое ограничивает результаты только теми, которые не будут повторяться.
Ну, во-первых, я не знаю, почему вы используете 12.x.Это было EndOfLifed 31 декабря 2009 г., после получения уведомления 3 апреля 2007 г.15.0.2 (первая полноценная версия) вышла в январе 2009 года.Версия 15.5 намного лучше и была доступна 2 декабря 2009 года, так что у вас есть два основных выпуска, устаревших как минимум на 13 месяцев.
ASE 12.5.4 имеет новый синтаксис соединения.(вы не указали, возможно у вас 12.5.0.3, релиз до этого).
DB2 и Sybase не реализованы
FULL OUTER JOIN
, именно по той причине, которую вы указали:оно покрытоLEFT ... UNION ... RIGHT
безALL
.Речь идет не о «неподдержке» FOJ;это случай, когда ключевое слово отсутствует.И тогда у вас возникает проблема, заключающаяся в том, что типы Sybase и DB2 обычно никогда не используют внешние соединения, не говоря уже о FOJ, потому что их базы данных имеют тенденцию быть более нормализованными и т. д.
Наконец, есть совершенно обычный SQL, который вы можете использовать в любой версии Sybase, который будет обеспечивать функцию FOJ и будет работать заметно быстрее в версии 12.x;лишь немного быстрее на 15.x.Это что-то вроде функции RANK():совершенно ненужно, если вы можете написать подзапрос.
Вторая причина, по которой это не нужно
FULL OUTER
, как это делают некоторые низкоуровневые движки, объясняется тем, что новый оптимизатор чрезвычайно быстр и запрос полностью нормализован.Т.е.он выполняет ЛЕВОЕ и ПРАВОЕ за один проход.В зависимости от ваших SARG, несоответствий DataType и т. д., возможно, все равно придется сортировать-объединять, но это тоже передается на всех трех уровнях:дисковая подсистема ввода-вывода;двигатель(и);и сетевой обработчик.Если ваши таблицы секционированы, то на этом уровне они дополнительно распараллеливаются.
Если ваш сервер не настроен и ваш набор результатов очень велик, возможно, вам придется увеличить
proc cache size
иnumber of sort buffers
.Вот и все.