SQL JOIN - предложение WHERE против предложения ON


690

После прочтения, это не дубликат явных и неявных соединений SQL . Ответ может быть связан (или даже один и тот же), но вопрос в другом.


Какая разница и что должно быть у каждого?

Если я правильно понимаю теорию, оптимизатор запросов должен быть в состоянии использовать оба взаимозаменяемо.


2
Просто для будущих читателей и вашей информации вы должны прочитать порядок выполнения SQL. Это поможет вам более точно понять основную разницу.
Рахул Неехра

Ответы:


871

Они не одно и то же.

Рассмотрим эти запросы:

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
Вы получите лучшую производительность, поместив предложение where в предложение on для внутреннего соединения?
FistOfFury

96
@FistOfFury Sql Server использует процедуру оптимизатора запросов, которая компилирует и оценивает ваш код для выработки наилучшего из возможных планов выполнения. Это не идеально, но в большинстве случаев это не имеет значения, и вы получите тот же план выполнения в любом случае.
Джоэл Коухорн

18
В Postgres я отметил, что они НЕ эквивалентны и привели к различным планам запросов. Если вы используете ON, это привело к использованию материализации. Если вы использовали WHERE, он использовал хеш. Материализация имела худший случай, который был в 10 раз дороже, чем хеш. При этом использовался набор идентификаторов, а не один идентификатор.
Джеймс Хатчисон

13
@JamesHutchison Трудно сделать надежные обобщения производительности, основанные на наблюдаемом поведении, подобном этому. То, что было правдой в один день, имеет тенденцию быть неправильным в следующий, потому что это детали реализации, а не документированное поведение. Команды баз данных всегда ищут места для улучшения производительности оптимизатора. Я буду удивлен, если поведение ON не улучшится, чтобы соответствовать ГДЕ. Он может даже не отображаться где-либо в примечаниях к выпуску от версии к версии, кроме как что-то вроде «общего улучшения производительности».
Джоэль Кехорн

4
@FiHoran Это не так, как работает Sql Server. Он будет агрессивно предварительно фильтровать на основе элементов из предложения WHERE, когда статистика покажет, что это может быть полезно.
Джоэл Коухорн

364
  • Не имеет значения для внутренних соединений
  • Вопросы для внешних объединений

    а. WHEREпункт: после вступления. Записи будут отфильтрованы после объединения.

    б. ONоговорка - до присоединения. Записи (из правой таблицы) будут отфильтрованы перед присоединением. Это может закончиться как нуль в результате (так как OUTER join).



Пример : рассмотрим приведенные ниже таблицы:

    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 Нет, это только для объяснения. База данных может сделать что-то более производительное, чем создание промежуточной таблицы.
Сандип Джиндал

Понял, я предположил, что, возможно, был использован третий инструмент.
Мануэль Джордан

146

На INNER JOINs они взаимозаменяемы, и оптимизатор переставит их по желанию.

На OUTER JOINs они не обязательно взаимозаменяемы, в зависимости от того, от какой стороны соединения они зависят.

Я помещаю их в любом месте в зависимости от читабельности.



Это, вероятно, намного яснее в предложении Where, особенно в лямбда-выражениях Linq-To-EntitiesOrders.Join( OrderLines, x => x.ID, x => OrderID, (o,l) => new {Orders = o, Lines = l}).Where( ol => ol.Orders.ID = 12345)
Triynko

49

Я делаю это так:

  • Всегда помещайте условия соединения в ONпредложение, если вы делаете INNER JOIN. Поэтому не добавляйте условия WHERE к предложению ON, поместите их в WHEREпредложение.

  • Если вы делаете LEFT JOIN, добавьте любые условия WHERE в ONпредложение для таблицы в правой части соединения. Это необходимо, потому что добавление предложения WHERE, которое ссылается на правую сторону объединения, преобразует соединение в INNER JOIN.

    Исключение составляют случаи, когда вы ищете записи, которых нет в конкретной таблице. Вы бы добавить ссылку на уникальный идентификатор (который никогда не NULL) в RIGHT JOIN таблицы ИНЕКЕ следующим образом: WHERE t2.idfield IS NULL. Таким образом, единственный раз, когда вы должны ссылаться на таблицу с правой стороны объединения, это найти те записи, которых нет в таблице.


8
Это лучший ответ, который я когда-либо читал по этому вопросу. Полностью имеет смысл , как только ваш мозг понимает , левые присоединиться будет собираются вернуть все строки в таблице слева , и вы должны отфильтровать его позже.
Ник Ларсен

если вы внешне соединяете таблицу с пустым столбцом, то вы все равно можете «где» этот столбец быть нулевым, не делая его внутренним соединением? Это не совсем ищет записи, которые не только в конкретной таблице. Вы можете искать 1. не существует 2. не имеет значения вообще.
около

Я имею в виду, что вы можете искать оба: «1. не существует 2. не имеет значения вообще» вместе. И это относится к случаю, когда это поле не является idfield.
около

Как я столкнулся с этим делом: ищу участников, включая новичка (данные еще не введены) без экстренного контакта.
около

30

На внутреннем соединении они означают одно и то же. Однако вы получите разные результаты во внешнем соединении в зависимости от того, поместите ли вы условие соединения в предложение WHERE vs ON. Взгляните на этот связанный вопрос и этот ответ (мной).

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


26

Это очень распространенный вопрос, поэтому этот ответ основан на статье, которую я написал.

Таблица отношений

Учитывая , мы имеем следующее postи post_commentтаблицы:

Таблицы <code> post </ 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 JOIN

Предложение SQL JOIN позволяет связывать строки, которые принадлежат разным таблицам. Например, CROSS JOIN создаст декартово произведение, содержащее все возможные комбинации строк между двумя объединяющимися таблицами.

Хотя CROSS JOIN полезен в определенных сценариях, в большинстве случаев вы хотите объединить таблицы на основе определенных условий. И именно здесь INNER JOIN вступает в игру.

SQL INNER JOIN позволяет нам фильтровать декартово произведение объединения двух таблиц на основе условия, указанного в предложении ON.

SQL INNER JOIN - ON «всегда истинное» условие

Если вы укажете условие «всегда верно», INNER JOIN не будет фильтровать объединенные записи, а набор результатов будет содержать декартово произведение двух объединяющихся таблиц.

Например, если мы выполним следующий запрос 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 JOIN - ON «всегда ложное» условие

С другой стороны, если условие предложения 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.review |
| ------ | ------------ | ------- | ----------- | --------- - |
| 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

Давайте рассмотрим эти таблицы:

A

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 и условие фильтрации в предложении WHERE.

С точки зрения производительности разницы не должно быть, хотя разные типы SQL иногда обрабатывают планирование запросов по-разному, поэтому стоит попробовать ¯\_(ツ)_/¯ (имейте в виду, что кэширование влияет на скорость запроса)

Также, как отметили другие, если вы используете внешнее объединение, вы получите другие результаты, если вы поместите условие фильтра в предложение ON, поскольку оно влияет только на одну из таблиц.

Я написал более подробный пост об этом здесь: https://dataschool.com/learn/difference-between-where-and-on-in-sql


2

В SQL предложения «WHERE» и «ON» являются разновидностями условных выражений состояния, но основное отличие между ними заключается в том, что выражение «Where» используется в операторах выбора / обновления для указания условий, тогда как предложение «ON» используется в соединениях, где он проверяет или проверяет, совпадают ли записи в таблицах назначения и источника, до объединения таблиц

Например: - «ГДЕ»

SELECT * FROM employee WHERE employee_id=101

Например: - «ВКЛ»

Есть две таблицы employee и employee_details, соответствующие столбцы - employee_id.

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)
...
)

Это (ИМХО) совершенно запутывает человека, и очень легко забыть сослаться table1на что-либо (потому что в таблице «driver» нет предложения «on»), но это законно.


1

для лучшей производительности таблицы должны иметь специальный индексированный столбец для использования в JOINS.

так что если столбец, к которому вы относитесь, не является одним из тех проиндексированных столбцов, то я подозреваю, что лучше хранить его в ГДЕ.

поэтому вы ПРИСОЕДИНЯЕТЕСЬ, используя индексированные столбцы, затем после СОЕДИНЕНИЯ вы запускаете условие для неиндексированного столбца.


1

Обычно фильтрация обрабатывается в предложении WHERE, когда две таблицы уже объединены. Однако возможно, что вы захотите отфильтровать одну или обе таблицы перед тем, как присоединиться к ним. то есть предложение where применяется ко всему набору результатов, тогда как предложение on применяется только к рассматриваемому соединению.


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

1

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

  • FROM (включая объединения)
  • WHERE
  • GROUP BY
  • Скопления
  • HAVING
  • WINDOW
  • SELECT
  • DISTINCT
  • UNION, INTERSECT,EXCEPT
  • ORDER BY
  • OFFSET
  • FETCH

Объединения - это не предложение оператора 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

Что касается вашего вопроса,

Это то же самое, что и «on» или «where» во внутреннем соединении, если ваш сервер может его получить:

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
Группировка только по songs.fullname, а вы также выбираете song_id и singers.fullname, будут проблемой в большинстве баз данных.
btilly
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.