Vị trí của mệnh đề ON thực sự có nghĩa là gì?


23

JOIN ... ON ...Cú pháp bình thường là nổi tiếng. Nhưng cũng có thể định vị ONmệnh đề riêng biệt với mệnh đề JOINtương ứng. Đây là một điều hiếm khi được nhìn thấy trong thực tế, không được tìm thấy trong các hướng dẫn và tôi đã không tìm thấy bất kỳ tài nguyên web nào thậm chí đề cập rằng điều này là có thể.

Đây là một kịch bản để chơi xung quanh:

SELECT *
INTO #widgets1
FROM (VALUES (1), (2), (3)) x(WidgetID)


SELECT *
INTO #widgets2
FROM (VALUES (1, 'SomeValue1'), (2, 'SomeValue2'), (3, 'SomeValue3')) x(WidgetID, SomeValue)

SELECT *
INTO #widgetProperties
FROM (VALUES
    (1, 'a'), (1, 'b'),
    (2, 'a'), (2, 'b'))
x(WidgetID, PropertyName)


--q1
SELECT w1.WidgetID, w2.SomeValue, wp.PropertyName
FROM #widgets1 w1
LEFT JOIN #widgets2 w2 ON w2.WidgetID = w1.WidgetID
LEFT JOIN #widgetProperties wp ON w2.WidgetID = wp.WidgetID AND wp.PropertyName = 'b'
ORDER BY w1.WidgetID


--q2
SELECT w1.WidgetID, w2.SomeValue, wp.PropertyName
FROM #widgets1 w1
LEFT JOIN #widgets2 w2 --no ON clause here
JOIN #widgetProperties wp
 ON w2.WidgetID = wp.WidgetID AND wp.PropertyName = 'b'
 ON w2.WidgetID = w1.WidgetID
ORDER BY w1.WidgetID


--q3
SELECT w1.WidgetID, w2.SomeValue, wp.PropertyName
FROM #widgets1 w1
LEFT JOIN (
    #widgets2 w2 --no SELECT or FROM here
    JOIN #widgetProperties wp
    ON w2.WidgetID = wp.WidgetID AND wp.PropertyName = 'b')
ON w2.WidgetID = w1.WidgetID
ORDER BY w1.WidgetID

q1 trông bình thường. q2 và q3 có các vị trí bất thường của ONmệnh đề.

Kịch bản này không nhất thiết có nhiều ý nghĩa. Thật khó cho tôi để có được một kịch bản có ý nghĩa.

Vậy những mẫu cú pháp bất thường này có ý nghĩa gì? Điều này được định nghĩa như thế nào? Tôi nhận thấy rằng không phải tất cả các vị trí và thứ tự cho hai ONmệnh đề đều được cho phép. Các quy tắc quản lý này là gì?

Ngoài ra có bao giờ là một ý tưởng tốt để viết các truy vấn như thế này?

Câu trả lời:


32

Nếu bạn nhìn vào FROMsơ đồ cú pháp mệnh đề, bạn sẽ thấy rằng chỉ có một vị trí cho ONmệnh đề:

<joined_table> ::= 
{
    <table_source> <join_type> <table_source> ON <search_condition> 
    ...
}

Điều bạn thấy khó hiểu là đệ quy đơn giản, vì <table_source>trong <joined_table> ở trên có thể là một thứ khác <joined_table>:

[ FROM { <table_source> } [ ,...n ] ] 
<table_source> ::= 
{
    table_or_view_name ... 
    ...
    | <joined_table> 
    ...
}

Để tránh nhầm lẫn, bạn nên sử dụng dấu ngoặc đơn trong các trường hợp không rõ ràng (như ví dụ của bạn) để phân tách trực quan <table_sources>; chúng không cần thiết cho trình phân tích cú pháp truy vấn nhưng hữu ích cho con người.


33

Nó xác định các bảng logic liên quan đến việc tham gia.

Với một ví dụ đơn giản

SELECT w1.WidgetID,
       w2.SomeValue,
       wp.PropertyName
FROM   #widgets1 w1
       LEFT JOIN #widgets2 w2
         ON w2.WidgetID = w1.WidgetID
       JOIN #widgetProperties wp
         ON w2.WidgetID = wp.WidgetID
            AND wp.PropertyName = 'b'
ORDER  BY w1.WidgetID 

#widgets1được kết nối bên ngoài bên ngoài #widgets2- kết quả của việc tạo thành một bảng ảo được nối bên trong #widgetProperties. Vị ngữ w2.WidgetID = wp.WidgetIDsẽ có nghĩa là bất kỳ hàng mở rộng null nào từ phép nối ngoài ban đầu được lọc ra, thực hiện tất cả các phép nối bên trong.

Điều này khác với q2 ...

SELECT w1.WidgetID,
       w2.SomeValue,
       wp.PropertyName
FROM   #widgets1 w1
       LEFT JOIN #widgets2 w2 --no ON clause here
                 JOIN #widgetProperties wp
                   ON w2.WidgetID = wp.WidgetID
                      AND wp.PropertyName = 'b'
         ON w2.WidgetID = w1.WidgetID
ORDER  BY w1.WidgetID

#widgets2là bên trong tham gia vào #widgetProperties. Bảng ảo kết quả từ phép nối đó sau đó là bảng bên phải trong Kết nối bên ngoài bên trái#widgets1

Kết quả tương tự có thể đạt được bằng cách sử dụng bảng dẫn xuất hoặc Biểu thức bảng chung ...

WITH VT2
     AS (SELECT w2.WidgetID,
                w2.SomeValue,
                wp.PropertyName
         FROM   #widgets2 w2 
                JOIN #widgetProperties wp
                  ON w2.WidgetID = wp.WidgetID
                     AND wp.PropertyName = 'b')
SELECT w1.WidgetID,
       VT2.SomeValue,
       VT2.PropertyName
FROM   #widgets1 w1
       LEFT JOIN VT2
         ON VT2.WidgetID = w1.WidgetID
ORDER  BY w1.WidgetID 

... Hoặc thay vào đó, bạn có thể đặt lại các bảng ảo và sử dụng RIGHT JOINthay thế.

SELECT w1.WidgetID,
       w2.SomeValue,
       wp.PropertyName
FROM   #widgets2 w2
       INNER JOIN #widgetProperties wp
               ON w2.WidgetID = wp.WidgetID
                  AND wp.PropertyName = 'b'
       RIGHT JOIN #widgets1 w1
               ON w2.WidgetID = w1.WidgetID
ORDER  BY w1.WidgetID 

Điều này được bao phủ bởi Itzik Ben Gan ở đây

... các điều kiện THAM GIA phải tuân theo mối quan hệ chiastic với thứ tự bảng. Nghĩa là, nếu bạn chỉ định các bảng T1, T2, T3 và T4 theo thứ tự đó và các điều kiện THAM GIA khớp với T1, T2 với T3 và T3 với T4, bạn phải chỉ định các điều kiện THAM GIA theo thứ tự ngược với thứ tự bảng , như thế này:

FROM   T1
       <join_type> T2 T2
                  <join_type> T3 T3
                             <join_type> T4
                               ON T4.key = T3.key
                    ON T3.key = T2.key
         ON T2.key = T1.key 

Để xem xét kỹ thuật nối này theo một cách khác, một điều kiện THAM GIA đã cho chỉ có thể tham chiếu đến các tên bảng ngay phía trên nó hoặc các tên bảng mà các điều kiện THAM GIA trước đó đã được đề cập và giải quyết.

nhưng bài báo có một số điểm không chính xác, hãy xem thư theo dõi của Lubor Kollar .


Cảm ơn Martin, câu trả lời này rất hữu ích. Mặc dù vậy, tôi sẽ chấp nhận một điều khác, bởi vì quan điểm của ông về ngữ pháp chính thức là điều giúp tôi hiểu đầy đủ về vấn đề này. Cụ thể, "mối quan hệ chiastic" dường như là một ý tưởng sai lầm. Nó là một cái cây, không phải là một danh sách cộng với một danh sách đảo ngược. mustaccio cung cấp khuôn khổ để hiểu tại sao giải thích Itziks không hoàn toàn đúng.
boot4life
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.