Самосоединение в SQL Oracle; Почему правильное внешнее соединение не сохраняет все значения таблицы

Я не понимаю, почему правое внешнее соединение (пример ниже) не дает полного набора данных таблицы, как это делает левое внешнее соединение; поскольку внешние соединения всегда сохраняют строки соответствующей таблицы.

Создать таблицу

create table join_test
(id number unique not null, name varchar2(10), department varchar2(10));

Заполнить таблицу

select * from join_test;

   ID NAME            DEPARTMENT   
    1 stelios          sa 
    2 andros           sa 
    3 stav             ba  
    4 mary             ba  
    5 antonia          la  
    6 lambros          ka  

Внутреннее соединение

select j1.name, j1.department
from join_test j1 join join_test j2
on(j1.department=j2.department and j1.name<>j2.name);

   NAME         DEPARTMENT
   andros          sa
   steliso         sa
   mary            ba
   stav            ba

Левое внешнее соединение

select j1.name, j1.department
from join_test j1 left join join_test j2
on(j1.department=j2.department and j1.name<>j2.name)

   NAME       DEPARTMENT
   andros     sa
   steliso    sa
   mary       ba
   stav       ba
   antonia    la
   lambros    ka

Правое внешнее соединение

select j1.name, j1.department
from join_test j1 right join join_test j2
on(j1.department=j2.department and j1.name<>j2.name)

   NAME       DEPARTMENT
   steliso    sa
   andros     sa
   stav       ba
   mary       ba

Изменение списка выбора на j2

select j2.name, j2.department
from join_test j1 right join join_test j2
on(j1.department=j2.department and j1.name<>j2.name)

 NAME       DEPARTMENT
 andros     sa
 steliso    sa
 mary       ba
 stav       ba
 antonia    la
 lambros    ka

person Stelios    schedule 11.02.2014    source источник
comment
это было сделано в оракуле   -  person Stelios    schedule 11.02.2014


Ответы (3)


Правое и левое соединения выполняют одну и ту же функцию. Что отличается в ваших примерах, так это таблицы, из которых вы ВЫБИРАЕТЕ.

Эти два запроса:

select j2.name,j2.department
from join_test j1 left join join_test j2
on(j1.department=j2.department and j1.name<>j2.name)

а также

select j1.name,j1.department
from join_test j1 right join join_test j2
on(j1.department=j2.department and j1.name<>j2.name)

Получите тот же результат:

NAME    DEPARTMENT
stelios sa
andros  sa
stav    ba
mary    ba
(null)  (null)
(null)  (null)

Причина разницы в результатах, которую вы видите между вашими левыми и правыми запросами, заключается в том, что в примере left вы выполняете ВЫБОР из «ведущей» таблицы (левая таблица, J1). Соединение показывает все строки из ведущей таблицы (J1) и совпадающие строки (которые не отображаются) из правой или неведущей таблицы (J2).

В вашем правом примере вы меняете объединение, но по-прежнему выбираете из J1. Поскольку J1 теперь является таблицей не управляющей, вы видите только совпадающие результаты из J1. Если вы добавите столбцы J2 в выборку, вы увидите все ее строки:

NAME        DEPARTMENT   NAME       DEPT
stelios     sa           andros     sa
andros      sa           stelios    sa
stav        ba           mary       ba
mary        ba           stav       ba
(null)      (null)       antonia    la
(null)      (null)       lambros    ka

Вы увидите тот же результат с ЛЕВЫМ соединением, но нули не будут с другой стороны.

В обоих случаях (пустые) строки представляют собой строки из ведущей таблицы, которые не совпадают в неведущей таблице.

person Joe    schedule 11.02.2014
comment
Спасибо за объяснение. Я предполагаю, что это тот факт, что я использовал те же имена столбцов; так как это один и тот же стол, это меня смутило. Спасибо, что разъяснили это! - person Stelios; 13.02.2014

Это дает правильные результаты в SQL Fiddle (sqlfiddle.com/#!4/1e7075/2). Однако у меня есть подозрение. Возвращаемые результаты:

NAME    DEPARTMENT
stelios sa
andros  sa
stav    ba
mary    ba
(null)  (null)
(null)  (null)

Я подозреваю, что, как бы вы ни возвращали результаты (или просматривали их), строки со всеми значениями NULL игнорируются. Попробуйте выбрать столбцы из таблицы j2 и посмотрите, получите ли вы больше результатов.

person Gordon Linoff    schedule 11.02.2014
comment
это просто дает тот же результат, что и исходное левое соединение; все данные. если честно, ваше наблюдение за нулевыми значениями только еще больше смутило меня. - person Stelios; 11.02.2014
comment
@user3297834 . . . В этом запросе левое и правое соединения должны давать одинаковые результаты. Я подозреваю, что что-то отфильтровывает строки только со значениями NULL, когда вы смотрите на результаты. - person Gordon Linoff; 11.02.2014

здесь вы делаете самосоединение и комбинируете его с правильным внешним соединением с неравными условиями соединения;

Из того, что я понял: когда он запрашивает правильное соединение, это означает, что он будет извлекать записи только с правой стороны таблицы, где есть строки, соответствующие условиям соединения, и объединять их со строками с левой стороны (основная таблица) где условия соблюдены.

А также потому, что основная таблица - это таблица с левой стороны от, поэтому, когда вы выполняете левое соединение, она извлекает все записи из левой таблицы (основной таблицы) + записи из правой таблицы, где есть строки соответствуют условиям соединения.

Когда дело доходит до внутреннего соединения, оно будет извлекать только совпадающие записи (строки), в которых выполняются условия соединения из обеих таблиц. Даже основная таблица является левой таблицей, все равно строки из левой таблицы, где не выполняются условия, не будут включены в наборы результатов.

Мне потребовалось некоторое время, чтобы понять это, и я надеюсь, что это хорошо объясняет и может быть полезно (COZ, я также изо всех сил пытался понять это раньше).

person sarah prette    schedule 29.01.2021