【问题标题】:How can I substitute a left join in SQL如何在 SQL 中替换左连接
【发布时间】:2011-11-22 13:17:41
【问题描述】:

谁能告诉我如何在不真正使用左连接的情况下编写相当于左连接的方法。

Select * from a left join b on a.name = b.name.

【问题讨论】:

  • Select * from b right join a on a.name = b.name.
  • 开个玩笑,你为什么要这么做?
  • 我的意思是完全不使用连接,问题是我无法让左连接在 Hibernate 中工作,并且打算完全消除它
  • 如果 Hibernate 无法生成包含左连接的查询,我会非常地感到惊讶。也许你应该问一个关于这个的问题? (无论你在这里得到什么答案,如果你能强制 Hibernate 生成它们,我会感到惊讶)

标签: sql left-join


【解决方案1】:

请记住,SQL 的外连接是一种关系联合,专门设计用于投射空值。如果你想避免使用空值(在我看来这是一件好事),你应该避免使用外连接。请注意,现代关系语言已经完全放弃了空连接和外连接的概念。

这个外连接:

SELECT DISTINCT T1.id, T1.value, T2.other_value
  FROM T1
       LEFT OUTER JOIN T2
          ON T1.id = T2.id;

...在语义上等同于以下 SQL 代码:

SELECT T1.id, T1.value, T2.other_value
  FROM T1
       INNER JOIN T2
          ON T1.id = T2.id
UNION
SELECT T1.id, T1.value, NULL
  FROM T1
 WHERE NOT EXISTS (
                   SELECT * 
                     FROM T2
                    WHERE T1.id = T2.id
                  );

第二个查询可能看起来很冗长,但这仅仅是因为 SQL 的设计/演变方式。以上只是自然连接、联合和半连接。但是,SQL 没有半连接运算符,如果您的产品没有实现标准 SQL 的 NATURAL JOIN 语法,则需要您在 SELECT 子句中指定列列表并编写 JOIN 子句,这导致要表达的代码很多很简单的事情。

因此,您可以编写类似于上面第二个查询的代码,但使用实际的默认值而不是空值。

【讨论】:

    【解决方案2】:

    虽然与替代方法相比,左外连接是编写 sql 的推荐方式,但我们仍然可以通过对结果集使用联合来实现左外连接。如果我们有两个表 Table1 和 Table 2 那么我们可以通过以下方式实现 -

    select
           A.Id, 
           A.Col1, 
           A.Col2, 
           A.Col3, 
           B.Id Col4, 
           B.Col1 Col5, 
           B.Col2 Col6, 
           B.Col3 Col7, 
           B.Col4 Col8
    from   Table1 A, Table2 B
    where  A.Id = B.Id
    
    union all
    
    select
           A.Id, 
           A.Col1, 
           A.Col2, 
           A.Col3, 
           null as Col4, 
           null as Col5, 
           null as Col6, 
           null as Col7, 
           null as Col8
    from   Table1 A
    where  not exists(select 1 from Table2 B where B.Id = A.Id)
    

    这将有助于实现相同的结果,但由于使用联合,如果表很大,可能会出现一些性能问题。

    【讨论】:

      【解决方案3】:

      Oracle 伪装的左连接:

      SELECT * FROM A, B
       WHERE a.name = b.name(+)
      

      通用:

      SELECT a.*, case c.existence WHEN 1 then c.name ELSE NULL END
        FROM A
       INNER JOIN ( SELECT name name, 1 existence FROM B
                     UNION ALL
                    SELECT a.name name, 0 existence FROM A
                     WHERE a.name NOT IN ( SELECT name FROM B )
                  ) C
          ON c.name = a.name
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-07-08
        • 1970-01-01
        • 2022-01-24
        • 2018-12-24
        • 2018-02-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多