Як лівий зовнішній приєднатися може повернути більше записів, ніж існує в лівій таблиці?


165

У мене є дуже базовий ВЛІТЬНИЙ ПРИЄДНАЙТЕСЬ, щоб повернути всі результати з лівої таблиці та додаткову інформацію зі значно більшої таблиці. Ліва таблиця містить 4935 записів, але коли я НАЛЕГУЮТЬСЯ СПОЛУЧАЮТЬ її до додаткової таблиці, кількість записів значно більша.

Наскільки мені відомо, є абсолютною євангелією, що СПІЛЬКИЙ ВІДПРИЄМНИЙ СПИСОК поверне всі записи з лівої таблиці з відповідними записами з правої таблиці та нульовими значеннями для будь-яких рядків, які не можуть бути узгоджені, як таке, я розумію, що це повинно не можна повернути більше рядків, ніж існує в лівій таблиці, але це відбувається все одно!

Наступний запит SQL:

SELECT     SUSP.Susp_Visits.SuspReason, SUSP.Susp_Visits.SiteID
FROM         SUSP.Susp_Visits LEFT OUTER JOIN
                      DATA.Dim_Member ON SUSP.Susp_Visits.MemID = DATA.Dim_Member.MembershipNum

Можливо, я зробив помилку в синтаксисі чи моє розуміння LEFT OUTER JOIN є неповним, сподіваємось, хтось може пояснити, як це могло статися?

Постскрипт

Дякую за чудові відповіді, моє розуміння LEFT OUTER JOINS тепер набагато краще, чи може хто-небудь запропонувати спосіб змінити цей запит, щоб я отримав лише стільки записів, що повернулися, скільки існує в лівій таблиці?

Цей запит полягає лише у створенні звіту, а дублюючі збіги просто плутають питання.

/ Постскрипт


5
Щоб "повернути стільки записів, скільки існує в лівій таблиці", вам потрібно вказати, який рядок з правого боку вибрати, чи є кілька збігів.
АК

1
як ви це вказуєте? Я хотів би повернути перший матч.
Simon Cross

1
ви повинні визначити, що означає перший матч. Чи хочете ви самий ранній запис, той, у кого найвищий ідентифікатор, чи що?
HLGEM

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

Я часто використовую ресурс , як це в якості шпаргалки при створенні запитів. Якщо посилання коли-небудь вмирає, просто приєднайтеся google sql ; це діаграми Венна різних типів з'єднання.
Зімано

Відповіді:


190

LEFT OUTER ПРИЄДНАЙТЕ, коли це можливо, поверне всі записи з таблиці LEFT, поєднаної з таблицею ВПРАВО.

Якщо є збіги, він все одно поверне всі рядки, які відповідають, тому один рядок вліво, який відповідає двом рядкам ВПРАВО, повернеться як два РЯДИ, як і ВНУТРІШНІ ПРИЄДНАННЯ.

РЕДАКТУВАННЯ: У відповідь на вашу редакцію я щойно переглянув ваш запит, і схоже, що ви лише повертаєте дані з таблиці ВЛЕВО. Тому, якщо ви хочете лише дані з таблиці ВЛЕВО, і ви хочете, щоб тільки один рядок повертався для кожного рядка в таблиці ВЛЕВО, то вам взагалі не потрібно виконувати СПОЛУЧЕННЯ, і ви можете просто зробити SELECT безпосередньо з таблиці LEFT.


1
Причиною приєднання до правої таблиці було те, що я отримав записи лише зліва, де в правій таблиці був принаймні один запис, але дуже дякую за пояснення.
Джей Уайльд

125
Table1                Table2
_______               _________
1                      2
2                      2
3                      5
4                      6

SELECT Table1.Id, Table2.Id FROM Table1 LEFT OUTER JOIN Table2 ON Table1.Id=Table2.Id

Результати:

1,null
2,2
2,2
3,null
4,null

1
Так просто, і все ж таки потужно.
kiradotee

39

Це не неможливо. Кількість записів у лівій таблиці - це мінімальна кількість записів, які вона поверне. Якщо права таблиця має два записи, які відповідають одному запису в лівій таблиці, вона поверне два записи.


12

У відповідь на ваш постскрипт, це залежить від того, що б ви хотіли.

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

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

Якщо ви дивитесь лише на 1 або 2 стовпчики із зовнішнього з'єднання, ви можете скористатися скалярним підзапитом, оскільки вам буде гарантовано 1 результат.


4
Це хороша відповідь, оскільки він пропонує пропозиції щодо повернення лише рядків із лівої таблиці.
karns

9

Кожен запис з лівої таблиці буде повернуто стільки разів, скільки в правій таблиці є відповідні записи - принаймні 1, але їх легко може бути більше 1.


8

ЛІВНІШЕ ВІДПОЛУЧАЙТЕ так само, як INNER JOIN (нормальне з'єднання) поверне стільки результатів для кожного рядка в лівій таблиці, скільки збігів, знайдених у правій таблиці. Отже, у вас може бути багато результатів - до N x M, де N - кількість рядків у лівій таблиці, а M - кількість рядків у правій таблиці.

Це мінімальна кількість результатів, які завжди гарантуються, щоб ЛІФТ ЗОВНІШНІЙ ПРИЄДНАЙТЕ як мінімум N.


1
Я почав думати, коли кількість рядків дорівнює N x M, і єдина реальна ситуація, яка мені спадає на думку, це коли N або M дорівнює 1. Чи згодні ви?
BartoszMiller

2
Ні, я ні. Не слід думати про умову приєднання як про ключове рівність приєднання лише. Це може бути довільна умова, наприклад, діапазони дат, нерівності тощо. Два крайніх випадки: (a) N рядків не мають жодної відповідності серед M рядків, тоді ліві результати зовнішнього з'єднання в N рядках збігаються з NULL. (b) кожен з N рядків відповідає всім M рядків, тоді результат встановлюється N x M рядків.
топчеф

1
Ви маєте рацію, я думав про приєднання лише з точки зору ключової рівності. Мені подобається твій приклад із "випадку b". Я вважаю, що "кожен з N рядків відповідає всім M рядків" - це загальний рецепт повернення N x M рядків, який неможливо уявити, коли думати лише про ключову рівність.
BartoszMiller


6

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


1
Потім слід додати умову до пункту ON відповідного лівого ВИХІДНОГО ПРИЄДНАННЯ.
Мік

6

Якщо вам потрібен будь-який один ряд з правого боку

SELECT SuspReason, SiteID FROM(
    SELECT SUSP.Susp_Visits.SuspReason, SUSP.Susp_Visits.SiteID, ROW_NUMBER()
    OVER(PARTITION BY SUSP.Susp_Visits.SiteID) AS rn
    FROM SUSP.Susp_Visits
    LEFT OUTER JOIN DATA.Dim_Member ON SUSP.Susp_Visits.MemID = DATA.Dim_Member.MembershipNum
) AS t
WHERE rn=1

або просто

SELECT SUSP.Susp_Visits.SuspReason, SUSP.Susp_Visits.SiteID
FROM SUSP.Susp_Visits WHERE EXISTS(
    SELECT DATA.Dim_Member WHERE SUSP.Susp_Visits.MemID = DATA.Dim_Member.MembershipNum
)

1
Оскільки ви не надали DDL та DML, я не тестував. У будь-якому випадку я думаю, що EXISTS - це те, чого ти хочеш. Тест: SELECT SuspReason, SiteID ВІД (ВИБІР SUSP.Susp_Visits.SuspReason, SUSP.Susp_Visits.SiteID, ROW_NUMBER () OVER (PARTITION BY SUSP.Susp_Visits.SiteID ORDER BY SUSP.Susp_Visits.SiteID) ЯК гп ВІД SUSP.Susp_Visits LEFT OUTER РЕЄСТРУЙСЯ DATA.Dim_Member ON SUSP.Susp_Visits.MemID = DATA.Dim_Member.MembershipNum) AS т ДЕ гп = 1
AK

2

Схоже, у таблиці DATA.Dim_Member в рядку SUSP.Susp_Visits є кілька рядків.


2

якщо декілька (x) рядків у Dim_Member пов'язані з одним рядком у Susp_Visits, у отриманому наборі буде x рядків.

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