SQL JOIN - klauzula WHERE vs. klauzula ON

688

Po przeczytaniu go, to nie duplikat Explicit vs niejawny SQL przyłącza . Odpowiedź może być powiązana (lub nawet taka sama), ale pytanie jest inne.


Jaka jest różnica i co powinno się w nich znaleźć?

Jeśli dobrze rozumiem teorię, optymalizator zapytań powinien być w stanie używać obu zamiennie.

BCS
źródło
2
Tylko dla przyszłych czytelników i twoich informacji powinieneś przeczytać kolejność wykonywania SQL. Pomogłoby to dokładniej zrozumieć podstawową różnicę.
Rahul Neekhra

Odpowiedzi:

870

To nie to samo.

Rozważ te zapytania:

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

i

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

Pierwszy zwróci zamówienie i jego ewentualne wiersze dla numeru zamówienia 12345. Drugi zwróci wszystkie zamówienia, ale tylko zamówienie 12345będzie miało powiązane linie.

W przypadku INNER JOINklauzule są faktycznie równoważne. Jednak tylko dlatego, że są funkcjonalnie takie same, ponieważ dają takie same wyniki, nie oznacza, że ​​dwa rodzaje klauzul mają to samo znaczenie semantyczne.

Joel Coehoorn
źródło
83
czy uzyskasz lepszą wydajność, umieszczając klauzulę where w klauzuli „on” dla sprzężenia wewnętrznego?
FistOfFury,
96
Serwer @FistOfFury Sql używa procedury optymalizatora zapytań, która kompiluje i ocenia kod w celu stworzenia najlepszego możliwego planu wykonania. To nie jest idealne, ale przez większość czasu nie będzie miało to znaczenia, a ty i tak otrzymasz ten sam plan wykonania.
Joel Coehoorn,
18
W Postgresie zauważyłem, że NIE były one równoważne i skutkowały różnymi planami zapytań. Jeśli użyjesz ON, spowoduje to użycie materializacji. Jeśli użyłeś GDZIE, użyłeś skrótu. Materializacja miała gorszy przypadek, który był 10 razy droższy niż skrót. Użyto zestawu identyfikatorów zamiast jednego identyfikatora.
JamesHutchison
13
@JamesHutchison Trudno jest dokonać wiarygodnych uogólnień wydajności na podstawie zaobserwowanych zachowań takich jak ten. To, co było prawdą jednego dnia, wydaje się być błędne następnego dnia, ponieważ jest to raczej szczegół implementacji niż udokumentowane zachowanie. Zespoły baz danych zawsze szukają miejsc do poprawy wydajności optymalizatora. Zaskoczę się, jeśli zachowanie WŁĄCZENIA nie poprawi się, aby GDZIE. Może nawet nie pojawić się nigdzie w informacjach o wersji z wersji do wersji innej niż „ogólne ulepszenia wydajności.”
Joel Coehoorn
4
@FiHoran Nie tak działa Sql Server. Będzie agresywnie wstępnie filtrować na podstawie elementów z klauzuli WHERE, gdy statystyki pokażą, że może to być pomocne.
Joel Coehoorn,
362
  • Nie ma znaczenia dla połączeń wewnętrznych
  • Sprawy dla połączeń zewnętrznych

    za. WHEREklauzula: Po dołączeniu. Rekordy zostaną odfiltrowane po zakończeniu łączenia.

    b. ONklauzula - Przed dołączeniem. Rekordy (z prawej tabeli) będą filtrowane przed dołączeniem. Wynik może być zerowy (od przyłączenia OUTER).



Przykład : Rozważ poniższe tabele:

    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     |

a) WHEREKlauzula wewnętrzna :

  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  | 

b) JOINKlauzula wewnętrzna

  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 | 
Sandeep Jindal
źródło
40
IMO to najlepsza odpowiedź, ponieważ wyraźnie pokazuje, co dzieje się „pod maską” innych popularnych odpowiedzi.
psrpsrpsr
1
Doskonałe wyjaśnienie .... dobra robota! - Ciekawe, co zrobiłeś, żeby to zdobyć intermediate join table? Jakieś polecenie „Wyjaśnij”?
Manuel Jordan,
1
@ManuelJordan Nie, to tylko dla wyjaśnienia. Baza danych może zrobić coś bardziej wydajnego niż utworzenie tabeli pośredniej.
Sandeep Jindal
Zrozumiałem, przypuszczam, że być może zostało użyte trzecie narzędzie.
Manuel Jordan
145

Na INNER JOINs są wymienne i optymalizator zmienić ich woli.

W przypadku OUTER JOINs niekoniecznie są one zamienne, w zależności od strony połączenia, od której zależą.

Umieszczam je w dowolnym miejscu w zależności od czytelności.

Cade Roux
źródło
Prawdopodobnie jest to o wiele jaśniejsze w klauzuli Where, szczególnie w wyrażeniach lambda 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

Tak to robię:

  • Zawsze umieszczaj warunki łączenia w ONklauzuli, jeśli wykonujesz INNER JOIN. Dlatego nie dodawaj żadnych warunków GDZIE do klauzuli ON, umieść je w WHEREklauzuli.

  • Jeśli wykonujesz a LEFT JOIN, dodaj dowolne warunki WHERE do ONklauzuli dotyczącej tabeli po prawej stronie złączenia. Jest to konieczne, ponieważ dodanie klauzuli WHERE, która odwołuje się do prawej strony złączenia, przekształci złączenie w INNER JOIN.

    Wyjątkiem jest sytuacja, gdy szukasz rekordów, które nie znajdują się w określonej tabeli. Można by dodać odwołanie do unikalnego identyfikatora (który nie jest nigdy NULL) w prawym JOIN tabeli klauzuli WHERE w następujący sposób: WHERE t2.idfield IS NULL. Tak więc jedyny raz, kiedy powinieneś odwołać się do tabeli po prawej stronie złączenia, jest znalezienie tych rekordów, których nie ma w tabeli.

HLGEM
źródło
8
To najlepsza odpowiedź, jaką do tej pory przeczytałem. Całkowicie sens, gdy Twój mózg rozumie LEFT JOIN jest zamiar zwrócić wszystkie wiersze w lewej tabeli i trzeba je filtrować później.
Nick Larsen,
jeśli na zewnątrz dołączysz tabelę z kolumną zerowalną, to nadal możesz „gdzie” ta kolumna jest pusta, nie czyniąc z niej połączenia wewnętrznego? To nie jest dokładnie szukanie rekordów, których nie ma tylko w określonej tabeli. Możesz szukać: 1. nie istniał 2. w ogóle nie ma wartości.
Blisko
Mam na myśli, że możesz szukać obu: „1. nie istniał 2. nie ma w ogóle wartości” razem. Dotyczy to przypadku, gdy to pole nie jest polem id.
Około
Jak spotkałem ten przypadek: szukam uczestników, w tym studentów pierwszego roku (dane jeszcze nie wprowadzono) bez kontaktu w nagłych wypadkach.
Blisko
30

W połączeniu wewnętrznym oznaczają to samo. Jednak uzyskasz różne wyniki w złączeniu zewnętrznym, w zależności od tego, czy umieścisz warunek złączenia w klauzuli WHERE vs ON. Spójrz na to powiązane pytanie i tę odpowiedź (przeze mnie).

Myślę, że najbardziej sensowne jest przyzwyczajenie się do umieszczania warunku łączenia w klauzuli ON (chyba że jest to łączenie zewnętrzne, a tak naprawdę chcesz tego w klauzuli where), ponieważ czyni to bardziej zrozumiałym dla każdego, kto czyta twoje zapytanie w jakich warunkach łączone są tabele, a także pomaga to, aby klauzula WHERE nie miała kilkudziesięciu wierszy.

matowy b
źródło
26

To bardzo częste pytanie, więc ta odpowiedź jest oparta na tym artykule, który napisałem.

Relacja tabeli

Biorąc pod uwagę, że mamy następujące posti post_commenttabele:

Tabele <code> post </code> i <code> post_comment </code>

postMa następujące zapisy:

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

i post_commentma następujące trzy rzędy:

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

DOŁĄCZ DO WEWNĘTRZNEGO SQL

Klauzula JOIN SQL umożliwia powiązanie wierszy należących do różnych tabel. Na przykład CROSS JOIN utworzy produkt kartezjański zawierający wszystkie możliwe kombinacje wierszy między dwiema tabelami łączenia.

Chociaż połączenie krzyżowe jest przydatne w niektórych scenariuszach, w większości przypadków chcesz łączyć tabele w oparciu o określony warunek. I tu właśnie wchodzi INNER JOIN.

SQL INNER JOIN pozwala nam filtrować produkt kartezjański łączenia dwóch tabel w oparciu o warunek określony za pomocą klauzuli ON.

DOŁĄCZ DO WEWNĘTRZNEGO SQL - W stanie „zawsze prawdziwa”

Jeśli podasz warunek „zawsze prawda”, ŁĄCZENIE WEWNĘTRZNE nie będzie filtrowało połączonych rekordów, a zestaw wyników będzie zawierał iloczyn kartezjański dwóch tabel łączących.

Na przykład, jeśli wykonamy następujące zapytanie 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

Otrzymamy wszystkie kombinacje posti post_commentrekordy:

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

Jeśli więc warunek klauzuli ON jest „zawsze prawdziwy”, INNER JOIN jest po prostu równoważne zapytaniu 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

DOŁĄCZ DO WEWNĘTRZNEGO SQL - W stanie „zawsze fałszywe”

Z drugiej strony, jeśli warunek klauzuli ON jest „zawsze fałszywy”, wówczas wszystkie połączone rekordy zostaną odfiltrowane, a zestaw wyników będzie pusty.

Jeśli więc wykonamy następujące zapytanie 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

Nie otrzymamy żadnego wyniku z powrotem:

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

Dzieje się tak, ponieważ powyższe zapytanie jest równoważne następującemu zapytaniu 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 klauzula przy użyciu kolumn klucza obcego i klucza podstawowego

Najczęstszym warunkiem klauzuli ON jest ten, który pasuje do kolumny Klucz obcy w tabeli podrzędnej z kolumną Klucz główny w tabeli nadrzędnej, co ilustruje następujące zapytanie:

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

Podczas wykonywania powyższego zapytania SQL INNER JOIN otrzymujemy następujący zestaw wyników:

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

Tak więc tylko rekordy spełniające warunek klauzuli ON są zawarte w zestawie wyników zapytania. W naszym przypadku zestaw wyników zawiera wszystkie dane postwraz z ich post_commentrekordami. Te postwiersze, które nie związane post_commentsą wyłączone, ponieważ nie może spełniać warunek ON klauzuli.

Ponownie powyższe zapytanie SQL INNER JOIN jest równoważne następującemu zapytaniu 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

Nieprzestrzegane wiersze są tymi, które spełniają klauzulę WHERE i tylko te rekordy zostaną uwzględnione w zestawie wyników. To najlepszy sposób na wizualizację działania klauzuli INNER JOIN.

| p.id | pc.post_id | pc.id | p.title | przegląd pc. |
| ------ | ------------ | ------- | ----------- | --------- - |
| 1 | 1 | 1 | Java | Dobrze |
| 1 | 1 | 2 | Java | Doskonałe |
| 1 | 2 | 3 | Java | Niesamowite | 
| 2 | 1 | 1 | Hibernacja | Dobrze | 
| 2 | 1 | 2 | Hibernacja | Doskonałe |
| 2 | 2 | 3 | Hibernacja | Niesamowite |
| 3 | 1 | 1 | JPA | Dobrze | 
| 3 | 1 | 2 | JPA | Doskonałe | 
| 3 | 2 | 3 | JPA | Niesamowite |

Wniosek

Instrukcja INNER JOIN może zostać przepisana jako CROSS JOIN z klauzulą ​​WHERE pasującą do tego samego warunku, którego użyto w klauzuli ON zapytania INNER JOIN.

Nie dotyczy to tylko DOŁĄCZENIA WEWNĘTRZNEGO, a nie DOŁĄCZANIA ZEWNĘTRZNEGO.

Vlad Mihalcea
źródło
11

Istnieje wielka różnica między klauzulą ​​where a klauzulą , jeśli chodzi o lewe łączenie.

Oto przykład:

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

Tam jest identyfikator tabeli 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)

Zapytanie o klauzulę „on”:

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)

Zapytanie dotyczące „klauzuli gdzie”:

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)

Oczywiste jest, że pierwsze zapytanie zwraca rekord z t1 i jego zależny wiersz z t2, jeśli istnieje, dla wiersza t1.v = „K”.

Drugie zapytanie zwraca wiersze z t1, ale tylko dla t1.v = „K” będzie z nim powiązany dowolny wiersz.

Hrishikesh Mishra
źródło
9

Jeśli chodzi o optymalizator, nie powinno mieć znaczenia, czy definiujesz klauzule łączenia za pomocą ON czy WHERE.

Jednak, IMHO, myślę, że o wiele łatwiej jest użyć klauzuli ON podczas wykonywania złączeń. W ten sposób masz określoną sekcję zapytania, która określa, jak obsługiwane jest łączenie w porównaniu z pozostałymi częściami klauzul WHERE.

Grant Limberg
źródło
7

Rozważmy te tabele:

ZA

id | SomeData

b

id | id_A | SomeOtherData

id_A będąc kluczem obcym do tabeli A

Pisanie tego zapytania:

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

Zapewni ten wynik:

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

To, co jest w A, ale nie w B, oznacza, że ​​dla B. istnieją wartości zerowe.


Teraz rozważmy konkretną część B.id_Ai podkreślmy ją z poprzedniego wyniku:

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

Pisanie tego zapytania:

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

Zapewni ten wynik:

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

Ponieważ powoduje to usunięcie sprzężenia wewnętrznego wartości, których nie ma B.id_A = SpecificPart


Teraz zmieńmy zapytanie na to:

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

Wynik jest teraz:

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

Ponieważ cały wynik jest filtrowany przed B.id_A = SpecificPartusunięciem części B.id_A = NULLznajdujących się w A, które nie są w B

Cid
źródło
4

Czy próbujesz dołączyć dane lub filtrować dane?

Dla czytelności najbardziej sensowne jest izolowanie tych przypadków użycia odpowiednio na ON i WHERE.

  • połączyć dane w ON
  • filtruj dane w GDZIE

Bardzo trudno odczytać zapytanie, w którym warunek JOIN i warunek filtrowania istnieją w klauzuli WHERE.

Jeśli chodzi o wydajność, nie powinieneś widzieć różnicy, chociaż różne typy SQL czasami obsługują planowanie zapytań inaczej, więc warto spróbować ¯\_(ツ)_/¯ (pamiętaj, że buforowanie wpływa na szybkość zapytań)

Również, jak zauważyli inni, jeśli użyjesz sprzężenia zewnętrznego, uzyskasz inne wyniki, jeśli umieścisz warunek filtru w klauzuli ON, ponieważ wpływa on tylko na jedną z tabel.

Bardziej szczegółowy post napisałem o tym tutaj: https://dataschool.com/learn/difference-between-where-and-on-in-sql

Matthew David
źródło
2

W SQL klauzule „WHERE” i „ON” są rodzajem warunkowych instrukcji, ale główna różnica między nimi polega na tym, że klauzula „Where” jest używana w instrukcjach Select / Update do określania warunków, natomiast klauzula „ON” jest używany w połączeniach, gdzie weryfikuje lub sprawdza, czy rekordy są dopasowane w tabelach docelowych i źródłowych, przed dołączeniem tabel

Na przykład: - „GDZIE”

SELECT * FROM employee WHERE employee_id=101

Na przykład: - „ON”

Istnieją dwie tabele pracownik i szczegółowe informacje o pracowniku, pasujące kolumny to identyfikator pracownika.

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

Mam nadzieję, że odpowiedziałem na twoje pytanie. Powróć do wszelkich wyjaśnień.

Sharon Fernando
źródło
Ale możesz użyć słowa kluczowego WHEREzamiast ON, prawda? sqlfiddle.com/#!2/ae5b0/14/0
Qwerty
1

Myślę, że to efekt sekwencji łączenia. W przypadku lewego górnego przypadku łączenia najpierw SQL wykonaj lewe połączenie, a następnie wykonaj filtr gdzie. W niższym przypadku najpierw znajdź Orders.ID = 12345, a następnie dołącz.

Xing-Wei Lin
źródło
1

Do łączenia wewnętrznego WHEREi ONmoże być używany zamiennie. W rzeczywistości możliwe jest użycie ONw skorelowanym podzapytaniu. Na przykład:

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

Jest to (IMHO) całkowicie mylące dla człowieka i bardzo łatwo jest zapomnieć o linkowaniu table1do czegokolwiek (ponieważ tabela „sterownika” nie ma klauzuli „on”), ale jest legalna.

Austin Barry
źródło
1

w celu uzyskania lepszej wydajności tabele powinny mieć specjalną indeksowaną kolumnę do użycia dla JOINS.

więc jeśli kolumna, na której warunkujesz, nie jest jedną z tych indeksowanych kolumn, podejrzewam, że lepiej trzymać ją w GDZIE.

więc ŁĄCZYCIE za pomocą indeksowanych kolumn, a następnie po ŁĄCZENIU uruchamiasz warunek w kolumnie nieindeksowanej.

yakoub abaya
źródło
1

Zwykle filtrowanie jest przetwarzane w klauzuli WHERE po połączeniu dwóch tabel. Możliwe jest jednak, że możesz chcieć przefiltrować jedną lub obie tabele przed dołączeniem do nich. tzn. klauzula where ma zastosowanie do całego zestawu wyników, podczas gdy klauzula on ma zastosowanie tylko do danego sprzężenia.

sree
źródło
Tak się nie dzieje, ponieważ DBMS „normalnie” optymalizują.
philipxy
1

Myślę, że to rozróżnienie można najlepiej wyjaśnić poprzez logiczną kolejność operacji w SQL , co jest uproszczone:

  • FROM (w tym dołączenia)
  • WHERE
  • GROUP BY
  • Agregacje
  • HAVING
  • WINDOW
  • SELECT
  • DISTINCT
  • UNION, INTERSECT,EXCEPT
  • ORDER BY
  • OFFSET
  • FETCH

Połączenia nie są klauzulą ​​instrukcji select, ale operatorem wewnątrz FROM. Jako takie, wszystkie ONklauzule należące do odpowiedniego JOINoperatora „już się zdarzyły” logicznie , zanim przetwarzanie logiczne osiągnie WHEREklauzulę. Oznacza to, że w przypadku LEFT JOIN, na przykład, semantyka sprzężenia zewnętrznego już się zdarzyła do czasuWHERE klauzuli.

Bardziej szczegółowo wyjaśniłem następujący przykład w tym poście na blogu . Podczas uruchamiania tego zapytania:

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;

To LEFT JOINnaprawdę nie ma żadnego użytecznego efektu, ponieważ nawet jeśli aktor nie grał w filmie, aktor zostanie przefiltrowany, tak jak FILM_IDbędzie, NULLa WHEREklauzula przefiltruje taki wiersz. Wynikiem jest coś takiego:

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

To znaczy tak, jakbyśmy połączyli dwa stoliki. Jeśli przeniesiemy predykat filtru w ONklauzuli, stanie się on teraz kryterium dla sprzężenia zewnętrznego:

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;

Oznacza to, że wynik będzie zawierać aktorów bez filmów lub bez filmów z 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

W skrócie

Logicznie zawsze umieszczaj predykat tam, gdzie ma to sens.

Lukas Eder
źródło
0

Jeśli chodzi o twoje pytanie,

Jest to to samo zarówno „na”, jak i „gdzie” na złączeniu wewnętrznym, o ile serwer może to uzyskać:

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

i

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

Opcji „gdzie” nie wszyscy tłumacze znają, więc należy unikać. I oczywiście klauzula włączenia jest jaśniejsza.

Ezequiel
źródło
-5

to jest moje rozwiązanie.

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

Państwo musi miećGROUP BY aby zmusić go do pracy.

Mam nadzieję, że to pomoże.

Le Quang Chien
źródło
10
Grupowanie tylko dla songs.fullname podczas wybierania song_id i singers.fullname będzie problemem w większości baz danych.
btilly,