Як зробити ПОВНОГО ВІДПОЛУЧЕННЯ в MySQL?


654

Я хочу зробити повне зовнішнє приєднання до MySQL. Чи можливо це? Чи підтримується MySQL повне зовнішнє приєднання?



4
На це питання є кращі відповіді
Julio Marins

Остерігайтеся відповідей тут. Стандарт SQL говорить, що повне з'єднання є внутрішнім з'єднанням у рядках об'єднання всіх незрівняних лівих рядків таблиці, розширених об'єднанням нулів, усіх правильних рядків таблиці, розширених нулями. Більшість відповідей тут неправильні (див. Коментарі), а ті, що не помиляються, не вирішують загальну справу. Незважаючи на те, що є багато (невиправданих) подій. (Дивіться мою відповідь.)
philipxy

А як бути, коли ви намагаєтесь приєднатися за допомогою первинних ключів / згрупованих стовпців? як у мене є запит продажів за державою "стан", "продає" та ще один з витрат на стан "стан", "витрати", обидва запити використовують групу по ("держава"). Коли я з'єднуються між лівим і правим, приєднується між двома запитами, я отримую кілька рядків з продажами, але без витрат, ще кілька з витратами, але не продає, все до цього моменту, але я також отримую декілька з обома продає і витрачає і повторний стовпець "держави" ... не багато проблем, але не відчуває себе правильно ...
Jairo Lozano

1
@JairoLozano Обмеження не потрібні. Хоча, коли обмеження містять додаткові запити, повертайте бажану відповідь, яка в іншому випадку не була б. Обмеження не впливають на те, яке повне об'єднання при поверненні для заданих аргументів. Описана вами проблема полягає в тому, що написаний вами запит - це неправильний запит. (Імовірно, поширена помилка, коли люди хочуть приєднатись, кожен з яких може мати інший ключ, деяких підзапитів, кожен з яких може включати приєднання та / або агрегацію, але вони помилково намагаються зробити все об'єднання, а потім усі об'єднання або об'єднання за попередніми агрегаціями .)
philipxy

Відповіді:


669

У вас немає ПОЛЬНИХ ПРИЄДНАНЬ на MySQL, але ви можете впевнено імітувати їх .

Для коду ЗРАБОК, записаного з цього питання, ви маєте:

з двома таблицями t1, t2:

SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id

Наведений вище запит працює в особливих випадках, коли операція FULL OUTER JOIN не створює жодних повторюваних рядків. Наведений вище запит залежить від UNIONзаданого оператора для видалення повторюваних рядків, введених шаблоном запиту. Ми можемо уникнути введення повторюваних рядків, використовуючи шаблон для з'єднання для другого запиту, а потім використовувати оператор набору UNION ALL для об'єднання двох наборів. У більш загальному випадку, коли ПОВНОГО ВИХОДЖЕННЯ ПРИЄДНАЄТЬСЯ повертає повторювані рядки, ми можемо це зробити:

SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION ALL
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id
WHERE t1.id IS NULL

33
Насправді те, що ви написали, невірно. Тому що, коли ви робите UNION, ви видалите дублікати, а іноді, коли ви приєднаєтесь до двох різних таблиць, повинні бути дублікати.
Павло Лекіч

158
Це правильний приклад:(SELECT ... FROM tbl1 LEFT JOIN tbl2 ...) UNION ALL (SELECT ... FROM tbl1 RIGHT JOIN tbl2 ... WHERE tbl1.col IS NULL)
Павло Лекіч

8
Тому різниця полягає в тому, що я роблю приєднання зліва включно, а потім правоексклюзив, використовуючи UNION ALL
Павло Лекіч

5
і я бачу зараз, що ти сам це кажеш, вибач. Можливо, ви могли б оновити свою відповідь, враховуючи, чи є в цьому випадку, що вона помиляється, і що СОЮЗ ВСІ завжди буде більш ефективним?
ysth

10
@ypercube: Якщо немає повторюваних рядків не в t1і t2, запит в цій відповіді дійсно повертає результуючий набір, який емулює FULL OUTER JOIN. Але в більш загальному випадку, наприклад, список SELECT не містить достатньої кількості стовпців / виразів, щоб зробити повернені рядки унікальними, тоді ця схема запитів є недостатньою для відтворення набору, який буде створений a FULL OUTER JOIN. Щоб отримати більш вірну емуляцію, нам знадобиться UNION ALLоператор набору, і для одного із запитів потрібна схема з’єднання . Коментар Павла Лекіча (вище) дає правильну схему запитів.
spencer7593

350

Відповідь Пабло Санта Крус правильна; однак, якщо хтось натрапив на цю сторінку і хоче більше роз'яснень, ось детальний розбір.

Приклад таблиць

Припустимо, у нас є такі таблиці:

-- t1
id  name
1   Tim
2   Marta

-- t2
id  name
1   Tim
3   Katarina

Внутрішня приєднується

Внутрішнє з'єднання, як це:

SELECT *
FROM `t1`
INNER JOIN `t2` ON `t1`.`id` = `t2`.`id`;

Отримали б ми лише записи, які відображаються в обох таблицях, наприклад:

1 Tim  1 Tim

Внутрішні з'єднання не мають напрямку (як лівий чи правий), оскільки вони явно двосторонні - нам потрібна відповідність обох сторін.

Зовнішній приєднується

Зовнішні приєднання, з іншого боку, призначені для пошуку записів, які можуть не відповідати іншій таблиці. Таким чином, ви повинні вказати, на якій стороні з'єднання дозволено мати запис про відсутність.

LEFT JOINі RIGHT JOINє скороченим для LEFT OUTER JOINі RIGHT OUTER JOIN; Я буду використовувати їх повні назви нижче, щоб підсилити концепцію зовнішніх з'єднань проти внутрішніх з'єднань.

Залишилося зовнішнє приєднання

Ліве зовнішнє з'єднання, як це:

SELECT *
FROM `t1`
LEFT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`;

... отримає нам усі записи з лівої таблиці незалежно від того, чи мають вони відповідність у правій таблиці, як це:

1 Tim   1    Tim
2 Marta NULL NULL

Справа назовні

Правий зовнішній з’єднання, як це:

SELECT *
FROM `t1`
RIGHT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`;

... отримає нам усі записи з правої таблиці незалежно від того, чи мають вони відповідність у лівій таблиці, як це:

1    Tim   1  Tim
NULL NULL  3  Katarina

Повне зовнішнє приєднання

Повне зовнішнє з'єднання дасть нам усі записи з обох таблиць, незалежно від того, чи мають вони збіг в іншій таблиці, з NULL з обох сторін, де немає відповідності. Результат виглядатиме так:

1    Tim   1    Tim
2    Marta NULL NULL
NULL NULL  3    Katarina

Однак, як зазначив Пабло Санта Крус, MySQL не підтримує цього. Ми можемо наслідувати це, зробивши об’єднання лівого з'єднання та правого з'єднання, як це:

SELECT *
FROM `t1`
LEFT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`

UNION

SELECT *
FROM `t1`
RIGHT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`;

Ви можете подумати про те UNION, що означає "запустити обидва ці запити, а потім скласти результати один на одного"; частина рядків надходитиме з першого запиту, а частина з другого.

Слід зазначити, що UNIONв MySQL усуне точні дублікати: Тім з’явиться в обох запитах тут, але результат UNIONлише перераховує його один раз. Мій колега з гуру бази даних вважає, що на цю поведінку не слід покладатися. Щоб бути більш чітким щодо цього, ми можемо додати WHEREпункт до другого запиту:

SELECT *
FROM `t1`
LEFT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`

UNION

SELECT *
FROM `t1`
RIGHT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`
WHERE `t1`.`id` IS NULL;

З іншого боку, якщо ви хочете побачити дублікати з якоїсь причини, ви могли б скористатися UNION ALL.


4
Для MySQL ви дійсно хочете уникати використання UNION замість UNION ALL, якщо немає перекриття (див. Коментар Павла вище). Якщо ви можете додати трохи більше інформації для цього у своїй відповіді тут, я думаю, що це було б кращою відповіддю на це питання, оскільки воно є більш ретельним.
Гарен

2
Рекомендація «колеги по гуру бази даних» є правильною. З точки зору реляційної моделі (всі теоретичні роботи, виконані Тедом Коддом та Крісом Дата), запит останньої форми імітує ПОВНІШНІЙ СПІЛЬНИЙ ПРИЄДНАЙТЕСЬ, оскільки вона об'єднує два різних набори, другий запит не вводить "дублікатів" ( рядки, які вже були повернуті першим запитом), які не буде створено a FULL OUTER JOIN. Немає нічого поганого в тому, щоб робити запити таким чином і використовувати UNION для видалення цих дублікатів. Але для того, щоб насправді реплікувати FULL OUTER JOIN, нам потрібен один із запитів, щоб бути антиприєднанням.
spencer7593

1
@IstiaqueAhmed: мета полягає в тому, щоб наслідувати операцію ПОВНОГО ВИКОРИСТАННЯ. Нам потрібна ця умова у другому запиті, тому він повертає лише рядки, у яких немає відповідності (шаблон протиз'єднання.). Без цієї умови запит є зовнішнім з'єднанням ... він повертає рядки, які відповідають, а також ті, що не відповідають. І рядки, які відповідають, вже були повернуті першим запитом. Якщо другий запит повертає ті самі рядки (знову), ми дублювали рядки, і наш результат не буде еквівалентним ПОЛНОМУ ВІДПОЛУЧЕННЮ.
spencer7593

1
@IstiaqueAhmed: Це правда, що UNIONоперація видалить ці дублікати; але він також видаляє ВСІ дублікати рядків, у тому числі повторювані рядки, які були б повернуті ПОВНІШНІМ ВИКОРИСТАННЯМ. Щоб наслідувати a FULL JOIN b, правильна схема є (a LEFT JOIN b) UNION ALL (b ANTI JOIN a).
spencer7593

1
Дуже лаконічна відповідь із чудовим поясненням. Дякую за це
Наджиб

35

Використання unionзапиту видалить дублікати, і це відрізняється від поведінки, full outer joinяка ніколи не видаляє жодного дубліката:

[Table: t1]                            [Table: t2]
value                                  value
-------                                -------
1                                      1
2                                      2
4                                      2
4                                      5

Це очікуваний результат full outer join:

value | value
------+-------
1     | 1
2     | 2
2     | 2
Null  | 5
4     | Null
4     | Null

Це результат використання leftі right Joinз union:

value | value
------+-------
Null  | 5 
1     | 1
2     | 2
4     | Null

[SQL Fiddle]

Мій запропонований запит:

select 
    t1.value, t2.value
from t1 
left outer join t2  
  on t1.value = t2.value
union all      -- Using `union all` instead of `union`
select 
    t1.value, t2.value
from t2 
left outer join t1 
  on t1.value = t2.value
where 
    t1.value IS NULL 

Результат вищезазначеного запиту, такий самий, як і очікуваний результат:

value | value
------+-------
1     | 1
2     | 2
2     | 2
4     | NULL
4     | NULL
NULL  | 5

[SQL Fiddle]


@Steve Chambers : [З коментарів, велике спасибі!]
Примітка. Це може бути найкращим рішенням як для ефективності, так і для отримання тих же результатів, що й а FULL OUTER JOIN. Цей пост у блозі також це добре пояснює - цитую з Методу 2: "Це обробляє дублюючі рядки правильно та не містить нічого, що не повинно. Це потрібно використовувати UNION ALLзамість прості UNION, що усуне дублікати, які я хочу зберегти. Це може бути значно ефективнішим для великих наборів результатів, оскільки немає необхідності сортувати та видаляти дублікати. "


Я вирішив додати ще одне рішення, яке виходить із full outer joinвізуалізації та математики, це не краще, ніж вище, але читабельніше:

Повне зовнішнє з'єднання означає (t1 ∪ t2): все в t1або в t2
(t1 ∪ t2) = (t1 ∩ t2) + t1_only + t2_only: все в обох t1і t2плюс усе в t1тому, що не є, t2і плюс усе в t2тому, що не в t1:

-- (t1 ∩ t2): all in both t1 and t2
select t1.value, t2.value
from t1 join t2 on t1.value = t2.value    
union all  -- And plus 
-- all in t1 that not exists in t2
select t1.value, null
from t1
where not exists( select 1 from t2 where t2.value = t1.value)    
union all  -- and plus
-- all in t2 that not exists in t1
select null, t2.value
from t2
where not exists( select 1 from t1 where t2.value = t1.value)

[SQL Fiddle]


Ми робимо ті ж самі задачі, якщо є підзапроси для t1 і t2, то mysql доведеться виконувати те саме завдання більше разів, чи не так? Чи можемо ми усунути це, використовуючи псевдонім у цій ситуації ?:
Кабір Хоссайн

Я пропоную вам скористатися деякими тимчасовими таблицями;).
shA.t

5
Цей метод здається найкращим рішенням як для ефективності, так і для отримання тих же результатів, що й а FULL OUTER JOIN. Ця публікація в блозі також це добре пояснює - цитую з Методу 2: "Це обробляє дублікати рядків правильно і не включає нічого, що не повинно. Необхідно використовувати UNION ALL замість простого UNION, що усуне дублікати, які я хочу Це може бути значно ефективніше для великих наборів результатів, оскільки немає необхідності сортувати та видаляти дублікати. "
Стів Чемберс

2
@SteveChambers вже пізно, але дякую за ваш коментар. Я додав ваш коментар, щоб потім відповісти на виділене більше, якщо ви не згодні, будь ласка, відкатіть його;).
shA.t

Немає проблем @ shA.t - IMO, це дійсно повинно мати більше результатів і / або бути прийнятою відповіддю.
Стів Чемберс

6

MySql не має синтаксису ПОВНОГО ВИХІД-ПРИЄДНАЙТЕСЯ. Ви повинні наслідувати, виконуючи і СПІЛЬНИЙ ПРИЄДНАЙТЕСЬ, і ПРАВИЛЬНИЙ ПРИЄДНУЙСЯ,

SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id  
UNION
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id

Але MySql також не має синтаксису ПРАВО ПРИЄДНАЙТЕСЬ. Згідно із спрощенням зовнішнього приєднання MySql , право приєднання перетворюється на еквівалентне ліве з'єднання шляхом перемикання t1 і t2 в FROMі ONв запиті. Таким чином, оптимізатор запитів MySql переводить оригінальний запит у наступне -

SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id  
UNION
SELECT * FROM t2
LEFT JOIN t1 ON t2.id = t1.id

Тепер немає жодної шкоди в написанні оригінального запиту таким, який є, але скажіть, якщо у вас є предикати, як пункт WHERE, який є предикатом перед приєднанням або предикатом AND на ONпункті, який є предикатом під час приєднання , тоді ви можливо, захоче поглянути на чорта; що в деталях.

Оптимізатор запитів MySql регулярно перевіряє предикати, чи не відхилено їх . Визначення та приклади, відхилені від нуля Тепер, якщо ви зробили ПРАВИЛЬНЕ ПРИЄДНАННЯ, але з тим, де предикат на стовпчик від t1, ви, можливо, ризикуєте зіткнутися з нульовим сценарієм.

Наприклад, наступний запит -

SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
WHERE t1.col1 = 'someValue'
UNION
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id
WHERE t1.col1 = 'someValue'

Оптимізатор запитів перекладається на наступне:

SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
WHERE t1.col1 = 'someValue'
UNION
SELECT * FROM t2
LEFT JOIN t1 ON t2.id = t1.id
WHERE t1.col1 = 'someValue'

Отже, порядок таблиць змінився, але присудок досі застосовується до t1, але t1 тепер знаходиться у пункті "ON". Якщо t1.col1 визначено як NOT NULL стовпець, то цей запит буде відхилено нулем .

Будь-яке зовнішнє з'єднання (ліве, праве, повне), яке відхилене від нуля , перетворюється на внутрішнє з'єднання MySql.

Таким чином, результати, які ви можете очікувати, можуть бути абсолютно іншими, ніж повертається MySql. Ви можете подумати, що це помилка з ПРАВИМОЮ ПРИЄДНАЙТЕСЬ до MySql, але це не так. Просто так працює оптимізатор запитів MySql. Тож відповідальний розробник повинен звертати увагу на ці нюанси, коли він будує запит.


4

У SQLite слід зробити це:

SELECT * 
FROM leftTable lt 
LEFT JOIN rightTable rt ON lt.id = rt.lrid 
UNION
SELECT lt.*, rl.*  -- To match column set
FROM rightTable rt 
LEFT JOIN  leftTable lt ON lt.id = rt.lrid

Чи можемо ми ним скористатися? як: SELECT * FROM leftTable lt LEFT JOIN ;
Кабір Хоссейн

так, але SQLite не підтримує право приєднання, але так, у MYSQL так
Рамі Джамле,

4

Жоден із наведених відповідей насправді не є правильним, оскільки не відповідає семантиці, коли є дублювані значення.

Для запиту, такого як (з цього дубліката ):

SELECT * FROM t1 FULL OUTER JOIN t2 ON t1.Name = t2.Name;

Правильний еквівалент:

SELECT t1.*, t2.*
FROM (SELECT name FROM t1 UNION  -- This is intentionally UNION to remove duplicates
      SELECT name FROM t2
     ) n LEFT JOIN
     t1
     ON t1.name = n.name LEFT JOIN
     t2
     ON t2.name = n.name;

Якщо для цього вам потрібно працювати зі NULLзначеннями (що також може знадобитися), тоді скористайтеся NULLоператором порівняння -safe, <=>а не =.


3
це часто є хорошим рішенням, але воно може давати інші результати, ніж кожен FULL OUTER JOINраз, коли nameстовпець є недійсним. union allЗапит з анти-Join шаблоном повинен відтворити зовнішнє з'єднання поведінки правильно, але яке рішення є більш відповідним , залежить від контексту і від обмежень, які діють на столах.
fthiella

@fthiella. . . Це хороший момент. Я скоригував відповідь.
Гордон Лінофф

1
Гаразд, але оператор порівняння з нульовою безпекою зробить з'єднання успішним, що відрізняється від повної зовнішньої поведінки приєднання, якщо у вас є нульові імена і в t1, і в t2
fthiella

@fthiella. . . Мені доведеться подумати про найкращий спосіб зробити це. Але з огляду на те, наскільки помилкова прийнята відповідь, майже все ближче до правильної відповіді. (Ця відповідь просто помилкова, якщо в обидві сторони є кілька клавіш.)
Гордон Лінофф,

1
так, прийнята відповідь є неправильною, як загальне рішення, я вважаю, що це правильно використовувати union all, але ця відповідь не вистачає в анти-приєднаному шаблоні ні в першому, ні в другому запиті, який буде зберігати існуючі дублікати, але не дозволяє додавати нові. Залежно від контексту інші рішення (на кшталт цього) можуть бути більш підходящими.
fthiella

3

Модифікований запит shA.t для більшої чіткості:

-- t1 left join t2
SELECT t1.value, t2.value
FROM t1 LEFT JOIN t2 ON t1.value = t2.value   

    UNION ALL -- include duplicates

-- t1 right exclude join t2 (records found only in t2)
SELECT t1.value, t2.value
FROM t1 RIGHT JOIN t2 ON t1.value = t2.value
WHERE t2.value IS NULL 

3

Ви можете зробити наступне:

(SELECT 
    *
FROM
    table1 t1
        LEFT JOIN
    table2 t2 ON t1.id = t2.id
WHERE
    t2.id IS NULL)
UNION ALL
 (SELECT 
    *
FROM
    table1 t1
        RIGHT JOIN
    table2 t2 ON t1.id = t2.id
WHERE
    t1.id IS NULL);

1

що ви сказали про рішення для приєднання Cross ?

SELECT t1.*, t2.*
FROM table1 t1
INNER JOIN table2 t2 
ON 1=1;

2
Ні, це перехресне з'єднання. Він буде відповідати кожному рядку в t1 кожному рядку в t2, даючи набір усіх можливих комбінацій, з select (select count(*) from t1) * (select count(*) from t2))рядками в наборі результатів.
Марк Л.

Хоча цей код може відповісти на питання, надаючи додатковий контекст щодо того, як і чому він вирішує проблему, покращить довгострокове значення відповіді.
Олександр

Яке доповнення може бути корисним? може бути, наприклад,?
Супер Маріо

0
SELECT
    a.name,
    b.title
FROM
    author AS a
LEFT JOIN
    book AS b
    ON a.id = b.author_id
UNION
SELECT
    a.name,
    b.title
FROM
    author AS a
RIGHT JOIN
    book AS b
    ON a.id = b.author_id

0

Це також можливо, але ви повинні згадати однакові назви полів у select.

SELECT t1.name, t2.name FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION
SELECT t1.name, t2.name FROM t2
LEFT JOIN t1 ON t1.id = t2.id

Це просто дублювання результатів зліва.
Матвій

-1

Я виправляю відповідь, і роботи включають усі рядки (на основі відповіді Павла Лекіча)

    (
    SELECT a.* FROM tablea a
    LEFT JOIN tableb b ON a.`key` = b.key
    WHERE b.`key` is null
    )
    UNION ALL
    (
    SELECT a.* FROM tablea a
    LEFT JOIN tableb b ON a.`key` = b.key
    where  a.`key` = b.`key`
    )
    UNION ALL
    (
    SELECT b.* FROM tablea a
    right JOIN tableb b ON b.`key` = a.key
    WHERE a.`key` is null
    );

Ні, це тип з'єднання "лише зовнішнє", яке поверне лише рядки, у tableaяких немає відповідності, tablebі навпаки. Те, що ви намагаєтеся UNION ALL, що спрацювало б лише в тому випадку, якщо ці дві таблиці мають однаково впорядковані стовпці, що не гарантується.
Марк Л.

це працює, я створюю на базі даних temp tablea (1,2,3,4,5,6) та tableb (4,5,6,7,8,9), у його рядках є 3 знаки "id", "number" і "name_number" як текст, і працює лише в результаті (1,2,3,7,8,9)
Rubén Ruíz

1
Це не зовнішнє з'єднання. Зовнішнє з'єднання також включає відповідні члени.
Марк Л.

це нове речення має всі результати 1,2, ..., 9
Рубен Руїз

-2

Відповідь:

SELECT * FROM t1 FULL OUTER JOIN t2 ON t1.id = t2.id;

Можна відтворити так:

 SELECT t1.*, t2.* 
 FROM (SELECT * FROM t1 UNION SELECT name FROM t2) tmp
 LEFT JOIN t1 ON t1.id = tmp.id
 LEFT JOIN t2 ON t2.id = tmp.id;

Використання відповіді UNION або UNION ALL не охоплює крайного випадку, коли базові таблиці мають дублювані записи.

Пояснення:

Є крайній випадок, який не може охопити Спілка чи Союз. Ми не можемо перевірити це на mysql, оскільки він не підтримує ПОЛІШІ ВІДНОСІЛЬНІ ПРИЄДНАННЯ, але ми можемо проілюструвати це на базі даних, яка його підтримує:

 WITH cte_t1 AS
 (
       SELECT 1 AS id1
       UNION ALL SELECT 2
       UNION ALL SELECT 5
       UNION ALL SELECT 6
       UNION ALL SELECT 6
 ),
cte_t2 AS
(
      SELECT 3 AS id2
      UNION ALL SELECT 4
      UNION ALL SELECT 5
      UNION ALL SELECT 6
      UNION ALL SELECT 6
)
SELECT  *  FROM  cte_t1 t1 FULL OUTER JOIN cte_t2 t2 ON t1.id1 = t2.id2;

This gives us this answer:

id1  id2
1  NULL
2  NULL
NULL  3
NULL  4
5  5
6  6
6  6
6  6
6  6

Рішення UNION:

SELECT  * FROM  cte_t1 t1 LEFT OUTER JOIN cte_t2 t2 ON t1.id1 = t2.id2
UNION    
SELECT  * FROM cte_t1 t1 RIGHT OUTER JOIN cte_t2 t2 ON t1.id1 = t2.id2

Дає неправильну відповідь:

 id1  id2
NULL  3
NULL  4
1  NULL
2  NULL
5  5
6  6

Рішення UNION ALL:

SELECT  * FROM cte_t1 t1 LEFT OUTER join cte_t2 t2 ON t1.id1 = t2.id2
UNION ALL
SELECT  * FROM  cte_t1 t1 RIGHT OUTER JOIN cte_t2 t2 ON t1.id1 = t2.id2

Також неправильно.

id1  id2
1  NULL
2  NULL
5  5
6  6
6  6
6  6
6  6
NULL  3
NULL  4
5  5
6  6
6  6
6  6
6  6

Беручи до уваги цей запит:

SELECT t1.*, t2.*
FROM (SELECT * FROM t1 UNION SELECT name FROM t2) tmp 
LEFT JOIN t1 ON t1.id = tmp.id 
LEFT JOIN t2 ON t2.id = tmp.id;

Дає наступне:

id1  id2
1  NULL
2  NULL
NULL  3
NULL  4
5  5
6  6
6  6
6  6
6  6

Порядок інший, але в іншому випадку відповідає правильній відповіді.


Це мило, але неправильно представляє UNION ALLрішення. Крім того, у ньому представлено рішення, UNIONяке використовуватиме повільніше на великих вихідних таблицях через необхідне дедублювання. Нарешті, вона не буде компілюватися, оскільки поля idне існує в підзапиті tmp.
Марк Л.

Я ніколи не висловлював претензії щодо швидкості, і ні в ОП нічого згаданого про швидкість. Якщо припустити, що UNION ALL (ви не покладаєтесь, вкажіть, який з них), і це обидва дасть правильну відповідь, якщо ми хотіли б стверджувати, що один швидший, нам потрібно було б встановити орієнтири, і це було б відмовою від ОП питання.
Ангелос

Щодо зауваження про те, що ідентифікатор не міститься в підзапиті, я виправив помилку друку - дякую, що вказали на нього. Ваша заява про хибні уявлення нечітка - якщо, можливо, ви могли б надати більше інформації, я можу це вирішити. Щодо вашого остаточного зауваження щодо милості, я не маю жодних коментарів, я б скоріше зосередився на логіці sql.
Ангелос

3
Помилково представляє: " UNION ALLРішення: ... також неправильне." Код, який ви подаєте, не виключає перетину-виключення з права з'єднання ( where t1.id1 is null), яке повинно бути вказано в UNION ALL. Що означає, що ваше рішення перемагає всі інші, лише коли одне з цих рішень неправильно реалізовано. Про "милості", взяті точки. Це було виправдано, мої вибачення.
Марк Л.

-3

Стандарт SQL говорить full join on, що inner join onрядки не union allзбігаються лівими рядками таблиці, розширені на нулі. union allПраві рядки таблиці розширені на нулі. Тобто inner join onряди union allрядків у, left join onале не inner join on union allрядки, right join onале не inner join on.

Тобто left join onряди union all right join onрядків не в inner join on. Або якщо ви знаєте, що ваш inner join onрезультат не може мати нуль у певному правильному стовпчику таблиці, тоді " right join onрядки не inner join onє" - це рядки right join onіз onумовою, розширеним andцим стовпцем is null.

Тобто аналогічні right join on union allвідповідні left join onряди.

Від чого відмінність "ВНУТРІШНЯ ПРИЄДНАЙТЕСЬ" та "ВНУТРІШНЯ ПРИЄДНАЙТЕСЬ"? :

(SQL Standard 2006 SQL / Foundation 7.7 Синтаксичні правила 1, Загальні правила 1 b, 3 c & d, 5 b.)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.