连接操作的顺序:这两个FROM子句会产生相同的结果吗?

Bra*_*ore -5 sql left-join sql-server-2008 right-join

这两个FROM子句会产生相同的结果吗?如果没有,有没有办法写第一个,所以不需要括号?

FROM            SALESTAX
     RIGHT JOIN (            ITEMS
                  RIGHT JOIN (            PINVOICE
                               INNER JOIN PINVDET ON PINVOICE.PNV_INVOICENO = PINVDET.PND_INVOICENO AND PINVOICE.PNV_Site = PINVDET.PND_Site
                             ) ON ITEMS.ITE_INVNO = PINVDET.PND_INVNO
                ) ON SALESTAX.STX_GroupID = PINVDET.PND_TAX1
      FULL JOIN (            CUSTMS
                  RIGHT JOIN CUSMER ON CUSTMS.TMS_CODE = CUSMER.CUS_TERM
                ) ON PINVDET.PND_CUSTID = CUSMER.CUS_CustID

FROM  CUSTMS RIGHT JOIN
      CUSMER ON TMS_CODE = CUS_TERM FULL JOIN
      PINVDET ON PND_CUSTID = CUS_CustID LEFT JOIN
      PINVOICE ON PNV_INVOICENO = PND_INVOICENO AND PNV_Site = PND_Site LEFT JOIN
      SALESTAX on STX_GROUPID = PND_TAX1 left join
      ITEMS on ITE_INVNO = PND_INVNO
Run Code Online (Sandbox Code Playgroud)

编辑:虽然我想知道第一个问题的答案,但我更感兴趣的是只需要一个不需要括号的第一个FROM子句的更简单版本,所以如果你只是重写它而不是比较两者然后随意做到这一点.

ype*_*eᵀᴹ 14

我不知道第一个是否等同于第二个(第一个因为查询是不友好的格式化,说至少和第二个因为RIGHT连接有点令人困惑,因为许多人习惯使用LEFT连接来写.)但回答这个问题:

有没有办法写第一个,所以不需要括号?

是的,您只需从第一个查询中删除括号即可.

保留括号并使用一些空格格式化:

FROM 
        SALESTAX
    RIGHT JOIN 
        (   ITEMS
        RIGHT JOIN 
            (   PINVOICE
            INNER JOIN 
                PINVDET 
              ON  PINVOICE.PNV_INVOICENO = PINVDET.PND_INVOICENO 
              AND PINVOICE.PNV_Site = PINVDET.PND_Site
            ) 
          ON ITEMS.ITE_INVNO = PINVDET.PND_INVNO
        ) 
      ON SALESTAX.STX_GroupID = PINVDET.PND_TAX1
    FULL JOIN 
        (   CUSTMS
        RIGHT JOIN
            CUSMER 
          ON CUSTMS.TMS_CODE = CUSMER.CUS_TERM
        ) 
      ON PINVDET.PND_CUSTID = CUSMER.CUS_CustID
Run Code Online (Sandbox Code Playgroud)

没有括号和白色空格格式:

FROM    
        SALESTAX
    RIGHT JOIN
            ITEMS
        RIGHT JOIN
                PINVOICE
            INNER JOIN 
                PINVDET 
              ON  PINVOICE.PNV_INVOICENO = PINVDET.PND_INVOICENO
              AND PINVOICE.PNV_Site = PINVDET.PND_Site
          ON ITEMS.ITE_INVNO = PINVDET.PND_INVNO
      ON SALESTAX.STX_GroupID = PINVDET.PND_TAX1
    FULL JOIN
            CUSTMS
        RIGHT JOIN 
            CUSMER 
          ON CUSTMS.TMS_CODE = CUSMER.CUS_TERM
      ON PINVDET.PND_CUSTID = CUSMER.CUS_CustID
Run Code Online (Sandbox Code Playgroud)

要回答另一个问题,关于第二个查询,不是它不等同.您错过了表别名并将内部联接更改为左联接.这相当于第1次:

FROM  CUSMER  
        LEFT JOIN
      CUSTMS     ON  CUSTMS.TMS_CODE = CUSMER.CUS_TERM
   FULL JOIN
      PINVDET
        INNER JOIN                                      -- this is changed
      PINVOICE   ON  PINVOICE.PNV_INVOICENO = PINVDET.PND_INVOICENO
                 AND PINVOICE.PNV_Site = PINVDET.PND_Site
        LEFT JOIN
      ITEMS      ON  ITEMS.ITE_INVNO = PINVDET.PND_INVNO
        LEFT JOIN
      SALESTAX   ON  SALESTAX.STX_GroupID = PINVDET.PND_TAX1
   ON PINVDET.PND_CUSTID = CUSMER.CUS_CustID
Run Code Online (Sandbox Code Playgroud)

  • @ruakh:**[Postgres](http://sqlfiddle.com/#!1/43f97/3)**允许它.**[Oracle](http://sqlfiddle.com/#!4/43f97/16)**允许它.它是时髦的(或不是),它是标准的SQL. (6认同)
  • @ruakh对不起,你错了.尝试给我们一个带有"ON"条件的例子.你的例子是他们错过了. (4认同)
  • @GordonLinoff见**[小提琴](http://sqlfiddle.com/#!3/d41d8/14258)**(我更改了两个ON条件的顺序) (3认同)
  • @ConradFrix你和访问:) (3认同)

Gor*_*off 6

我鼓励你先写下你from的所有条款,left join然后是inner joins.这极大地简化了试图找出正在执行的查询的过程.一系列的left joins说"保留第一个表中的所有行".一系列inner joins说"只保留表格之间存在匹配的行".(有时,您可能需要第一个示例中的子查询.)

在这个例子中,两者是不一样的.在第一个中,它full join是"最外层"的连接.在第二个中,full join嵌入了一系列连接.这些从第一个到最后一个顺序解释.其中一个可能是转换full joininner joinleft join.当然,如果所有表都匹配,则两者可以产生相同的结果.

第二个例子可能写成:

FROM  CUSMER  LEFT JOIN
      CUSTMS ON TMS_CODE = CUS_TERM LEFT JOIN
      PINVDET ON PND_CUSTID = CUS_CustID LEFT JOIN
      PINVOICE ON PNV_INVOICENO = PND_INVOICENO AND PNV_Site = PND_Site LEFT JOIN
      SALESTAX on STX_GROUPID = PND_TAX1 left join
      ITEMS on ITE_INVNO = PND_INVNO
Run Code Online (Sandbox Code Playgroud)

(假设在将full join其转换为left join反正之后的某些东西).