SQL THAM GIA - Mệnh đề WHERE so với mệnh đề ON


686

Sau khi đọc nó, đây không phải là một bản sao của Tham gia SQL ẩn và ẩn . Câu trả lời có thể liên quan (hoặc thậm chí giống nhau) nhưng câu hỏi thì khác.


Sự khác biệt và những gì nên đi trong mỗi?

Nếu tôi hiểu lý thuyết chính xác, trình tối ưu hóa truy vấn sẽ có thể sử dụng cả hai thay thế cho nhau.


2
Chỉ dành cho độc giả trong tương lai và thông tin của bạn, bạn nên đọc thứ tự thực hiện sql. Điều này sẽ giúp bạn chính xác hơn để hiểu sự khác biệt cơ bản.
Rahul Neekhra

Câu trả lời:


869

Chúng không giống nhau.

Hãy xem xét các truy vấn sau:

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

Đầu tiên sẽ trả về một đơn đặt hàng và các dòng của nó, nếu có, cho số thứ tự 12345. Thứ hai sẽ trả về tất cả các đơn đặt hàng, nhưng chỉ có đơn hàng 12345sẽ có bất kỳ dòng nào liên quan đến nó.

Với một INNER JOIN, các mệnh đề có hiệu quả tương đương. Tuy nhiên, chỉ vì chúng có chức năng giống nhau, ở chỗ chúng tạo ra kết quả giống nhau, không có nghĩa là hai loại mệnh đề có cùng ý nghĩa ngữ nghĩa.


83
bạn sẽ có được hiệu suất tốt hơn bằng cách đặt mệnh đề where trong mệnh đề "bật" cho phép nối bên trong chứ?
FistOfFury

96
@FistOfFury Sql Server sử dụng thủ tục tối ưu hóa truy vấn để biên dịch và đánh giá mã của bạn để tạo ra kế hoạch thực hiện tốt nhất có thể. Nó không hoàn hảo, nhưng hầu hết thời gian sẽ không thành vấn đề và bạn sẽ nhận được cùng một kế hoạch thực hiện.
Joel Coehoorn

18
Trong Postgres tôi lưu ý rằng chúng KHÔNG tương đương và dẫn đến các kế hoạch truy vấn khác nhau. Nếu bạn sử dụng BẬT, nó dẫn đến việc sử dụng vật chất hóa. Nếu bạn đã sử dụng WHERE, nó đã sử dụng hàm băm. Vật chất hóa có một trường hợp tồi tệ hơn gấp 10 lần so với hàm băm. Điều này đã sử dụng một bộ ID chứ không phải một ID duy nhất.
JamesHutchison

13
@JamesHutchison Thật khó để thực hiện khái quát hóa hiệu suất đáng tin cậy dựa trên các hành vi được quan sát như thế này. Điều gì là đúng một ngày có xu hướng sai trong ngày tiếp theo, bởi vì đây là một chi tiết thực hiện chứ không phải là hành vi được ghi lại. Các nhóm cơ sở dữ liệu luôn tìm kiếm các địa điểm để cải thiện hiệu suất tối ưu hóa. Tôi sẽ ngạc nhiên nếu hành vi BẬT không cải thiện để phù hợp với WHERE. Nó thậm chí có thể không hiển thị ở bất cứ đâu trong các ghi chú phát hành từ phiên bản này sang phiên bản khác ngoài "cải tiến hiệu suất chung.
Joel Coehoorn

4
@FiHoran Đó không phải là cách Sql Server hoạt động. Nó sẽ lọc trước một cách căng thẳng dựa trên các mục từ mệnh đề WHERE khi số liệu thống kê cho thấy nó có thể hữu ích.
Joel Coehoorn

362
  • Không quan trọng đối với tham gia bên trong
  • Các vấn đề cho tham gia bên ngoài

    a. WHEREmệnh đề: Sau tham gia. Hồ sơ sẽ được lọc sau khi tham gia đã diễn ra.

    b. ONmệnh đề - Trước khi tham gia. Bản ghi (từ bảng bên phải) sẽ được lọc trước khi tham gia. Điều này có thể kết thúc là null trong kết quả (kể từ khi tham gia OUTER).



Ví dụ : Xem xét các bảng dưới đây:

    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) WHEREMệnh đề bên trong :

  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) JOINMệnh đề bên trong

  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
IMO đây là câu trả lời tốt nhất vì nó cho thấy rõ ràng những gì đang diễn ra 'dưới mui xe' của các câu trả lời phổ biến khác.
psrpsrpsr

1
Giải thích tuyệt vời .... cũng được thực hiện! - Chỉ tò mò bạn đã làm gì để có được điều đó intermediate join table? Một số lệnh 'Giải thích'?
Manuel Jordan

1
@ManuelJordan Không, đây chỉ là để giải thích. Một cơ sở dữ liệu có thể làm một cái gì đó hiệu quả hơn là tạo một bảng trung gian.
Sandeep Jindal

Hiểu, tôi cho rằng có lẽ một công cụ thứ ba đã được sử dụng.
Manuel Jordan

145

Trên INNER JOINchúng có thể hoán đổi cho nhau và trình tối ưu hóa sẽ sắp xếp lại chúng theo ý muốn.

Trên OUTER JOINs, chúng không nhất thiết có thể thay thế cho nhau, tùy thuộc vào phía nào của sự tham gia mà chúng phụ thuộc.

Tôi đặt chúng ở một trong hai nơi tùy thuộc vào khả năng đọc.



Có lẽ nó rõ ràng hơn nhiều trong mệnh đề Where, đặc biệt là trong các biểu thức 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

Cách tôi làm là:

  • Luôn đặt các điều kiện tham gia trong ON mệnh đề nếu bạn đang làm INNER JOIN. Vì vậy, không thêm bất kỳ điều kiện WHERE nào vào mệnh đề ON, hãy đặt chúng vào WHEREmệnh đề.

  • Nếu bạn đang làm a LEFT JOIN, hãy thêm bất kỳ điều kiện WHERE nào vào ONmệnh đề cho bảng ở bên phải của phép nối. Đây là điều bắt buộc, bởi vì việc thêm mệnh đề WHERE tham chiếu phía bên phải của phép nối sẽ chuyển đổi phép nối thành INNER THAM GIA.

    Ngoại lệ là khi bạn đang tìm kiếm các bản ghi không có trong một bảng cụ thể. Bạn sẽ thêm tham chiếu vào một mã định danh duy nhất (chưa từng là NULL) trong bảng RIGHT THAM GIA vào mệnh đề WHERE theo cách này : WHERE t2.idfield IS NULL. Vì vậy, lần duy nhất bạn nên tham chiếu một bảng ở phía bên phải của phép nối là tìm những bản ghi không có trong bảng.


8
Đây là câu trả lời tốt nhất tôi đã đọc về điều này cho đến nay. Hoàn toàn có ý nghĩa một khi bộ não của bạn hiểu một liên kết bên trái sẽ trả về tất cả các hàng trong bảng bên trái và bạn phải lọc nó sau.
Nick Larsen

nếu bạn bên ngoài tham gia một bảng có cột rỗng, thì bạn vẫn có thể "ở đâu" cột đó là null mà không biến nó thành một phép nối bên trong? Đó không phải là chính xác tìm kiếm các bản ghi không chỉ trong một bảng cụ thể. Bạn có thể tìm kiếm 1. không tồn tại 2. không có giá trị nào cả.
Gần

Ý tôi là bạn có thể tìm cả hai: "1. không tồn tại 2. hoàn toàn không có giá trị". Và điều này áp dụng cho trường hợp trường đó không phải là idfield.
Gần

Như tôi đã gặp trường hợp này: tìm kiếm người tham gia bao gồm sinh viên năm nhất (dữ liệu chưa được nhập) mà không có liên hệ khẩn cấp.
Gần

30

Trong một tham gia bên trong, họ có nghĩa là điều tương tự. Tuy nhiên, bạn sẽ nhận được các kết quả khác nhau trong một phép nối ngoài tùy thuộc vào việc bạn đặt điều kiện nối trong mệnh đề WHERE so với ON. Hãy xem câu hỏi liên quan nàycâu trả lời này (của tôi).

Tôi nghĩ sẽ hợp lý nhất khi có thói quen luôn đặt điều kiện nối trong mệnh đề ON (trừ khi đó là phép nối ngoài và bạn thực sự muốn nó trong mệnh đề where) vì nó làm cho mọi người đọc truy vấn của bạn rõ ràng hơn những điều kiện nào các bảng đang được nối vào và nó cũng giúp ngăn mệnh đề WHERE dài hàng chục dòng.


26

Đây là một câu hỏi rất phổ biến, vì vậy câu trả lời này dựa trên bài viết này tôi đã viết.

Bảng mối quan hệ

Xét chúng ta có những điều sau đây postpost_commentbảng:

Các bảng <code> post </ code> và <code> post_comment </ code>

postcác hồ sơ sau đây:

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

post_commentcó ba hàng sau:

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

SQL tham gia

Mệnh đề SQL THAM GIA cho phép bạn liên kết các hàng thuộc về các bảng khác nhau. Chẳng hạn, CROSS THAM GIA sẽ tạo ra Sản phẩm Cartesian chứa tất cả các kết hợp hàng có thể có giữa hai bảng tham gia.

Mặc dù CROSS THAM GIA hữu ích trong một số trường hợp nhất định, nhưng hầu hết thời gian, bạn muốn tham gia các bảng dựa trên một điều kiện cụ thể. Và, đó là nơi INNER THAM GIA phát huy tác dụng.

SQL INNER THAM GIA cho phép chúng tôi lọc Sản phẩm của Cartesian khi nối hai bảng dựa trên một điều kiện được chỉ định thông qua mệnh đề ON.

SQL INNER THAM GIA - Điều kiện "luôn luôn đúng"

Nếu bạn cung cấp một điều kiện "luôn luôn đúng", INNER THAM GIA sẽ không lọc các bản ghi đã tham gia và tập kết quả sẽ chứa Sản phẩm Cartesian của hai bảng tham gia.

Chẳng hạn, nếu chúng ta thực hiện truy vấn SQL INNER THAM GIA sau đây:

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

Chúng tôi sẽ nhận được tất cả các kết hợp postpost_commenthồ sơ:

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

Vì vậy, nếu điều kiện mệnh đề ON là "luôn luôn đúng", INNER THAM GIA đơn giản tương đương với truy vấn CROSS THAM GIA:

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 THAM GIA - Điều kiện "luôn luôn sai"

Mặt khác, nếu điều kiện mệnh đề ON là "luôn luôn sai", thì tất cả các bản ghi đã tham gia sẽ được lọc ra và tập kết quả sẽ trống.

Vì vậy, nếu chúng tôi thực hiện truy vấn SQL INNER THAM GIA sau đây:

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

Chúng tôi sẽ không nhận được bất kỳ kết quả nào:

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

Đó là vì truy vấn trên tương đương với truy vấn CROSS THAM GIA sau:

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 THAM GIA - Mệnh đề ON sử dụng các cột Khóa ngoài và Khóa chính

Điều kiện mệnh đề ON phổ biến nhất là điều kiện khớp với cột Khóa ngoài trong bảng con với cột Khóa chính trong bảng cha, như được minh họa bằng truy vấn sau:

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

Khi thực hiện truy vấn SQL INNER THAM GIA ở trên, chúng ta sẽ nhận được tập kết quả sau:

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

Vì vậy, chỉ các bản ghi khớp với điều kiện mệnh đề ON mới được đưa vào tập kết quả truy vấn. Trong trường hợp của chúng tôi, tập kết quả chứa tất cả postcùng với post_commenthồ sơ của họ . Các posthàng không có liên kết post_commentđược loại trừ vì chúng không thể đáp ứng điều kiện ON ON.

Một lần nữa, truy vấn SQL INNER THAM GIA ở trên tương đương với truy vấn CROSS THAM GIA sau đây:

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

Các hàng không bị tấn công là những hàng thỏa mãn mệnh đề WHERE và chỉ những bản ghi này sẽ được đưa vào tập kết quả. Đó là cách tốt nhất để hình dung cách hoạt động của mệnh đề INNER THAM GIA.

| p.id | pc.post_id | pc.id | tiêu đề | pc.review |
| ------ | ------------ | ------- | ----------- | --------- - |
| 1 | 1 | 1 | Java | Tốt
| 1 | 1 | 2 | Java | Tuyệt vời |
| 1 | 2 | 3 | Java | Tuyệt vời | 
| 2 | 1 | 1 | Ngủ đông | Tốt 
| 2 | 1 | 2 | Ngủ đông | Tuyệt vời |
| 2 | 2 | 3 | Ngủ đông | Tuyệt vời |
| 3 | 1 | 1 | JPA | Tốt 
| 3 | 1 | 2 | JPA | Tuyệt vời | 
| 3 | 2 | 3 | JPA | Tuyệt vời |

Phần kết luận

Một câu lệnh INNER THAM GIA có thể được viết lại dưới dạng CROSS THAM GIA với mệnh đề WHERE khớp với cùng một điều kiện bạn đã sử dụng trong mệnh đề ON của truy vấn INNER THAM GIA.

Không phải điều này chỉ áp dụng cho INNER THAM GIA, không áp dụng cho OUTER THAM GIA.


11

Có sự khác biệt lớn giữa mệnh đề where so với mệnh đề trên , khi nói đến tham gia trái.

Đây là ví dụ:

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

Có fid là id của bảng 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)

Truy vấn về "mệnh đề":

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)

Truy vấn về "mệnh đề where":

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)

Rõ ràng là, truy vấn đầu tiên trả về một bản ghi từ t1 và hàng phụ thuộc của nó từ t2, nếu có, cho hàng t1.v = 'K'.

Truy vấn thứ hai trả về các hàng từ t1, nhưng chỉ với t1.v = 'K' sẽ có bất kỳ hàng liên quan nào với nó.


9

Về mặt tối ưu hóa, nó không nên tạo sự khác biệt cho dù bạn xác định mệnh đề tham gia của mình bằng BẬT hay Ở ĐÂU.

Tuy nhiên, IMHO, tôi nghĩ việc sử dụng mệnh đề BẬT khi thực hiện các phép nối sẽ rõ ràng hơn nhiều. Bằng cách đó, bạn có một phần cụ thể của truy vấn để xác định cách tham gia được xử lý so với xen kẽ với các mệnh đề WHERE còn lại.


7

Hãy xem xét các bảng:

Một

id | SomeData

B

id | id_A | SomeOtherData

id_A là một chìa khóa nước ngoài để bàn A

Viết truy vấn này:

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

Sẽ cung cấp kết quả này:

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

Những gì trong A nhưng không có trong B có nghĩa là có giá trị null cho B.


Bây giờ, hãy xem xét một phần cụ thể trong B.id_Avà làm nổi bật nó từ kết quả trước đó:

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

Viết truy vấn này:

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

Sẽ cung cấp kết quả này:

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

Bởi vì điều này loại bỏ trong tham gia bên trong các giá trị không có trong B.id_A = SpecificPart


Bây giờ, hãy thay đổi truy vấn này:

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

Kết quả là ngay bây giờ:

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

Bởi vì toàn bộ kết quả được lọc chống lại B.id_A = SpecificPartviệc loại bỏ các phần B.id_A = NULL, nằm trong A không có trong B


4

Bạn đang cố gắng tham gia dữ liệu hoặc lọc dữ liệu?

Để dễ đọc, cách ly các trường hợp sử dụng này thành BẬT và WHERE tương ứng là hợp lý nhất.

  • tham gia dữ liệu trong ON
  • lọc dữ liệu trong WHERE

Có thể rất khó để đọc một truy vấn trong đó điều kiện THAM GIA và điều kiện lọc tồn tại trong mệnh đề WHERE.

Hiệu suất khôn ngoan, bạn không nên thấy sự khác biệt, mặc dù các loại SQL khác nhau đôi khi xử lý lập kế hoạch truy vấn khác nhau để có thể đáng để thử ¯\_(ツ)_/¯ (Hãy lưu ý đến bộ đệm ẩn ảnh hưởng đến tốc độ truy vấn)

Ngoài ra, như những người khác đã lưu ý, nếu bạn sử dụng phép nối ngoài, bạn sẽ nhận được các kết quả khác nhau nếu bạn đặt điều kiện lọc trong mệnh đề ON vì nó chỉ ảnh hưởng đến một trong các bảng.

Tôi đã viết một bài viết sâu hơn về điều này ở đây: https://dataschool.com/learn/difference-b between-where-and-on-in-sql


2

Trong SQL, mệnh đề 'WHERE' và 'ON', là loại Stitterant có điều kiện, nhưng điểm khác biệt chính giữa chúng là, khoản 'Where' được sử dụng trong Chọn / Cập nhật Báo cáo để chỉ định Điều kiện, trong khi Điều khoản 'ON' được sử dụng trong Joins, nơi nó xác minh hoặc kiểm tra nếu Bản ghi được khớp trong bảng mục tiêu và nguồn, trước khi các Bảng được tham gia

Ví dụ: - 'Ở ĐÂU'

SELECT * FROM employee WHERE employee_id=101

Ví dụ: - 'BẬT'

Có hai bảng worker và worker_details, các cột khớp nhau là worker_id.

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

Hy vọng tôi đã trả lời câu hỏi của bạn. Hoàn nguyên cho bất kỳ làm rõ.


Nhưng bạn có thể sử dụng từ khóa WHEREthay cho ON, phải không? sqlfiddle.com/#!2/ae5b0/14/0
Qwerty

1

Tôi nghĩ đó là hiệu ứng chuỗi tham gia. Trong trường hợp tham gia phía trên bên trái, SQL thực hiện Tham gia trái trước và sau đó thực hiện bộ lọc. Trong trường hợp downer, trước tiên hãy tìm Đơn hàng.ID = 12345 và sau đó tham gia.


1

Đối với một tham gia bên trong, WHEREONcó thể được sử dụng thay thế cho nhau. Trong thực tế, nó có thể được sử dụng ONtrong một truy vấn con tương quan. Ví dụ:

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

Đây là (IMHO) hoàn toàn khó hiểu với con người và rất dễ quên liên kết table1với bất cứ điều gì (vì bảng "trình điều khiển" không có mệnh đề "bật"), nhưng nó hợp pháp.


1

để các bảng hiệu suất tốt hơn nên có một cột được lập chỉ mục đặc biệt để sử dụng cho THAM GIA.

Vì vậy, nếu cột bạn điều kiện không phải là một trong những cột được lập chỉ mục thì tôi nghi ngờ tốt hơn là giữ nó ở ĐÂU.

vì vậy, bạn THAM GIA bằng cách sử dụng các cột được lập chỉ mục, sau đó sau khi THAM GIA bạn chạy điều kiện trên cột không được lập chỉ mục.


1

Thông thường, lọc được xử lý trong mệnh đề WHERE sau khi hai bảng đã được nối. Mặc dù có thể bạn muốn lọc một hoặc cả hai bảng trước khi nối chúng. tức là mệnh đề where áp dụng cho toàn bộ tập kết quả trong khi mệnh đề on chỉ áp dụng cho phép nối trong câu hỏi.


Điều này chỉ không đúng vì DBMS "bình thường" tối ưu hóa.
philipxy

1

Tôi nghĩ rằng sự khác biệt này có thể được giải thích tốt nhất thông qua thứ tự logic của các hoạt động trong SQL , được đơn giản hóa:

  • FROM (bao gồm cả tham gia)
  • WHERE
  • GROUP BY
  • Tập hợp
  • HAVING
  • WINDOW
  • SELECT
  • DISTINCT
  • UNION, INTERSECT,EXCEPT
  • ORDER BY
  • OFFSET
  • FETCH

Tham gia không phải là một mệnh đề của câu lệnh chọn, mà là một toán tử bên trong FROM. Như vậy, tất cả ONcác mệnh đề thuộc về JOINtoán tử tương ứng đã "đã xảy ra" một cách hợp lý bởi thời gian xử lý logic đạt đến WHEREmệnh đề. Điều này có nghĩa là trong trường hợp a LEFT JOIN, ví dụ, ngữ nghĩa của phép nối ngoài đã xảy ra vào thời điểmWHERE mệnh đề được áp dụng.

Tôi đã giải thích ví dụ sau sâu hơn trong bài viết trên blog này . Khi chạy truy vấn này:

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;

Điều LEFT JOINnày thực sự không có tác dụng hữu ích nào, bởi vì ngay cả khi một diễn viên không đóng trong phim, diễn viên sẽ được lọc, vì nó FILM_IDsẽ như vậy NULLWHEREmệnh đề sẽ lọc một hàng như vậy. Kết quả là một cái gì đó như:

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

Tức là như thể chúng ta bên trong đã tham gia hai bảng. Nếu chúng ta di chuyển vị từ bộ lọc trong ONmệnh đề, thì bây giờ nó trở thành một tiêu chí cho phép nối ngoài:

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;

Có nghĩa là kết quả sẽ chứa các diễn viên mà không có bất kỳ bộ phim nào, hoặc không có bất kỳ bộ phim nào với 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

Nói ngắn gọn

Luôn đặt vị ngữ của bạn ở nơi nó có ý nghĩa nhất, hợp lý.


0

Liên quan đến câu hỏi của bạn,

Nó giống nhau cả 'trên' hoặc 'trong đó' khi tham gia bên trong miễn là máy chủ của bạn có thể nhận được:

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

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

Tùy chọn 'where' không phải tất cả các thông dịch viên đều biết nên có lẽ nên tránh. Và tất nhiên, mệnh đề 'trên' rõ ràng hơn.


-5

đây là giải pháp của tôi

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

Bạn phải có cácGROUP BY để làm cho nó làm việc.

Hy vọng điều này giúp đỡ.


10
Nhóm chỉ các bài hát.fullname trong khi bạn cũng đang chọn song_id và singers.fullname sẽ là một vấn đề trong hầu hết các cơ sở dữ liệu.
btilly
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.