【问题标题】:SQL: can any type of join be rewritten as a set of WHERE conditions?SQL:可以将任何类型的连接重写为一组 WHERE 条件吗?
【发布时间】:2011-05-07 09:33:43
【问题描述】:

例子:

如果我有一张物品及其所有者的表格。

对于自然连接,我可以做或得到相同的结果:

SELECT * FROM owners, things WHERE owners.id = things.owner_id
SELECT * FROM owners JOIN things ON owners.id = things.owner_id

现在如果我想做一个左连接?像这样,所有所有者都被归还...

SELECT * FROM owners LEFT JOIN things ON owners.id = things.owner_id

是否可以将任何类型的连接重写为一组 WHERE 条件?

谢谢

【问题讨论】:

    标签: sql database join where-clause


    【解决方案1】:

    INNER JOIN 始终可以重写为隐式连接。

    OUTER JOIN 有时可以在 Oracle 中使用专有子句行 (+)SQL Server 中的 * 等重写,但并非总是如此。

    另外,OUTER JOIN 可以使用UNION ALL 和子查询重写:

    SELECT  *
    FROM    a
    FULL JOIN
            b
    ON      some_condition(a, b)
    

    相同
    SELECT  *
    FROM    a, b
    WHERE   some_condition(a, b)
    UNION ALL
    SELECT  a.*, NULL, NULL, …, NULL
    FROM    a
    WHERE   NOT EXISTS
            (
            SELECT  NULL
            FROM    b
            WHERE   some_condition(a, b)
            )
    UNION ALL
    SELECT  NULL, NULL, …, NULL, b.*
    FROM    b
    WHERE   NOT EXISTS
            (
            SELECT  NULL
            FROM    a
            WHERE   some_condition(a, b)
            )
    

    这曾经是 OraclePostgreSQL 在早期版本中不支持 ANSI 语法的解决方法,也是 MySQL 不支持 FULL JOIN 的解决方法

    如果您的数据库支持,您应该使用 ANSI OUTER JOIN 语法。

    【讨论】:

    • 相反,仅仅因为您可以将WHERE 条件放在ON 子句中并不意味着您应该这样做。将ON 子句用于JOIN 目的,将WHERE 子句用于过滤目的。
    • JNK:是的,你可以。 WHERE 1 = 1.
    • @jnk 意外的笛卡尔连接是使用隐式连接的最大问题。错过一组条件中的一个条件并得到一个叉积确实很容易,但是如果您错过了一个连接条件,显式连接将不会通过语法检查。
    【解决方案2】:

    就您的 LEFT JOIN 示例而言,是的,您可以在 WHERE 子句中表达这一点,具体取决于 SQL 的风格和版本。

    在使用 LEFT JOIN(和某些其他联接)时,在某些情况下,不能在 WHERE 子句中表达单个 JOIN 的多个条件。

    一般来说,使用 ANSI 连接语法而不是 Theta(“WHERE 子句”)语法通常被认为是最佳实践。

    【讨论】:

      【解决方案3】:

      取决于什么数据库,以及是否仍支持其已弃用的外连接语法。 WHERE 子句中的 JOIN 标准是 ANSI-89 语法,但正如您所注意到的 - 没有 OUTER 连接支持,因此供应商实现了自己的。

      甲骨文:

      SELECT * 
        FROM owners, things 
       WHERE owners.id = things.owner_id(+)
      

      SQL 服务器:

      SELECT * 
        FROM owners, things 
       WHERE owners.id =* things.owner_id
      

      推荐

      不要 - 使用 ANSI-92 语法。它是可移植的,并且没有替代它的语法:

         SELECT * 
           FROM owners o
      LEFT JOIN things t ON o.id = t.owner_id
      

      【讨论】:

        【解决方案4】:

        当然,您永远不想使用隐式语法(这是一种非常糟糕的编程技术,容易出错并产生维护问题),那么为什么要这样编写左连接呢?

        我不能代表所有数据库,但 SQL Server 中的隐式左连接语法已被弃用,在任何情况下都不应该使用,因为它不能保证给出正确的结果。如果您将左连接的显式连接语法与隐式连接语法结合起来,我发现结果存在问题,因此如果您需要左连接,则将所有连接修复为显式。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2017-07-31
          • 2023-01-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-08-10
          • 1970-01-01
          相关资源
          最近更新 更多