SQL BERGABUNG - DI MANA klausa vs. klausa ON

686

Setelah membacanya, ini bukan duplikat dari Bergabung SQL Eksplisit vs Implisit . Jawabannya mungkin terkait (atau bahkan sama) tetapi pertanyaannya berbeda.


Apa perbedaannya dan apa yang harus dilakukan pada masing-masing?

Jika saya memahami teori dengan benar, pengoptimal kueri harus dapat menggunakan keduanya secara bergantian.

BCS
sumber
2
Hanya untuk pembaca masa depan dan informasi Anda, Anda harus membaca urutan eksekusi sql. Ini akan membantu Anda lebih tepat untuk memahami perbedaan yang mendasarinya.
Rahul Neekhra

Jawaban:

869

Mereka bukan hal yang sama.

Pertimbangkan pertanyaan ini:

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

dan

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

Yang pertama akan mengembalikan pesanan dan garisnya, jika ada, untuk nomor pesanan 12345. Yang kedua akan mengembalikan semua pesanan, tetapi hanya pesanan yang 12345akan memiliki garis yang terkait dengannya.

Dengan INNER JOIN, klausa secara efektif setara. Namun, hanya karena keduanya secara fungsional sama, dalam arti mereka menghasilkan hasil yang sama, tidak berarti kedua jenis klausa memiliki makna semantik yang sama.

Joel Coehoorn
sumber
83
apakah Anda akan mendapatkan kinerja yang lebih baik dengan meletakkan klausa where di klausa "on" untuk join internal?
FistOfFury
96
@FistOfFury Sql Server menggunakan prosedur optimizer kueri yang mengkompilasi dan mengevaluasi kode Anda untuk menghasilkan rencana eksekusi terbaik yang dapat dilakukannya. Itu tidak sempurna, tetapi sebagian besar waktu itu tidak masalah dan Anda akan mendapatkan rencana eksekusi yang sama.
Joel Coehoorn
18
Dalam Postgres saya mencatat bahwa mereka TIDAK setara dan menghasilkan rencana permintaan yang berbeda. Jika Anda menggunakan HIDUP, itu mengakibatkan penggunaan materialize. Jika Anda menggunakan WHERE, itu menggunakan hash. Materialize memiliki kasus yang lebih buruk yaitu 10x lebih mahal daripada hash. Ini menggunakan satu set ID daripada satu ID.
JamesHutchison
13
@JamesHutchison Sangat sulit untuk membuat generalisasi kinerja yang andal berdasarkan perilaku yang diamati seperti ini. Apa yang benar suatu hari cenderung salah pada hari berikutnya, karena ini adalah detail implementasi daripada perilaku yang didokumentasikan. Tim basis data selalu mencari tempat untuk meningkatkan kinerja pengoptimal. Saya akan terkejut jika perilaku ON tidak membaik untuk mencocokkan dengan WHERE. Bahkan mungkin tidak muncul di mana pun di catatan rilis dari versi ke versi selain sesuatu seperti "peningkatan kinerja umum.
Joel Coehoorn
4
@FiHoran Bukan itu cara kerja Sql Server. Ini akan melakukan pra-filter secara agresif berdasarkan item dari klausa WHERE ketika statistik menunjukkan itu bisa membantu.
Joel Coehoorn
362
  • Tidak masalah untuk gabungan batin
  • Hal-hal untuk gabungan luar

    Sebuah. WHEREklausa: Setelah bergabung. Catatan akan disaring setelah bergabung telah terjadi.

    b. ONklausa - Sebelum bergabung. Rekaman (dari tabel kanan) akan difilter sebelum bergabung. Ini mungkin berakhir sebagai nol dalam hasil (sejak OUTER bergabung).



Contoh : Pertimbangkan tabel di bawah ini:

    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) WHEREKlausa di dalam :

  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) JOINKlausa di dalam

  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
sumber
40
IMO ini adalah jawaban terbaik karena jelas menunjukkan apa yang sedang terjadi 'di bawah tenda' dari jawaban populer lainnya.
psrpsrpsr
1
Penjelasan yang sangat baik .... dilakukan dengan baik! - Hanya ingin tahu apa yang Anda lakukan untuk mendapatkan itu intermediate join table? Perintah 'Jelaskan'?
Manuel Jordan
1
@ManuelJordan Tidak, ini hanya untuk penjelasan. Database mungkin melakukan sesuatu yang lebih berkinerja daripada membuat tabel perantara.
Sandeep Jindal
Dipahami, saya berasumsi mungkin alat ketiga digunakan.
Manuel Jordan
145

Pada saat INNER JOINmereka dipertukarkan, dan pengoptimal akan mengatur ulang mereka di akan.

Pada tanggal OUTER JOIN, mereka tidak perlu dipertukarkan, tergantung pada sisi mana mereka bergabung.

Saya menempatkan mereka di kedua tempat tergantung pada keterbacaan.

Cade Roux
sumber
Ini mungkin jauh lebih jelas dalam klausa Where, terutama dalam ekspresi 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

Cara saya melakukannya adalah:

  • Selalu masukkan ketentuan gabungan dalam ONklausa jika Anda melakukan INNER JOIN. Jadi, jangan menambahkan kondisi WHERE ke klausa ON, letakkan mereka di WHEREklausa.

  • Jika Anda melakukan a LEFT JOIN, tambahkan kondisi WHERE ke ONklausa untuk tabel di sisi kanan gabungan. Ini adalah suatu keharusan, karena menambahkan klausa WHERE yang mereferensikan sisi kanan join akan mengonversi join menjadi INNER JOIN.

    Pengecualian adalah ketika Anda mencari catatan yang tidak ada dalam tabel tertentu. Anda akan menambahkan referensi untuk pengenal yang unik (yang tidak pernah NULL) di KANAN JOIN meja dengan klausa WHERE cara ini: WHERE t2.idfield IS NULL. Jadi, satu-satunya waktu Anda harus mereferensikan tabel di sisi kanan bergabung adalah menemukan catatan-catatan yang tidak ada dalam tabel.

HLGEM
sumber
8
Ini adalah jawaban terbaik yang saya baca sejauh ini. Benar-benar masuk akal setelah otak Anda memahami gabungan kiri akan mengembalikan semua baris di tabel kiri dan Anda harus memfilternya nanti.
Nick Larsen
jika Anda luar bergabung dengan tabel dengan kolom nullable, maka Anda masih bisa "di mana" kolom itu menjadi nol tanpa menjadikannya join dalam? Itu tidak persis mencari catatan yang tidak ada dalam tabel tertentu saja. Anda dapat mencari 1. tidak ada 2. tidak memiliki nilai sama sekali.
Dekat
Maksud saya Anda dapat mencari keduanya: "1. tidak ada 2. tidak memiliki nilai sama sekali" bersama-sama. Dan ini berlaku untuk kasus di mana bidang itu bukan idfield.
Dekat
Seperti yang saya temui kasus ini: mencari peserta termasuk mahasiswa baru (data belum dimasukkan) tanpa kontak darurat.
Dekat
30

Pada gabungan batin, mereka memiliki arti yang sama. Namun Anda akan mendapatkan hasil yang berbeda di gabung luar tergantung pada jika Anda memasukkan kondisi gabung di WHERE vs klausa ON. Lihatlah pertanyaan terkait ini dan jawaban ini (oleh saya).

Saya pikir itu masuk akal untuk menjadi kebiasaan selalu menempatkan kondisi bergabung dalam klausa ON (kecuali itu adalah join luar dan Anda benar-benar menginginkannya di klausa mana) karena membuatnya lebih jelas bagi siapa pun yang membaca kueri Anda pada kondisi apa tabel-tabel tersebut disambung, dan juga membantu mencegah klausa WHERE dari lusinan garis.

matt b
sumber
26

Ini adalah pertanyaan yang sangat umum, jadi jawaban ini didasarkan pada artikel yang saya tulis ini.

Hubungan meja

Mengingat kami memiliki tabel postdan post_commenttabel berikut :

Tabel <code> post </code> dan <code> post_comment </code>

The postmemiliki catatan berikut:

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

dan post_commentmemiliki tiga baris berikut:

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

SQL INNER BERGABUNG

Klausa SQL JOIN memungkinkan Anda untuk mengaitkan baris milik tabel yang berbeda. Misalnya, CROSS JOIN akan membuat Produk Cartesian yang berisi semua kemungkinan kombinasi baris antara dua tabel yang bergabung.

Meskipun CROSS JOIN berguna dalam skenario tertentu, sebagian besar waktu, Anda ingin bergabung dengan tabel berdasarkan kondisi tertentu. Dan, di situlah INNER BERGABUNG berperan.

SQL INNER JOIN memungkinkan kita untuk menyaring Produk Cartesian dari bergabung dengan dua tabel berdasarkan kondisi yang ditentukan melalui klausa ON.

SQL INNER JOIN - ON "selalu benar" kondisi

Jika Anda memberikan kondisi "selalu benar", INNER JOIN tidak akan memfilter rekaman yang bergabung, dan kumpulan hasil akan berisi Produk Cartesian dari dua tabel bergabung.

Misalnya, jika kami menjalankan query SQL INNER JOIN berikut:

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

Kami akan mendapatkan semua kombinasi postdan post_commentcatatan:

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

Jadi, jika kondisi klausa ON "selalu benar", INNER JOIN sama dengan kueri 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 "selalu salah" kondisi

Di sisi lain, jika kondisi klausa ON "selalu salah", maka semua catatan yang bergabung akan disaring dan hasil yang ditetapkan akan kosong.

Jadi, jika kita menjalankan query SQL INNER JOIN berikut:

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

Kami tidak akan mendapatkan hasil apa pun:

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

Itu karena kueri di atas setara dengan kueri Gabung Gabung berikut:

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 klausa menggunakan kolom Foreign Key dan Primary Key

Kondisi klausa ON paling umum adalah kondisi yang cocok dengan kolom Kunci Asing di tabel anak dengan kolom Kunci Utama di tabel induk, seperti yang diilustrasikan oleh permintaan berikut:

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

Saat menjalankan query SQL INNER JOIN di atas, kami mendapatkan hasil sebagai berikut:

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

Jadi, hanya catatan yang cocok dengan kondisi klausa ON yang termasuk dalam set hasil kueri. Dalam kasus kami, set hasil berisi semua postbeserta post_commentcatatannya. The postbaris yang telah ada terkait post_commentdikecualikan karena mereka tidak dapat memenuhi kondisi ON Clause.

Sekali lagi, kueri SQL INNER JOIN di atas setara dengan kueri CROSS JOIN berikut:

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

Baris yang tidak disambar adalah yang memenuhi klausa WHERE, dan hanya catatan ini yang akan dimasukkan dalam hasil yang ditetapkan. Itulah cara terbaik untuk memvisualisasikan cara kerja klausa INNER JOIN.

| p.id | pc.post_id | pc.id | p.title | pc.review |
| ------ | ------------ | ------- | ----------- | --------- - |
| 1 | 1 | 1 | Jawa | Bagus |
| 1 | 1 | 2 | Jawa | Luar Biasa |
| 1 | 2 | 3 | Jawa | Luar Biasa | 
| 2 | 1 | 1 | Hibernasi | Bagus | 
| 2 | 1 | 2 | Hibernasi | Luar Biasa |
| 2 | 2 | 3 | Hibernasi | Luar Biasa |
| 3 | 1 | 1 | JPA | Bagus | 
| 3 | 1 | 2 | JPA | Luar Biasa | 
| 3 | 2 | 3 | JPA | Luar Biasa |

Kesimpulan

Pernyataan INNER JOIN dapat ditulis ulang sebagai CROSS JOIN dengan klausa WHERE yang cocok dengan kondisi yang sama dengan yang Anda gunakan pada klausa ON dari permintaan INNER JOIN.

Bukan berarti ini hanya berlaku untuk INNER JOIN, bukan untuk OUTER JOIN.

Vlad Mihalcea
sumber
11

Ada perbedaan besar antara di mana klausa vs klausa , ketika datang ke kiri bergabung.

Berikut ini contohnya:

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

Ada fid id dari tabel 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)

Permintaan pada "pada klausa":

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)

Pertanyaan tentang "di mana klausa":

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)

Jelas bahwa, permintaan pertama mengembalikan catatan dari t1 dan baris dependennya dari t2, jika ada, untuk baris t1.v = 'K'.

Kueri kedua mengembalikan baris dari t1, tetapi hanya untuk t1.v = 'K' akan memiliki baris terkait dengannya.

Hrishikesh Mishra
sumber
9

Dalam hal pengoptimal, seharusnya tidak membuat perbedaan apakah Anda mendefinisikan klausa bergabung Anda dengan ON atau WHERE.

Namun, IMHO, saya pikir itu jauh lebih jelas untuk menggunakan klausa ON saat melakukan bergabung. Dengan cara itu Anda memiliki bagian spesifik dari kueri Anda yang menentukan bagaimana gabungan ditangani versus dicampur dengan klausa WHERE lainnya.

Grant Limberg
sumber
7

Mari kita perhatikan tabel-tabel itu:

SEBUAH

id | SomeData

B

id | id_A | SomeOtherData

id_A menjadi kunci asing ke meja A

Menulis kueri ini:

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

Akan memberikan hasil ini:

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

Apa yang ada di A tetapi tidak di B berarti ada nilai null untuk B.


Sekarang, mari kita pertimbangkan bagian tertentu di B.id_Adalamnya, dan sorot dari hasil sebelumnya:

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

Menulis kueri ini:

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

Akan memberikan hasil ini:

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

Karena ini menghapus di bagian dalam bergabung dengan nilai-nilai yang tidak ada di B.id_A = SpecificPart


Sekarang, mari kita ubah kueri menjadi ini:

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

Hasilnya sekarang:

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

Karena seluruh hasil disaring agar tidak B.id_A = SpecificPartmenghapus bagian B.id_A = NULL, yang ada di A yang tidak di B

Cid
sumber
4

Apakah Anda mencoba menggabungkan data atau memfilter data?

Agar mudah dibaca, sebaiknya isolasi kasus penggunaan ini ke ON dan WHERE.

  • gabung data dalam ON
  • filter data di MANA

Sangat sulit untuk membaca kueri di mana kondisi GABUNG dan kondisi penyaringan ada di klausa WHERE.

Dari segi kinerja, Anda seharusnya tidak melihat perbedaan, meskipun beberapa tipe SQL terkadang menangani perencanaan kueri yang berbeda sehingga layak untuk dicoba ¯\_(ツ)_/¯(Berhati-hatilah dengan caching yang memengaruhi kecepatan kueri)

Juga seperti yang telah dicatat orang lain, jika Anda menggunakan gabungan luar Anda akan mendapatkan hasil yang berbeda jika Anda menempatkan kondisi filter dalam klausa ON karena hanya mempengaruhi salah satu tabel.

Saya menulis posting yang lebih mendalam tentang ini di sini: https://dataschool.com/learn/difference-between-where-and-on-in-sql

matthew david
sumber
2

Dalam SQL, klausa 'WHERE' dan 'ON', adalah semacam Statistic Bersyarat, tetapi perbedaan utama di antara keduanya adalah, klausa 'Di mana' digunakan dalam Pernyataan Pilih / Pembaruan untuk menentukan Ketentuan, sedangkan klausa 'ON' digunakan dalam Bergabung, di mana ia memverifikasi atau memeriksa apakah Catatan Cocok dengan target dan tabel sumber, sebelum Tabel Bergabung

Misalnya: - 'DI MANA'

SELECT * FROM employee WHERE employee_id=101

Sebagai Contoh: - 'ON'

Ada dua tabel pegawai dan rincian pegawai, kolom yang cocok adalah employee_id.

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

Semoga saya telah menjawab pertanyaan Anda. Kembalikan untuk klarifikasi apa pun.

Sharon Fernando
sumber
Tetapi Anda dapat menggunakan kata kunci WHEREsebagai pengganti ON, bukan? sqlfiddle.com/#!2/ae5b0/14/0
Qwerty
1

Saya pikir ini efek gabungan urutan. Dalam kasus bergabung kiri atas, SQL do Kiri bergabung dulu dan kemudian lakukan filter mana. Dalam kasus downer, cari Orders.ID = 12345 pertama, dan kemudian bergabung.

Xing-Wei Lin
sumber
1

Untuk join batin, WHEREdan ONbisa digunakan bergantian. Bahkan, dimungkinkan untuk digunakan ONdalam subquery yang dikorelasikan. Sebagai contoh:

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

Ini (IMHO) benar-benar membingungkan manusia, dan sangat mudah untuk lupa menautkan table1apa pun (karena tabel "driver" tidak memiliki klausul "on"), tetapi ini legal.

Austin Barry
sumber
1

untuk tabel kinerja yang lebih baik harus memiliki kolom diindeks khusus untuk digunakan untuk BERGABUNG.

jadi jika kolom yang Anda kondisikan bukan salah satu dari kolom yang diindeks maka saya curiga lebih baik menyimpannya di MANA.

jadi Anda BERGABUNG menggunakan kolom yang diindeks, kemudian setelah BERGABUNG Anda menjalankan kondisi pada kolom tidak diindeks.

yakoub abaya
sumber
1

Biasanya, pemfilteran diproses dalam klausa WHERE setelah kedua tabel sudah digabungkan. Mungkin saja Anda ingin memfilter satu atau kedua tabel sebelum bergabung. yaitu, di mana klausa berlaku untuk seluruh hasil yang ditetapkan sedangkan klausa on hanya berlaku untuk gabungan tersebut.

sree
sumber
Ini tidak begitu karena DBMS "normal" mengoptimalkan.
philipxy
1

Saya pikir perbedaan ini dapat dijelaskan melalui urutan operasi logis dalam SQL , yang disederhanakan:

  • FROM (termasuk gabungan)
  • WHERE
  • GROUP BY
  • Agregasi
  • HAVING
  • WINDOW
  • SELECT
  • DISTINCT
  • UNION, INTERSECT,EXCEPT
  • ORDER BY
  • OFFSET
  • FETCH

Bergabung bukan klausa pernyataan pilih, tetapi operator di dalamnya FROM. Dengan demikian, semua ONklausa yang dimiliki oleh JOINoperator terkait telah "terjadi" secara logis pada saat pemrosesan logis mencapai WHEREklausa. Ini berarti bahwa dalam kasus a LEFT JOIN, misalnya, semantik gabungan luar sudah bahagia pada saat WHEREklausa diterapkan.

Saya sudah menjelaskan contoh berikut ini secara lebih mendalam di posting blog ini . Saat menjalankan kueri ini:

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;

Itu LEFT JOINtidak benar-benar memiliki efek yang berguna, karena bahkan jika seorang aktor tidak bermain dalam film, aktor akan disaring, seperti yang FILM_IDakan terjadi NULLdan WHEREklausa akan menyaring baris seperti itu. Hasilnya adalah seperti:

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

Yaitu seolah-olah kita batin bergabung dengan dua tabel. Jika kami memindahkan predikat filter dalam ONklausa, itu sekarang menjadi kriteria untuk gabungan luar:

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;

Berarti hasilnya akan berisi aktor tanpa film apa pun, atau tanpa film apa pun 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

Pendeknya

Selalu menempatkan predikat Anda di tempat yang paling masuk akal, secara logis.

Lukas Eder
sumber
0

Mengenai pertanyaan Anda,

Ini sama baik 'di' atau 'di mana' pada bergabung dalam selama server Anda bisa mendapatkannya:

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

dan

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

Opsi 'di mana' tidak semua penafsir tahu jadi mungkin harus dihindari. Dan tentu saja klausa 'on' lebih jelas.

Ezequiel
sumber
-5

ini solusi saya.

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

Anda harus memiliki yang GROUP BYuntuk mendapatkannya untuk bekerja.

Semoga bantuan ini.

Le Quang Chien
sumber
10
Pengelompokan hanya pada songs.fullname sementara Anda juga memilih song_id dan singers.fullname akan menjadi masalah di sebagian besar basis data.
btilly