2008-10-09 30 views
16

Tại sao thứ tự các bảng quan trọng khi kết hợp một bên ngoài & một tham gia bên trong? sau thất bại với postgres:Tham gia nội bộ & tham gia bên ngoài; thứ tự các bảng từ quan trọng là gì?

SELECT grp.number AS number,  
     tags.value AS tag 
FROM groups grp, 
    insrel archiverel 
LEFT OUTER JOIN ownrel ownrel ON grp.number = ownrel.dnumber 
LEFT OUTER JOIN tags tags ON tags.number = ownrel.snumber 
WHERE archiverel.snumber = 11128188 AND  
     archiverel.dnumber = grp.number 

với kết quả:

ERROR: invalid reference to FROM-clause entry for table "grp" LINE 5: LEFT OUTER JOIN ownrel ownrel ON grp.number = ownrel.d... 
^ HINT: There is an entry for table "grp", but it cannot be referenced from this part of the query. 

khi nhóm này được đảo ngược trong tất cả các TỪ nó hoạt động:

SELECT grp.number AS number,  
     tags.value AS tag 
FROM insrel archiverel, 
     groups grp 
LEFT OUTER JOIN ownrel ownrel ON grp.number = ownrel.dnumber 
LEFT OUTER JOIN tags tags ON tags.number = ownrel.snumber 
WHERE archiverel.snumber = 11128188 AND  
     archiverel.dnumber = grp.number 
+0

Đó là rất thú vị. Nó phải có một cái gì đó để làm với trộn công ước. Tôi hơi ngạc nhiên khi phiên bản thứ hai còn hoạt động! –

Trả lời

20

Tôi tin rằng bạn có thể nghĩ về điều này một vấn đề ưu tiên vận hành.

Khi bạn viết này:

FROM groups grp, 
    insrel archiverel 
LEFT OUTER JOIN ownrel ownrel ON grp.number = ownrel.dnumber 
LEFT OUTER JOIN tags tags ON tags.number = ownrel.snumber 

Tôi nghĩ rằng nó được giải thích bởi các cú pháp như thế này:

FROM groups grp, 
(
    (
    insrel archiverel 
    LEFT OUTER JOIN ownrel ownrel ON grp.number = ownrel.dnumber 
) 
LEFT OUTER JOIN tags tags ON tags.number = ownrel.snumber 
) 

Nếu vậy, thì trong thâm tâm tham gia "grp" là không ràng buộc.

Khi bạn đảo ngược các dòng có "nhóm" và "không liên quan", kết nối bên trong nhất sẽ áp dụng cho "nhóm" và "ownrel", vì vậy nó hoạt động.

Có lẽ điều này sẽ làm việc cũng như:

FROM groups grp 
     JOIN insrel archiverel ON archiverel.dnumber = grp.number 
    LEFT OUTER JOIN ownrel ownrel ON grp.number = ownrel.dnumber 
    LEFT OUTER JOIN tags tags ON tags.number = ownrel.snumber 
WHERE archiverel.snumber = 11128188 
+0

Bạn nói đúng, bằng cách sử dụng một tham gia chứ không phải trên insrel thực sự hoạt động và trông hợp lý hơn là tốt –

5

Bởi vì trong một grp đầu tiên là không phải là một phần của việc tham gia mệnh đề ON thuộc về.

+0

Đây là nhận xét duy nhất có ý nghĩa đối với tôi và nó đã sửa lỗi truy vấn của tôi. Tôi đã di chuyển một bảng trong mệnh đề FROM của tôi thành mệnh đề cuối cùng trong mệnh đề FROM và nó đã sửa lỗi. –

4

Tôi không biết điều gì đang gây ra hành vi đó, nếu đó là lỗi hoặc theo thiết kế, nhưng nó sẽ hoạt động tốt nếu bạn gắn bó với một hình thức tham gia này hoặc hình thức khác.

SELECT grp.number AS number,  
     tags.value AS tag 
FROM groups grp 
JOIN insrel archiverel ON archiverel.dnumber = grp.number 
LEFT OUTER JOIN ownrel ownrel ON grp.number = ownrel.dnumber 
LEFT OUTER JOIN tags tags ON tags.number = ownrel.snumber 
WHERE archiverel.snumber = 11128188 

Tôi muốn biết nhiều hơn nếu hành vi là do thiết kế.

2

Để tham gia bên trong, thứ tự của các bảng không quan trọng.

Để tham gia bên ngoài, chính là. Tất cả các hàng từ bảng bên cạnh được chỉ định (có phải là một LEFT hoặc RIGHT join) sẽ được bao gồm, trong khi chỉ các hàng phù hợp với tiêu chí tham gia sẽ được bao gồm từ bảng ở phía bên kia.

Vì OUTER JOINS giữ tất cả các hàng từ một phía, chúng được nói đến (nói chung) tăng các tập kết quả. INNER JOINS chỉ giữ các hàng từ cả hai phía nếu chúng khớp nhau, vì vậy chúng được nói (nói chung) để giảm các tập kết quả. Vì vậy, bạn thường muốn làm INNER JOINS của bạn trước OUTER JOINS (khi có thể).

Trong trường hợp của bạn, nó gần như chắc chắn là kết quả của cú pháp A, B ác.

+0

đúng nhưng không phải thứ tự của các kết nối gây ra sự cố nhưng thứ tự trong mệnh đề từ –

+0

@Thủ tục: WTFalse. Thứ tự của các phép nối được quy định trong mệnh đề from, do đó, "thứ tự các phép nối" thực sự là "thứ tự của các phép nối trong mệnh đề từ", và rằng * là * vấn đề, bởi vì thứ tự quan trọng. Nếu bạn làm các phép nối ngoài trước khi các phép nối bên trong, các kết nối bên trong sẽ giảm tập kết quả mà bạn đã cố gắng duy trì với phép nối ngoài; do đó bạn nên thực hiện việc kết hợp (bên ngoài) bao gồm sau khi tham gia bên trong (độc quyền); nếu không thì các kết nối bên ngoài là vô nghĩa. – Triynko

18

Tôi không nghĩ rằng bất kỳ ai đã đóng đinh điều này, hoặc giải thích rất rõ. Bạn đang kết hợp các kiểu 'kiểu cũ' (theta) và 'kiểu mới' (ANSI), mà tôi nghi ngờ mạnh mẽ đang được nhóm theo cách bạn không mong đợi. Nhìn vào nó theo cách này:

SELECT * FROM a, b JOIN c ON a.x = c.x 

cũng giống như nói

SELECT * FROM a, (b JOIN c on a.x = c.x) 

nơi điều ngoặc vuông đại diện cho một loạt các bảng sáp nhập vào một bảng ảo, để được tham gia vào với một theta-tham gia chống lại 'a'. Rõ ràng là bảng 'a' không thể là một phần của sự tham gia vì nó chỉ được nối vào sau. Đảo ngược nó và bạn đang thực hiện

SELECT * FROM b, (a JOIN c on a.x = c.x) 

hoàn toàn dễ hiểu và tốt. Tôi không chắc chắn lý do tại sao bạn không sử dụng cú pháp tham gia ANSI cho tất cả, mặc dù có vẻ hơi lạ (và độc ác đối với người phải duy trì nó!)

+0

Điều đó phải là những gì đang xảy ra. Tôi nghi ngờ việc thực hiện không mong đợi mọi người kết hợp cú pháp, và ngay cả khi họ đã làm không có tiêu chuẩn xác định hành vi của cú pháp hỗn hợp. –

+0

có pha trộn chúng là một thói quen cũ thực sự lộn xộn lên logic. –

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