17

为什么在结合外部和内部联接时表的顺序很重要?以下使用 postgres 失败:

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 

结果:

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.

当组在 FROM 中反转时,一切正常:

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 
4

5 回答 5

20

我相信您可以将其视为运算符优先级问题。

当你写这个:

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   

我认为解析器是这样解释的:

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
)

如果是这样,那么在最里面的连接中“grp”是未绑定的。

当你用“groups”和“insrel”反转行时,最里面的连接适用于“groups”和“ownrel”,所以它可以工作。

可能这也会起作用:

    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
于 2008-10-09T13:39:29.107 回答
19

我认为没有人非常清楚这一点,或者解释得很好。您正在组合“旧样式”(theta)和“新样式”(ANSI)连接,我强烈怀疑它们是以您意想不到的方式分组的。这样看:

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

就像说

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

其中括号中的东西表示一堆合并到一个虚拟表中的表,以针对“a”的 theta-join 进行连接。显然,“a”表不能成为连接的一部分,因为它只是稍后才加入。反转它,你正在做

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

这是完全可以理解的,很好。我不确定你为什么不使用 ANSI join 语法来处理它,这似乎有点奇怪(而且对必须维护它的人来说很残忍!)

于 2008-10-09T13:39:04.350 回答
5

因为在第一个中 grp 不是 ON 子句所属的连接的一部分。

于 2008-10-09T13:06:32.887 回答
4

我不知道是什么导致了这种行为,如果它是一个错误或设计,但如果你坚持使用一种形式的加入或另一种形式,它应该可以正常工作。

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

如果行为是设计使然,我很想知道更多。

于 2008-10-09T13:11:02.517 回答
2

对于内部连接,表的顺序并不重要。

对于外连接,它是。 将包含指定一侧的表中的所有行(是左连接还是右连接),而仅包含另一侧表中与连接条件匹配的行。

因为 OUTER JOINS 保留一侧的所有行,所以据说它们(通常)增加了结果集。INNER JOINS 仅在匹配的情况下保留来自双方的行,因此(通常)说它们是为了减少结果集。因此,您通常希望在 OUTER JOINS 之前执行 INNER JOINS(如果可能)。

在您的情况下,几乎可以肯定是邪恶的 A,B 语法的结果。

于 2008-10-09T13:22:36.643 回答