2015-12-24 18 views
18

Trong SQL Tôi cố gắng để lọc kết quả dựa trên một ID và tự hỏi nếu có bất kỳ sự khác biệt logic giữaSự khác nhau giữa các truy vấn lọc trong JOIN và WHERE?

SELECT value 
FROM table1 
JOIN table2 ON table1.id = table2.id 
WHERE table1.id = 1 

SELECT value 
FROM table1 
JOIN table2 ON table1.id = table2.id AND table1.id = 1 

Đối với tôi, nó có vẻ như nếu logic là khác nhau mặc dù bạn sẽ luôn nhận được cùng một tập hợp kết quả nhưng tôi tự hỏi liệu có bất kỳ điều kiện nào mà bạn sẽ nhận được hai tập hợp kết quả khác nhau hay không. Chúng tôi luôn trả về hai tập hợp kết quả giống nhau)

+3

Đơn giản ** KHÔNG ** khác biệt –

+7

Thử tham gia trái, sau đó bạn sẽ bắt đầu thấy sự khác biệt. – sstan

+2

Bạn đã thử một showplan để xem đường dẫn được thực hiện cho cả hai? – scrappedcola

Trả lời

28

Câu trả lời là NO sự khác biệt, nhưng:

Tôi sẽ luôn luôn thích làm như sau.

  • Luôn giữ Tham Điều kiện trong ON khoản
  • Luôn đặt lọc của trong where khoản

Điều này làm cho các truy vấn hơn có thể đọc được.

Vì vậy, tôi sẽ sử dụng truy vấn này:

SELECT value 
FROM table1 
INNER JOIN table2 
     ON table1.id = table2.id 
WHERE table1.id = 1 

Tuy nhiên khi bạn đang sử dụng OUTER JOIN'S có một sự khác biệt lớn trong việc giữ bộ lọc vào ON điều kiện và điều kiện Where.

logic xử lý truy vấn

Danh sách sau đây có chứa một dạng tổng quát của một truy vấn, cùng với số bước phân công theo thứ tự mà các điều khoản khác nhau được một cách logic xử lý.

(5) SELECT (5-2) DISTINCT (5-3) TOP(<top_specification>) (5-1) <select_list> 
(1) FROM (1-J) <left_table> <join_type> JOIN <right_table> ON <on_predicate> 
| (1-A) <left_table> <apply_type> APPLY <right_table_expression> AS <alias> 
| (1-P) <left_table> PIVOT(<pivot_specification>) AS <alias> 
| (1-U) <left_table> UNPIVOT(<unpivot_specification>) AS <alias> 
(2) WHERE <where_predicate> 
(3) GROUP BY <group_by_specification> 
(4) HAVING <having_predicate> 
(6) ORDER BY <order_by_list>; 

luồng xử lý sơ đồ truy vấn logic

Enter image description here

  • (1) TỪ: Các TỪ giai đoạn xác định bảng mã nguồn của truy vấn và khai thác quá trình bàn. Mỗi toán tử bảng áp dụng một loạt các giai đoạn phụ là . Ví dụ, các giai đoạn tham gia vào một tham gia là (1-J1) sản phẩm Descartes, (1-J2) ON Filter, (1-J3) Thêm hàng bên ngoài. Giai đoạn FROM tạo ra bảng ảo VT1.

  • (1-J1) Sản phẩm Descartes: Giai đoạn này thực hiện sản phẩm Cartesian (nối chéo) giữa hai bảng liên quan đến toán tử bảng, tạo VT1-J1.

  • (1-J2) ON Lọc: lọc Giai đoạn này các hàng từ VT1-J1 dựa trên vị xuất hiện trong mệnh đề ON (< on_predicate>).Chỉ có hàng mà biến vị ngữ ước tính thành TRUE được chèn vào VT1-J2.
  • (1-J3) Thêm Hàng Outer: Nếu OUTER JOIN được quy định (như trái ngược với CROSS JOIN hoặc INNER JOIN), các hàng từ bảng bảo quản hoặc bảng mà một trận đấu không được tìm thấy được thêm vào các hàng từ VT1-J2 là các hàng bên ngoài, tạo VT1-J3.
  • (2) WHERE: Giai đoạn này lọc các hàng từ VT1 dựa trên vị từ xuất hiện trong mệnh đề WHERE(). Chỉ có hàng mà vị từ ước tính đến TRUE được chèn vào VT2.
  • (3) GROUP BY: Giai đoạn này sắp xếp các hàng từ VT2 theo nhóm dựa trên trên danh sách cột được chỉ định trong mệnh đề GROUP BY, tạo VT3. Cuối cùng, sẽ có một hàng kết quả cho mỗi nhóm.
  • (4) ĐANG: Giai đoạn này lọc các nhóm từ VT3 dựa trên vị từ xuất hiện trong mệnh đề HAVING (< having_predicate>). Chỉ các nhóm mà vị từ ước tính TRUE được chèn vào VT4.
  • (5) CHỌN: Giai đoạn này xử lý các phần tử trong mệnh đề SELECT, tạo VT5.
  • (5-1) Đánh giá biểu thức: Giai đoạn này đánh giá các biểu thức trong danh sách SELECT, tạo VT5-1.
  • (5-2) DISTINCT: Giai đoạn này loại bỏ các hàng trùng lặp từ VT5-1, tạo VT5-2.
  • (5-3) TOP: Giai đoạn này lọc số đầu hoặc phần trăm được chỉ định hàng từ VT5-2 dựa trên thứ tự logic được xác định theo mệnh đề ORDER BY, tạo bảng VT5-3.
  • (6) ORDER BY: Giai đoạn này sắp xếp các hàng từ VT5-3 theo danh sách cột được chỉ định trong mệnh đề ORDER BY, tạo ra con trỏ VC6.

Nó được gọi từ this excellent link.

+2

Tương tự và đồng ý! Ngoài ra, hãy _specific_ với các kết nối của bạn. I E. sử dụng 'INNER' hoặc' LEFT-or-RIGHT OUTER' khi định nghĩa một phép nối, IMO. –

+2

Trong khi tôi đồng ý với câu hỏi CỤ THỂ này. Tham gia OUTER có một sự khác biệt lớn ở nơi giới hạn tiêu chí được đặt khi tiêu chí nằm trong tập hợp bản ghi phù hợp giới hạn. Bộ lọc có thể đi theo mệnh đề on và phải trong một số trường hợp khi sử dụng các phép nối ngoài để đạt được kết quả mong muốn.hoặc bạn kết thúc với mệnh đề (không giống như Santa Claus) như ở đâu '(val = 'blue' hoặc val là null)' cũng có thể tạo ra kết quả không chính xác vào những thời điểm đặc biệt nếu NULL có ý nghĩa cụ thể ngoài việc tạo ra trong join. – xQbert

+3

Trong khi về chủ đề ** khả năng đọc **: Tôi cũng khuyên bạn nên ** nhất quán ** với từ khóa của bạn - hoặc đặt tất cả trong UPPERCASE, hoặc tất cả trong chữ thường, hoặc tất cả trong một trường hợp hỗn hợp - I don ' t quan tâm - nhưng chỉ được ** ƯU ĐÃI ** - không sử dụng một kiểu ('SELECT',' FROM') được trộn lẫn với kiểu thứ hai ('on',' where') trong cùng một truy vấn ... ... làm cho nó ** thực sự ** khó đọc mã T-SQL .... Chọn một kiểu - tùy theo bạn thích - nhưng sau đó ** STICK ** cho nó và nhất quán –

9

Trong khi không có sự khác biệt khi sử dụng INNER NỐI, như VR46 chỉ ra, có một sự khác biệt đáng kể khi sử dụng outer joins và đánh giá một giá trị trong bảng thứ hai (đối với trái tham gia - Bàn đầu tiên cho quyền tham gia). Hãy xem xét các thiết lập sau:

DECLARE @Table1 TABLE ([ID] int) 
DECLARE @Table2 TABLE ([Table1ID] int, [Value] varchar(50)) 

INSERT INTO @Table1 
VALUES 
(1), 
(2), 
(3) 

INSERT INTO @Table2 
VALUES 
(1, 'test'), 
(1, 'hello'), 
(2, 'goodbye') 

Nếu chúng ta chọn từ nó sử dụng một trái bên ngoài tham gia và đặt một điều kiện trong mệnh đề where:

SELECT * FROM @Table1 T1 
LEFT OUTER JOIN @Table2 T2 
    ON T1.ID = T2.Table1ID 
WHERE T2.Table1ID = 1 

Chúng tôi nhận được kết quả như sau:

ID   Table1ID Value 
----------- ----------- -------------------------------------------------- 
1   1   test 
1   1   hello 

Điều này là do mệnh đề where giới hạn tập hợp kết quả, vì vậy chúng tôi chỉ bao gồm các bản ghi từ bảng 1 có ID là 1.Tuy nhiên, nếu chúng ta di chuyển điều kiện để về khoản:

SELECT * FROM @Table1 T1 
LEFT OUTER JOIN @Table2 T2 
    ON T1.ID = T2.Table1ID 
    AND T2.Table1ID = 1 

Chúng tôi nhận được kết quả như sau:

ID   Table1ID Value 
----------- ----------- -------------------------------------------------- 
1   1   test 
1   1   hello 
2   NULL  NULL 
3   NULL  NULL 

Điều này là do chúng ta không còn lọc các kết quả thiết lập bởi ID của table1 trong tổng số 1 - đúng hơn là chúng ta đang lọc JOIN. Vì vậy, mặc dù ID table1 của 2 DOES có một kết quả phù hợp trong bảng thứ hai, nó bị loại trừ khỏi phép nối - nhưng không phải là tập kết quả (do đó các giá trị null).

Vì vậy, để tham gia vào bên trong nó không quan trọng, nhưng bạn nên giữ nó trong mệnh đề where để dễ đọc và nhất quán. Tuy nhiên, đối với các kết nối bên ngoài, bạn cần lưu ý rằng nó KHÔNG quan trọng khi bạn đặt điều kiện vì nó sẽ tác động đến tập kết quả của bạn.

+1

cảm ơn ví dụ rất được giải thích này. – cdabel

3

Tôi nghĩ câu trả lời được đánh dấu là "đúng" không đúng. Tại sao? Tôi cố gắng giải thích:

Chúng tôi có ý kiến ​​

"Luôn luôn giữ Tham điều kiện tại khoản ON Luôn đặt của lọc trong mệnh đề where"

Và điều này là sai. Nếu bạn đang ở bên trong tham gia, mỗi lần đặt params lọc trong mệnh đề ON, không phải ở đâu. Bạn hỏi tại sao? Hãy thử tưởng tượng truy vấn phức tạp với tổng cộng 10 bảng (ví dụ: mỗi bảng có 10k recs) tham gia, với mệnh đề WHERE phức tạp (ví dụ, hàm hoặc tính toán được sử dụng). Nếu bạn đặt tiêu chí lọc trong mệnh đề ON, JOINS giữa 10 bảng này không xảy ra, mệnh đề WHERE sẽ không được thực thi chút nào. Trong trường hợp này, bạn không thực hiện 10000^10 phép tính trong mệnh đề WHERE. Điều này có ý nghĩa, không đặt các tham số lọc trong mệnh đề WHERE.

Các vấn đề liên quan