【问题标题】:SQL style question: INNER JOIN in FROM clause or WHERE clause?SQL 风格问题:FROM 子句或 WHERE 子句中的 INNER JOIN?
【发布时间】:2011-06-12 19:33:06
【问题描述】:

如果您要在 SQL 查询中连接多个表,您认为将连接语句放在哪里更好:FROM 子句还是 WHERE 子句?

如果你打算在 FROM 子句中做,你如何格式化它以使其清晰易读? (我指的是缩进、换行符、空格。)

各有优缺点吗?

【问题讨论】:

  • 我不太清楚你的意思。 INNER JOIN 在标准 SQL 中的任何 WHERE 子句之前,除非我遗漏了什么。
  • 你有五个答案几乎完全一样,所以我认为你的答案是对的 :)。
  • 值得一看this question
  • @Andrew:您可以通过以下语法在 WHERE 子句中进行 INNER JOIN:TABLE_X.x = TABLE_Y.y。您可以通过语法在 WHERE 子句中进行 LEFT JOIN:TABLE_X.x = TABLE_Y.y (+)
  • @Chris:是的,很高兴这里有如此广泛的共识:-)

标签: sql database


【解决方案1】:

ANSI 连接。我省略了 SQL 中的任何可选关键字,因为它们只会给等式添加噪音。没有左 inner 连接这样的东西,是吗?而且默认情况下,简单连接是内连接,所以说“内连接”并没有什么特别的意义。

然后我尽可能多地列对齐。

关键是大型复杂 SQL 查询可能很难理解,因此对其施加的顺序越多以使其更具可读性越好。任何查看查询以修复、修改或调整它的机构都需要能够立即回答一些问题:

  • 查询中涉及哪些表/视图?
  • 每个连接的标准是什么?每个连接的基数是多少?
  • 查询返回什么/多少列

我喜欢编写我的查询,使它们看起来像这样:

select PatientID              = rpt.ipatientid ,
       EventDate              = d.dEvent       ,
       Side                   = d.cSide        ,
       OutsideHistoryDate     = convert(nchar, d.devent,112) ,
       Outcome                = p.cOvrClass    ,
       ProcedureType          = cat.ctype      ,
       ProcedureCategoryMajor = cat.cmajor     ,
       ProcedureCategoryMinor = cat.cminor
from      dbo.procrpt rpt
join      dbo.procd   d   on d.iprocrptid   = rpt.iprocrptid
join      dbo.proclu  lu  on lu.iprocluid   = d.iprocluid
join      dbo.pathlgy p   on p.iProcID      = d.iprocid
left join dbo.proccat cat on cat.iproccatid = lu.iproccatid
where procrpt.ipatientid = @iPatientID

【讨论】:

    【解决方案2】:

    我几乎总是使用 ANSI 92 连接,因为它清楚地表明这些条件适用于 JOINING。

    通常我是这样写的

    FROM
        foo f
        INNER JOIN bar b
        ON f.id = b.id
    

    有时我会在琐碎的时候这样写

    FROM
        foo f
        INNER JOIN bar b  ON f.id = b.id
        INNER JOIN baz b2  ON b.id = b2.id
    

    当它不是微不足道的时候,我会做第一种方式

    例如

    FROM 
       foo f
       INNER JOIN bar b 
       ON f.id = b.id  
          and b.type = 1
    

    FROM 
       foo f
       INNER JOIN (
              SELECT max(date) date, id
              FROM foo 
              GROUP BY
                 id) lastF
      ON f.id = lastF.id
          and f.date = lastF.Date
    

    或者真的很奇怪(不确定我的括号是否正确,但它应该是表格栏的左连接,但栏需要内部连接到 baz)

    FROM 
         foo f
         LEFT JOIN (bar b
              INNER JOIN baz b2 
               ON b.id = b2.id
          )ON f.id = b.id
    

    【讨论】:

      【解决方案3】:

      我肯定总是在我的 FROM 子句中做我的 JOINS(任何类型的)。​​

      我缩进的方式是这样的:

      SELECT fields
      FROM table1 t1
      INNER JOIN table2 t2 ON t1.id = t2.t1_id
      INNER JOIN table3 t3 ON t1.id = t3.t1_id
          AND
          t2.id = t3.t2_id
      

      事实上,我通常会更进一步,将尽可能多的约束逻辑从 WHERE 子句移到 FROM 子句,因为这(至少在 MS SQL 中)预先加载了约束,这意味着它减少了在查询构造中记录集的大小更快(我见过与此相矛盾的文档,但是当我这样做时,我的执行计划总是更有效)。

      例如,如果我只想在上面的查询中选择 t3.id = 3 的东西,你可以在 WHERE 子句中选择,或者你可以这样做:

      SELECT fields
      FROM table1 t1
      INNER JOIN table2 t2 ON t1.id = t2.t1_id
      INNER JOIN table3 t3 ON t1.id = t3.t1_id
          AND
          t2.id = t3.t2_id
          AND
          t3.id = 3
      

      我个人认为以这种方式排列的查询非常可读和可维护,但这肯定是个人喜好问题,所以 YMMV。

      无论如何,我希望这会有所帮助。

      【讨论】:

        【解决方案4】:

        如果没有其他原因,我更喜欢 FROM 子句,它仅在外键关系和逻辑限制之间区分过滤结果(来自笛卡尔积)。例如:

        SELECT * FROM Products P JOIN ProductPricing PP ON P.Id = PP.ProductId
        WHERE PP.Price > 10
        

        相对于

        SELECT * FROM Products P, ProductPricing PP 
        WHERE P.Id = PP.ProductID AND Price > 10
        

        我可以看到第一个并立即知道我设置的唯一合乎逻辑的限制是价格,而不是在关系键上将表连接在一起的隐含机制。

        【讨论】:

          【解决方案5】:

          使用 FROM 子句符合 ANSI-92 标准。

          这个:

          select *
              from a
                  inner join b
                      on a.id = b.id
              where a.SomeColumn = 'x'
          

          不是这个:

          select *
              from a, b
              where a.id = b.id
                  and a.SomeColumn = 'x'
          

          【讨论】:

          • WHERE 子句版本完全符合 ISO 标准 SQL92 及更高版本。 (ANSI 是发布 ISO 标准的机构之一。ANSI SQL 真正的意思是 ISO SQL)
          【解决方案6】:

          在进行 OUTER JOIN(ANSI-89 或 ANSI-92)时,过滤位置很重要,因为ON 子句中指定的标准在在进行 JOIN 之前应用。 WHERE 子句中提供的针对 OUTER JOIN 表的条件在在进行 JOIN 之后应用。这会产生非常不同的结果集。

          相比之下,如果在 ONWHERE 子句中提供条件,则 INNER JOIN 无关紧要 - 结果将是相同的。也就是说,我努力保持WHERE 子句的干净——任何与JOINed 表相关的内容都将在它们各自的ON 子句中。无需通过 WHERE 子句进行搜索,这就是 ANSI-92 语法更具可读性的原因。

          【讨论】:

          • +1 表示过滤器位置。我看到很多人都被它绊倒了。
          【解决方案7】:

          您应该将连接放在 Join 子句中,即 From 子句。关于在哪里放置过滤语句可能会有不同的问题。

          关于缩进,有很多样式。我的偏好是缩进相关的连接,并将 Select、From、Where、Group By、Have 和 Order By 等主要子句保持在同一级别。此外,我将这些主要属性中的每一个和 On 子句的第一行放在了自己的行中。

          Select ..
          From Table1
              Join Table2
                  On Table2.FK = Table1.PK
                     And Table2.OtherCol = '12345'
                     And Table2.OtherCol2 = 9876
              Left Join (Table3
                  Join Table4
                      On Table4.FK = Table3.PK)
                  On Table3.FK = Table2.PK
          Where ...
          Group By ...
          Having ...
          Order By ...
          

          【讨论】:

            【解决方案8】:

            我倾向于使用FROM 子句,或者更确切地说是JOIN 子句本身,像这样缩进(并使用别名):

            SELECT t1.field1, t2.field2, t3.field3
            FROM table1 t1
              INNER JOIN table2 t2
                ON t1.id1 = t2.id1
              INNER JOIN table3 t3
                ON t1.id1 = t3.id3
            

            这使连接条件接近于进行连接的位置。我发现这种方式更容易理解,然后尝试查看 WHERE 子句以弄清楚究竟是如何加入的。

            【讨论】:

            • 谢谢。这是编写多个内部连接的一种非常清晰的方法。
            猜你喜欢
            • 2014-02-07
            • 1970-01-01
            • 2012-02-02
            • 2013-08-11
            • 2010-11-04
            • 2012-04-25
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多