SQL ПРИЄДНАЙТЕСЬ - ДІЙСЬКИЙ пункт та пункт ВКЛ


689

Після прочитання це не є дублікатом Explicit vs Implicit SQL Joins . Відповідь може бути пов'язаною (або навіть однаковою), але питання є іншою.


У чому різниця і що має йти в кожному?

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


2
Просто для майбутніх читачів та вашої інформації слід прочитати порядок виконання sql. Це допоможе точніше зрозуміти основну різницю.
Рахул Неехра

Відповіді:


870

Вони не одне і те ж.

Розглянемо ці запити:

SELECT *
FROM Orders
LEFT JOIN OrderLines ON OrderLines.OrderID=Orders.ID
WHERE Orders.ID = 12345

і

SELECT *
FROM Orders
LEFT JOIN OrderLines ON OrderLines.OrderID=Orders.ID 
    AND Orders.ID = 12345

Перший поверне замовлення та його рядки, якщо такі є, за номером замовлення 12345. Другий поверне всі замовлення, але тільки замовлення 12345матиме будь-які рядки, пов'язані з ним.

З а INNER JOIN, пункти фактично рівнозначні. Однак, оскільки вони функціонально однакові, оскільки вони дають однакові результати, це не означає, що два типи застережень мають однакове смислове значення.


83
ви отримаєте кращу ефективність, поставивши пункт "у" для внутрішнього з'єднання?
FistOfFury

96
Сервер @FistOfFury Sql використовує процедуру оптимізатора запитів, яка збирає та оцінює ваш код, щоб створити найкращий план виконання, який він може. Це не ідеально, але більшість часу це не має значення, і ви отримаєте той самий план виконання в будь-якому випадку.
Joel Coehoorn

18
У Postgres я зазначив, що вони НЕ еквівалентні і призводили до різних планів запитів. Якщо ви використовуєте ON, це призвело до використання materialize. Якщо ви використовували WHERE, він використовував хеш. Матеріал мав гірший випадок, який був у 10 разів дорожчим, ніж хеш. Для цього використовувався набір ідентифікаторів, а не один ідентифікатор.
Джеймс Хатчісон

13
@JamesHutchison Важко зробити надійні узагальнення ефективності на основі спостережуваної поведінки, як це. Що було правдою одного дня, як правило, помиляється наступного, оскільки це деталізація, а не документоване поведінка. Команди баз даних завжди шукають місця для підвищення продуктивності оптимізатора. Я буду здивований, якщо поведінка ON не покращиться, щоб відповідати ДЕЙ. Він може навіть не з’являтися ніде у примітках до випуску від версії до версії, окрім чогось, наприклад, "загального покращення продуктивності."
Joel Coehoorn

4
@FiHoran Це не так, як працює сервер Sql. Він буде попередньо фільтрувати на основі пунктів із пункту WHERE, коли статистичні дані показують, що це може бути корисним.
Joel Coehoorn

363
  • Не має значення для внутрішніх приєднань
  • Матеріали для зовнішніх з'єднань

    а. WHEREпункт: Після вступу. Записи будуть відфільтровані після того, як відбудеться приєднання.

    б. ONстаття - До приєднання. Записи (з правої таблиці) будуть відфільтровані до приєднання. Це може закінчитися нульовим результатом (з моменту приєднання OUTER).



Приклад : Розгляньте наведені нижче таблиці:

    1. documents:
     | id    | name        |
     --------|-------------|
     | 1     | Document1   |
     | 2     | Document2   |
     | 3     | Document3   |
     | 4     | Document4   |
     | 5     | Document5   |


    2. downloads:
     | id   | document_id   | username |
     |------|---------------|----------|
     | 1    | 1             | sandeep  |
     | 2    | 1             | simi     |
     | 3    | 2             | sandeep  |
     | 4    | 2             | reya     |
     | 5    | 3             | simi     |

а) Внутрішній WHEREпункт:

  SELECT documents.name, downloads.id
    FROM documents
    LEFT OUTER JOIN downloads
      ON documents.id = downloads.document_id
    WHERE username = 'sandeep'

 For above query the intermediate join table will look like this.

    | id(from documents) | name         | id (from downloads) | document_id | username |
    |--------------------|--------------|---------------------|-------------|----------|
    | 1                  | Document1    | 1                   | 1           | sandeep  |
    | 1                  | Document1    | 2                   | 1           | simi     |
    | 2                  | Document2    | 3                   | 2           | sandeep  |
    | 2                  | Document2    | 4                   | 2           | reya     |
    | 3                  | Document3    | 5                   | 3           | simi     |
    | 4                  | Document4    | NULL                | NULL        | NULL     |
    | 5                  | Document5    | NULL                | NULL        | NULL     |

  After applying the `WHERE` clause and selecting the listed attributes, the result will be: 

   | name         | id |
   |--------------|----|
   | Document1    | 1  |
   | Document2    | 3  | 

б) внутрішня JOINпропозиція

  SELECT documents.name, downloads.id
  FROM documents
    LEFT OUTER JOIN downloads
      ON documents.id = downloads.document_id
        AND username = 'sandeep'

For above query the intermediate join table will look like this.

    | id(from documents) | name         | id (from downloads) | document_id | username |
    |--------------------|--------------|---------------------|-------------|----------|
    | 1                  | Document1    | 1                   | 1           | sandeep  |
    | 2                  | Document2    | 3                   | 2           | sandeep  |
    | 3                  | Document3    | NULL                | NULL        | NULL     |
    | 4                  | Document4    | NULL                | NULL        | NULL     |
    | 5                  | Document5    | NULL                | NULL        | NULL     |

Notice how the rows in `documents` that did not match both the conditions are populated with `NULL` values.

After Selecting the listed attributes, the result will be: 

   | name       | id   |
   |------------|------|
   |  Document1 | 1    |
   |  Document2 | 3    | 
   |  Document3 | NULL |
   |  Document4 | NULL | 
   |  Document5 | NULL | 

40
ІМО - це найкраща відповідь, оскільки вона наочно демонструє, що відбувається "під капотом" інших популярних відповідей.
psrpsrpsr

1
Відмінне пояснення .... молодець! - Просто цікаво, що ти зробив, щоб це отримати intermediate join table?. Якась команда "Пояснити"?
Мануель Йордан

1
@ManuelJordan Ні, це лише для пояснення. База даних може зробити щось ефективніше, ніж створити проміжну таблицю.
Сандіп Джиндал

Зрозумівши, я припускав, що, можливо, використовується третій інструмент.
Мануель Йордан

145

З іншого боку INNER JOINвони взаємозамінні, і оптимізатор переставить їх за бажанням.

Що стосується OUTER JOINs, вони не обов'язково взаємозамінні, залежно від того, від якої сторони з'єднання вони залежать.

Я розміщую їх у будь-якому місці залежно від читабельності.



Це, мабуть, набагато зрозуміліше в пункті «Де», особливо в Orders.Join( OrderLines, x => x.ID, x => OrderID, (o,l) => new {Orders = o, Lines = l}).Where( ol => ol.Orders.ID = 12345)
лямбдаських

49

Я це роблю:

  • Завжди ставите умови приєднання в ONпункті, якщо ви це робите INNER JOIN. Отже, не додайте жодних умов, де БУК до пункту ON, додайте їх до WHEREпункту.

  • Якщо ви робите a LEFT JOIN, додайте будь-які умови WHERE до ONпункту таблиці в правій частині з'єднання. Це обов'язково, тому що додавання пункту WHERE, який посилається на праву частину з'єднання, перетворить приєднання у ВНУТРІШНУ ПРИЄДНАННЯ.

    Виняток - коли ви шукаєте записи, які не знаходяться в певній таблиці. Ви б додати посилання на унікальний ідентифікатор (який ніколи не NULL) в RIGHT JOIN таблиці Інеко наступним чином: WHERE t2.idfield IS NULL. Отже, єдиний раз, коли вам слід посилатися на таблицю з правого боку з'єднання, - це знайти ті записи, яких немає в таблиці.


8
Це найкраща відповідь, яку я до цього часу читав. Повністю має сенс , як тільки ваш мозок розуміє , ліві приєднатися буде збираються повернути всі рядки в таблиці зліва , і ви повинні відфільтрувати його пізніше.
Нік Ларсен

якщо ви приєднаєте зовнішню таблицю з нульовим стовпцем, то ви все ще можете "куди", коли цей стовпець є нульовим, не роблячи його внутрішнім з'єднанням? Це не зовсім шукає записи, які не є лише в конкретній таблиці. Ви можете шукати 1. не існує 2. взагалі не має значення.
Близько

Я маю на увазі, що ви можете шукати і те й інше: "1. не існувало 2. взагалі не має значення". І це стосується випадку, коли це поле не є полем.
Близько

Як я стикався з цим випадком: шукаю учасників, включаючи першокурсника (дані ще не введені) без екстреного контакту.
Близько

30

Під внутрішнім з'єднанням вони означають те саме. Однак ви отримаєте різні результати у зовнішньому з'єднанні залежно від того, якщо ви ставите умову приєднання в пункті WHERE vs ON. Погляньте на це пов’язане питання та цю відповідь (мною).

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


26

Це дуже поширене питання, тому ця відповідь заснована на цій статті, яку я написав.

Табличні відносини

Враховуючи, що ми маємо наступні postта post_commentтаблиці:

Таблиці <code> публікація </code> та <code> post_comment </code>

postМає такі записи:

| id | title     |
|----|-----------|
| 1  | Java      |
| 2  | Hibernate |
| 3  | JPA       |

і post_commentмає наступні три ряди:

| id | review    | post_id |
|----|-----------|---------|
| 1  | Good      | 1       |
| 2  | Excellent | 1       |
| 3  | Awesome   | 2       |

SQL INNER ПРИЄДНАЙТЕСЬ

Запит SQL JOIN дозволяє асоціювати рядки, що належать до різних таблиць. Наприклад, CROSS JOIN створить декартовий продукт, що містить усі можливі комбінації рядків між двома таблицями з'єднання.

Хоча CROSS JOIN корисний у певних сценаріях, більшу частину часу ви хочете приєднати до таблиць на основі конкретної умови. І ось тут грає INNER JOIN.

SQL INNER JOIN дозволяє нам фільтрувати декартовий продукт об'єднання двох таблиць на основі умови, визначеної за допомогою пункту ON.

SQL INNER ПРИЄДНАЙТЕСЬ - УВІМКНЕНО "завжди істинна" умова

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

Наприклад, якщо ми виконуємо наступний запит SQL INNER JOIN:

SELECT
   p.id AS "p.id",
   pc.id AS "pc.id"
FROM post p
INNER JOIN post_comment pc ON 1 = 1

Ми отримаємо всі комбінації postта post_commentзаписи:

| p.id    | pc.id      |
|---------|------------|
| 1       | 1          |
| 1       | 2          |
| 1       | 3          |
| 2       | 1          |
| 2       | 2          |
| 2       | 3          |
| 3       | 1          |
| 3       | 2          |
| 3       | 3          |

Отже, якщо умова пункту ON "завжди відповідає дійсності", INNER JOIN просто еквівалентний запиту CROSS JOIN:

SELECT
   p.id AS "p.id",
   pc.id AS "pc.id"
FROM post p
CROSS JOIN post_comment
WHERE 1 = 1
ORDER BY p.id, pc.id

SQL INNER ПРИЄДНАЙТЕСЬ - УВІМКНЕНО "завжди помилкова" умова

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

Отже, якщо ми виконаємо наступний запит SQL INNER JOIN:

SELECT
   p.id AS "p.id",
   pc.id AS "pc.id"
FROM post p
INNER JOIN post_comment pc ON 1 = 0
ORDER BY p.id, pc.id

Ми не отримаємо жодного результату:

| p.id    | pc.id      |
|---------|------------|

Це тому, що вищезазначений запит еквівалентний наступному запиту CROSS JOIN:

SELECT
   p.id AS "p.id",
   pc.id AS "pc.id"
FROM post p
CROSS JOIN post_comment
WHERE 1 = 0
ORDER BY p.id, pc.id

Пропозиція SQL INNER JOIN - ON, використовуючи стовпці "Зовнішній ключ" та "Первинний ключ"

Найпоширеніша умова пункту ON - це та, яка відповідає стовпцю «Іноземний ключ» у дочірній таблиці зі стовпцем «Первинний ключ» у батьківській таблиці, як це проілюстровано наступним запитом:

SELECT
   p.id AS "p.id",
   pc.post_id AS "pc.post_id",
   pc.id AS "pc.id",
   p.title AS "p.title",
   pc.review  AS "pc.review"
FROM post p
INNER JOIN post_comment pc ON pc.post_id = p.id
ORDER BY p.id, pc.id

Виконуючи вищезазначений запит SQL INNER JOIN, ми отримуємо такий набір результатів:

| p.id    | pc.post_id | pc.id      | p.title    | pc.review |
|---------|------------|------------|------------|-----------|
| 1       | 1          | 1          | Java       | Good      |
| 1       | 1          | 2          | Java       | Excellent |
| 2       | 2          | 3          | Hibernate  | Awesome   |

Отже, до набору результатів запитів включаються лише записи, які відповідають умові пропозиції ON. У нашому випадку набір результатів містить усі postразом з їх post_commentзаписами. Ці postрядки , які не пов'язані post_commentвиключені , так як вони не можуть задовольняти умові ON Clause.

Знову вищезазначений запит SQL INNER JOIN еквівалентний наступному запиту CROSS JOIN:

SELECT
   p.id AS "p.id",
   pc.post_id AS "pc.post_id",
   pc.id AS "pc.id",
   p.title AS "p.title",
   pc.review  AS "pc.review"
FROM post p, post_comment pc
WHERE pc.post_id = p.id

Рядки без удару - це ті, що відповідають умові WHERE, і лише ці записи будуть включені до набору результатів. Це найкращий спосіб уявити, як працює пункт INNER JOIN.

| p.id | pc.post_id | pc.id | p.title | pc.перегляд |
| ------ | ------------ | ------- | ----------- | --------- - |
| 1 | 1 | 1 | Java | Добре |
| 1 | 1 | 2 | Java | Відмінно |
| 1 | 2 | 3 | Java | Дивовижна | 
| 2 | 1 | 1 | Зимує | Добре | 
| 2 | 1 | 2 | Зимує | Відмінно |
| 2 | 2 | 3 | Зимує | Дивовижна |
| 3 | 1 | 1 | JPA | Добре | 
| 3 | 1 | 2 | JPA | Відмінно | 
| 3 | 2 | 3 | JPA | Дивовижна |

Висновок

Оператор INNER JOIN може бути переписаний як CROSS JOIN із пунктом WHERE, який відповідає тому ж умові, який ви використовували в пункті ON запиту INNER JOIN.

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


11

Існує велика різниця між ІНЕК VS. на пункті , коли мова йде про лівому приєднатися.

Ось приклад:

mysql> desc t1; 
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | NO   |     | NULL    |       |
| fid   | int(11)     | NO   |     | NULL    |       |
| v     | varchar(20) | NO   |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+

Існує ідентифікатор таблиці t2.

mysql> desc t2;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | NO   |     | NULL    |       |
| v     | varchar(10) | NO   |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

Запит на "на пункт":

mysql> SELECT * FROM `t1` left join t2 on fid = t2.id AND t1.v = 'K' 
    -> ;
+----+-----+---+------+------+
| id | fid | v | id   | v    |
+----+-----+---+------+------+
|  1 |   1 | H | NULL | NULL |
|  2 |   1 | B | NULL | NULL |
|  3 |   2 | H | NULL | NULL |
|  4 |   7 | K | NULL | NULL |
|  5 |   5 | L | NULL | NULL |
+----+-----+---+------+------+
5 rows in set (0.00 sec)

Запит на "де пункт":

mysql> SELECT * FROM `t1` left join t2 on fid = t2.id where t1.v = 'K';
+----+-----+---+------+------+
| id | fid | v | id   | v    |
+----+-----+---+------+------+
|  4 |   7 | K | NULL | NULL |
+----+-----+---+------+------+
1 row in set (0.00 sec)

Зрозуміло, що перший запит повертає запис з t1 та його залежний рядок від t2, якщо такий є, для рядка t1.v = 'K'.

Другий запит повертає рядки з t1, але лише для t1.v = 'K' буде з ним будь-який асоційований рядок.


9

З точки зору оптимізатора, це не повинно змінювати, чи визначаєте ви приєднувальні пропозиції за допомогою ON або WHERE.

Однак, IMHO, я думаю, що набагато зрозуміліше використовувати пункт ON при виконанні приєднань. Таким чином, у вас є специфічний розділ запиту, який диктує, як обробляється з'єднання, а не змішується з рештою пунктів WHERE.


7

Розглянемо ці таблиці:

А

id | SomeData

Б

id | id_A | SomeOtherData

id_A будучи іноземним ключем до столу A

Написання цього запиту:

SELECT *
FROM A
LEFT JOIN B
ON A.id = B.id_A;

Цей результат забезпечить:

/ : part of the result
                                       B
                      +---------------------------------+
            A         |                                 |
+---------------------+-------+                         |
|/////////////////////|///////|                         |
|/////////////////////|///////|                         |
|/////////////////////|///////|                         |
|/////////////////////|///////|                         |
|/////////////////////+-------+-------------------------+
|/////////////////////////////|
+-----------------------------+

Те, що є в A, а не в B, означає, що для B є нульові значення.


Тепер розглянемо конкретну частину B.id_Aта виділимо її з попереднього результату:

/ : part of the result
* : part of the result with the specific B.id_A
                                       B
                      +---------------------------------+
            A         |                                 |
+---------------------+-------+                         |
|/////////////////////|///////|                         |
|/////////////////////|///////|                         |
|/////////////////////+---+///|                         |
|/////////////////////|***|///|                         |
|/////////////////////+---+---+-------------------------+
|/////////////////////////////|
+-----------------------------+

Написання цього запиту:

SELECT *
FROM A
LEFT JOIN B
ON A.id = B.id_A
AND B.id_A = SpecificPart;

Цей результат забезпечить:

/ : part of the result
* : part of the result with the specific B.id_A
                                       B
                      +---------------------------------+
            A         |                                 |
+---------------------+-------+                         |
|/////////////////////|       |                         |
|/////////////////////|       |                         |
|/////////////////////+---+   |                         |
|/////////////////////|***|   |                         |
|/////////////////////+---+---+-------------------------+
|/////////////////////////////|
+-----------------------------+

Тому що це видаляє внутрішнє приєднання значень, яких немає B.id_A = SpecificPart


Тепер давайте змінимо запит на це:

SELECT *
FROM A
LEFT JOIN B
ON A.id = B.id_A
WHERE B.id_A = SpecificPart;

Результат зараз:

/ : part of the result
* : part of the result with the specific B.id_A
                                       B
                      +---------------------------------+
            A         |                                 |
+---------------------+-------+                         |
|                     |       |                         |
|                     |       |                         |
|                     +---+   |                         |
|                     |***|   |                         |
|                     +---+---+-------------------------+
|                             |
+-----------------------------+

Тому що весь результат фільтрується проти B.id_A = SpecificPartвидалення частин B.id_A = NULL, які знаходяться в A, які не знаходяться в B


4

Ви намагаєтесь приєднатись до даних або фільтрувати дані?

Для читабельності має сенс виділити ці випадки використання відповідно до ON і WHERE.

  • приєднати дані до ВКЛ
  • фільтрують дані в ДІЙ

Прочитати запит, де існує умова JOIN та умова фільтрації, може стати дуже важким.

У продуктивності ви не повинні бачити різниці, хоча різні типи SQL іноді обробляють планування запитів по-різному, так що варто спробувати ¯\_(ツ)_/¯ (Будьте в курсі кешування, що впливає на швидкість запиту)

Крім того, як зазначали інші, якщо ви використовуєте зовнішнє з'єднання, ви отримаєте різні результати, якщо помістити стан фільтра в пункт ON, оскільки це впливає лише на одну з таблиць.

Про це я написав більш глибокий пост тут: https://dataschool.com/learn/difference-between-where-and-on-in-sql


2

У SQL пункт "WHERE" та "ON" - це різновиди умовних статей, але основна відмінність між ними полягає в тому, що пункт "Where" використовується в операторах Select / Update для визначення умов, тоді як пункт "ON" використовується в Joins, де він перевіряє чи перевіряє, чи відповідають записи в таблицях цілей та вихідних даних, перш ніж приєднати таблиці

Наприклад: - "WHERE"

SELECT * FROM employee WHERE employee_id=101

Наприклад: - "ON"

Існують дві таблиці співробітників і службових_деталей, відповідні стовпці - службовий_ід.

SELECT * FROM employee 
INNER JOIN employee_details 
ON employee.employee_id = employee_details.employee_id

Сподіваюся, я відповів на ваше запитання. Зверніться за будь-якими роз'ясненнями.


Але ви могли використовувати ключове слово WHEREзамість ON, чи не так? sqlfiddle.com/#!2/ae5b0/14/0
Qwerty

1

Я думаю, що це ефект послідовності приєднання. У верхньому лівому випадку приєднання SQL спочатку приєднується ліворуч, а потім виконує фільтр. У випадку сходу знайдіть спочатку Orders.ID = 12345, а потім зробіть приєднання.


1

Для внутрішнього з'єднання, WHEREі ONйого можна використовувати без змін. Насправді це можливо використовувати ONу корельованому підзапиті. Наприклад:

update mytable
set myscore=100
where exists (
select 1 from table1
inner join table2
on (table2.key = mytable.key)
inner join table3
on (table3.key = table2.key and table3.key = table1.key)
...
)

Це (IMHO) надзвичайно заплутане для людини, і дуже легко забути посилання table1на що-небудь (адже у таблиці "драйвер" немає пункту "on"), але це законно.


1

для кращої продуктивності таблиці повинні мати спеціальний індексований стовпець, який слід використовувати для JOINS.

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

тож ПРИЄДНАЙТЕ за допомогою індексованих стовпців, потім після JOIN запускаєте умову в неіндексованому стовпчику.


1

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


Це просто не так, оскільки СУБД "нормально" оптимізуються.
філіпсі

1

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

  • FROM (включаючи приєднання)
  • WHERE
  • GROUP BY
  • Агрегації
  • HAVING
  • WINDOW
  • SELECT
  • DISTINCT
  • UNION, INTERSECT,EXCEPT
  • ORDER BY
  • OFFSET
  • FETCH

Joins - це не заява select, а оператор всередині FROM. Таким чином, усі ONпропозиції, що належать відповідному JOINоператору, логічно "вже відбулися" , коли логічна обробка досягне часуWHERE пункту. Це означає, що у випадку LEFT JOIN, наприклад, семантика зовнішнього з'єднання вже відбулася до моменту застосування WHEREпункту.

Наступний приклад я пояснив більш глибоко в цій публікації блогу . Під час запуску цього запиту:

SELECT a.actor_id, a.first_name, a.last_name, count(fa.film_id)
FROM actor a
LEFT JOIN film_actor fa ON a.actor_id = fa.actor_id
WHERE film_id < 10
GROUP BY a.actor_id, a.first_name, a.last_name
ORDER BY count(fa.film_id) ASC;

Це LEFT JOINнасправді не має корисного ефекту, тому що навіть якщо актор не грав у фільмі, актор буде відфільтрований, як його FILM_IDбуде NULLіWHERE пункт фільтрує такий рядок. Результат виглядає приблизно так:

ACTOR_ID  FIRST_NAME  LAST_NAME  COUNT
--------------------------------------
194       MERYL       ALLEN      1
198       MARY        KEITEL     1
30        SANDRA      PECK       1
85        MINNIE      ZELLWEGER  1
123       JULIANNE    DENCH      1

Тобто так, як ніби ми внутрішні приєдналися до двох таблиць. Якщо ми перемістимо предикат фільтра в ONпункті, він тепер стає критерієм зовнішнього приєднання:

SELECT a.actor_id, a.first_name, a.last_name, count(fa.film_id)
FROM actor a
LEFT JOIN film_actor fa ON a.actor_id = fa.actor_id
  AND film_id < 10
GROUP BY a.actor_id, a.first_name, a.last_name
ORDER BY count(fa.film_id) ASC;

Значення результату буде містити акторів без жодного фільму або без жодного фільму FILM_ID < 10

ACTOR_ID  FIRST_NAME  LAST_NAME     COUNT
-----------------------------------------
3         ED          CHASE         0
4         JENNIFER    DAVIS         0
5         JOHNNY      LOLLOBRIGIDA  0
6         BETTE       NICHOLSON     0
...
1         PENELOPE    GUINESS       1
200       THORA       TEMPLE        1
2         NICK        WAHLBERG      1
198       MARY        KEITEL        1

Коротко

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


0

Що стосується вашого питання,

Це те саме, що "увімкнено" або "де" на внутрішньому об'єднанні, доки ваш сервер може отримати це:

select * from a inner join b on a.c = b.c

і

select * from a inner join b where a.c = b.c

Варіант "де" не всі перекладачі знають, тому, можливо, його слід уникати. І звичайно, пункт «увімкнено» зрозуміліший.


-5

це моє рішення.

SELECT song_ID,songs.fullname, singers.fullname
FROM music JOIN songs ON songs.ID = music.song_ID  
JOIN singers ON singers.ID = music.singer_ID
GROUP BY songs.fullname

ви повинніGROUP BY , щоб отримати його на роботу.

Сподіваюся, що це допоможе.


10
Угруповання лише пісень. Ім'я, коли ви також вибираєте song_id та songers.fullname, буде проблемою у більшості баз даних.
btilly
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.