代码之家  ›  专栏  ›  技术社区  ›  Jay

为什么使用join子句和where条件?

  •  12
  • Jay  · 技术社区  · 15 年前

    我针对Oracle数据库进行开发。当我需要手动写入(不使用类似于hibernate的ORM)时,我使用一个where条件而不是join。

    例如(这只是为了说明样式而简单化):

    Select *
    from customers c, invoices i, shipment_info si
    where c.customer_id = i.customer_id
        and i.amount > 999.99 
        and i.invoice_id = si.invoice_id(+)  -- added to show a replacement for a join
    order by i.amount, c.name
    

    我从一个旧的Oracle DBA学习了这种风格。从那以后,我了解到这不是标准的SQL语法。除了非标准和数据库可移植性差得多之外,使用这种格式还有其他影响吗?

    10 回复  |  直到 5 年前
        1
  •  6
  •   Erich Kitzmueller    15 年前

    有些人会说这种风格不太可读,但这是习惯问题。从性能的角度来看,这并不重要,因为查询优化器负责处理这一点。

        2
  •  16
  •   Hank Gay    15 年前

    我不喜欢这种款式,因为它很难决定是哪一种 WHERE 子句用于模拟 JOINs 哪些是用于实际过滤器的,我不喜欢那些使确定程序员的原始意图变得不必要的困难的代码。

        3
  •  10
  •   Adam Paynter    15 年前

    对于这种格式,我遇到的最大问题是容易忘记某些连接 WHERE 从而产生笛卡尔积。这在向查询添加新表时尤其常见(至少对我来说)。例如,假设 ADDRESSES 桌子被扔到了混合中,你的思想有点健忘:

    SELECT *
      FROM customers c, invoices i, addresses a
     WHERE c.customer_id = i.customer_id
       AND i.amount > 999.99
     ORDER BY i.amount, c.name
    

    繁荣!笛卡尔产品!:)

        4
  •  7
  •   Beryllium    11 年前

    旧的连接在某些情况下是完全错误的(外部连接是罪魁祸首)。虽然它们在使用内部联接时或多或少是等效的,但它们可以使用外部联接生成不正确的结果,特别是如果外部的列可以为空的话。这是因为使用旧语法时,联接条件 逻辑上 在构造整个结果集之前对其进行了计算,因此无法从联接的外侧对列表示一个条件,该条件将在列可以为空时筛选记录,因为没有匹配的记录。

    举个例子:

    选择 全部的 客户,以及8月份所有发票上小部件的销售总额,发票已在其中处理(invoice.processDate为 不是 空)

    使用新的ANSI-92联接语法

     Select c.name, Sum(d.Amount)
     From customer c
        Left Join Invoice I 
            On i.custId = c.custId
                And i.SalesDate Between '8/1/2009' 
                          and '8/31/2009 23:59:59'
                And i.ProcessDate Is Not Null
        Left Join InvoiceDetails d 
            On d.InvoiceId = i.InvoiceId
                And d.Product = 'widget'
     Group By c.Name
    

    尝试使用旧语法执行此操作…因为在使用旧样式语法时,在将“外部”行重新添加回之前,将对where子句中的所有条件进行评估/应用,所有未处理的发票行都将重新添加到最终结果集中…所以用旧的语法是不可能的-任何试图筛选出处理日期为空的发票的行为都将消除客户…唯一的选择是使用相关的子查询。

        5
  •  4
  •   Joel Coehoorn    15 年前

    从那以后,我了解到这不是标准的SQL语法。

    这不完全正确。这个 "a,b where" 语法来自ANSI-89标准, "a join b on" 语法是ANSI-92。但是,89语法是 贬低 也就是说你应该 用于新查询。

    此外,在某些情况下,旧样式缺乏表达能力,特别是在外部联接或复杂查询方面。

    通过WHERE子句尝试选择联接条件可能会很痛苦。因为任何超过一个加入的旧风格都是绝对邪恶的。一旦你了解了新的风格,你也可以继续使用它。

        6
  •  3
  •   Larry Lustig    15 年前

    这是标准的SQL语法,只是 老年人 标准而非连接。语法的发展是有原因的,您应该使用新的连接语法,因为:

    1. 它更具表现力,清楚地指示哪些表被联接,联接顺序,哪些条件适用于哪个联接,以及分离条件与联接条件之间的过滤。

    2. 它支持左、右和全外部联接,而WHERE语法不支持这种联接。

    我认为您不会发现where类型join比join语法更不可移植。

        7
  •  3
  •   Rob van Laarhoven    15 年前

    只要您不使用ansi自然连接功能,我就可以使用它。

    我发现这句“Scottcher”的话,我完全同意:

    我发现哪里的语法比内部连接更容易阅读——我猜它就像vegemite。世界上大多数人可能觉得它恶心,但孩子们从小就喜欢吃它。

        8
  •  3
  •   ercan    15 年前

    这真的取决于习惯,但我一直认为甲骨文的逗号分隔语法更自然。第一个原因是我认为使用 (内部)连接 降低可读性。第二个问题是灵活性。最后,联接是笛卡尔积的定义。您不必根据两个表的ID限制结果。虽然很少,但可能需要两个表的笛卡尔积。基于ID限制它们是非常合理的做法,但是 不是规则 .但是,如果您使用 加入 关键字,例如SQL Server,它不会让您忽略 关键字。假设您想要创建一个组合列表。你必须这样做:

    SELECT *
    FROM numbers
    JOIN letters
    ON 1=1
    

    除此之外,我发现 (+) 甲骨文的语法也很合理。这是一个很好的表达方式。” 将此记录也添加到结果集,即使它为空。 “这比 右/左连接 语法,因为实际上没有左或右!当您想用几种不同类型的外部联接联接来联接10个表时,会混淆哪个表在“左侧”和哪个表在右侧。

    顺便说一下,作为一个更一般的评论,我认为SQL可移植性在现实世界中已经不存在了。标准的SQL太差了,各种DBMS特定语法的表达能力经常被要求,我不认为100%可移植的SQL代码是一个可以实现的目标。我观察到的最明显的证据是 行号 有问题的搜索任何论坛 “SQL行数” 包括So在内,您将看到数百篇文章询问如何在特定DBMS中实现它。与此相似和相关,因此 限制返回行数 例如…

        9
  •  0
  •   DVK    15 年前

    这是Transact-SQL语法,我不太确定它有多“不可移植”——它是Sybase中使用的主要语法,例如(Sybase也支持ANSI语法)以及许多其他数据库(如果不是全部)。

    对ansi语法的主要好处是,它允许您编写一些T-SQL禁止的相当复杂的链接连接。

        10
  •  -2
  •   MusiGenesis    15 年前

    实际上,这个语法是 更多 比join更可移植,因为它几乎可以与任何数据库一起使用,而不是每个人都支持join语法(例如,OracleLite不支持(除非最近发生了变化))。