【问题标题】:Simulate a left join without using "left join"在不使用“左连接”的情况下模拟左连接
【发布时间】:2012-02-06 11:57:01
【问题描述】:

我需要在不使用“左连接”键的情况下模拟左连接效果。

我有两个表,A 和 B,都有 idname 列。我想选择两个表上的所有 dbid,其中 A 中的名称等于 B 中的名称。

我用它来进行同步,所以一开始 B 是空的(所以我会有一对来自 A 的 id 有一个值,而来自 B 的 id 为空)。稍后我将混合具有 value - value 和 value - null 的夫妇。

通常是:

SELECT A.id, B.id
FROM A left join B
ON A.name = B.name

问题是我不能使用left join 并且想知道是否/如何可以做同样的事情。

【问题讨论】:

  • 为什么不能使用左连接?
  • “我想做[事情]但我不能使用[通常用来做[事情]的工具]”格式的问题通常是一个标志以错误的方式处理问题。请围绕您要解决的实际问题提供一些背景信息,以及您不能在查询中使用LEFT JOIN 的原因。
  • @Polynomial 有时它是家庭作业或面试问题的标志。或者,也许 OP 的 L-key 坏了。也许他会澄清......
  • 听起来你想要关系运算符semi difference (a.k.a. antijoin),但不知道它叫什么,所以检查了通常用于执行它的 SQL 概念。不能使用左连接可能是一个有趣的问题,但又提出了另一个问题:“你可以使用什么可以?”
  • @Polynomial:在 SQL 中总是有大约七种方法可以完成给定的事情,其中​​两种将被视为候选方法,应该进行性能测试。 SQL 不是一种万能的语言。

标签: sql


【解决方案1】:

你可以使用这种方法,但你必须确保内部选择只返回一行。

SELECT A.id, 
(select B.id from B where  A.name = B.name) as B_ID
FROM A 

【讨论】:

  • 这个解决方案是否适用于所有数据库(Oracle、MySql、PostGre,...)?建议的多项式与此相同,但它使用 NVL,即 MySql 没有...
  • 不确定,您必须尝试一下。我这里只能访问 SQL Server
  • 这不等同于LEFT JOIN。或者,准确地说,它仅相当于 B(name) 具有 UNIQUE 约束。
  • @Diego 你能发一个完整的模拟左连接的代码吗?
  • 这适用于 postgres,但只能选择一列
【解决方案2】:

我只能想到两种目前还没有给出的方法。我的最后三个想法已经给出(嘘),但我把它们放在这里是为了后代。我确实没有作弊就想到了他们。 :-p

  1. 计算 B 是否有匹配,然后为 B 集提供一个额外的 UNIONed 行,以便在没有匹配时提供 NULL。

    SELECT A.Id, A.Something, B.Id, B.Whatever, B.SomethingElse
    FROM
       (
          SELECT
             A.*,
             CASE
                WHEN EXISTS (SELECT * FROM B WHERE A.Id = B.Id) THEN 1
                ELSE 0
             END Which
          FROM A
       ) A
       INNER JOIN (
          SELECT 1 Which, B.* FROM B
          UNION ALL SELECT 0, B* FROM B WHERE 1 = 0
       ) B ON A.Which = B.Which
          AND (
             A.Which = 0
             OR (
                A.Which = 1
                AND A.Id = b.Id
             )
          )
    
  2. 对同一个查询略有不同的看法:

    SELECT A.Id, B.Id
    FROM
       (
          SELECT
             A.*,
             CASE
                WHEN EXISTS (SELECT * FROM B WHERE A.Id = B.Id) THEN A.Id
                ELSE -1 // a value that doesn't exist in B
             END PseudoId
          FROM A
       ) A
       INNER JOIN (
          SELECT B.Id PseudoId, B.Id FROM B
          UNION ALL SELECT -1, NULL
       ) B ON A.Which = B.Which
          AND A.PseudoId = B.PseudoId
    
  3. 仅适用于 SQL Server。我知道,这确实是一个左连接,但它并没有在里面说 LEFT

    SELECT A.Id, B.Id
    FROM
       A
       OUTER APPLY (
          SELECT *
          FROM B
          WHERE A.Id = B.Id
       ) B
    
  4. 获取内部连接,然后 UNION 外部连接:

    SELECT A.Id, B.Id
    FROM
       A
       INNER JOIN B ON A.name = B.name
    UNION ALL 
    SELECT A.Id, NULL
    FROM A
    WHERE NOT EXISTS (
       SELECT *
       FROM B
       WHERE A.Id = B.Id
    )
    
  5. 使用右连接。这不是 LEFT JOIN!

    SELECT A.Id, B.Id
    FROM
       B
       RIGHT JOIN A ON B.name = A.name
    
  6. 只需在子查询表达式中选择 B 值(希望每个 A 只有一个 B)。 B 中的多个列可以是它们自己的表达式(YUCKO!):

    SELECT A.Id, (SELECT TOP 1 B.Id FROM B WHERE A.Id = B.Id) Bid
    FROM A
    

任何使用 Oracle 的人都可能需要在任何没有 FROM 的 SELECT 中使用一些 FROM DUAL 子句。

【讨论】:

    【解决方案3】:

    例如,在 SQL Server 中,您可以使用 *= 运算符进行左连接:

    select A.id, B.id
    from A, B
    where A.name *= B.name
    

    如果存在这样的运算符,其他数据库的语法可能会略有不同。

    这是在引入join 关键字之前使用的旧语法。如果可能,您当然应该使用 join 关键字。旧语法甚至可能无法在新版本的数据库中使用。

    【讨论】:

    • 我仍然在您的查询中看到 LEFT JOIN。我错过了什么吗?
    • *= 仅适用于 Microsoft SQL Server。 Oracle 使用(+)。所有其他人根本没有这样的运营商。
    • @Polynomial:你读得太快了。我在发布答案后立即纠正了这一点。 :)
    • @a_horse_with_no_name:是的,我应该提到这一点。
    【解决方案4】:

    您可以使用 oracle + 运算符进行左连接:-

    选择 A.id、B.id 从甲,乙 ON A.name = B.name (+)

    查找链接:-

    Oracle "(+)" Operator

    【讨论】:

      【解决方案5】:

      我不熟悉 java/jpa。使用纯 SQL,这是一种方法:

      SELECT A.id AS A_id, B.id AS B_id
        FROM A INNER JOIN B
                ON A.name = B.name
      UNION
      SELECT id AS A_id, NULL AS B_id 
        FROM A 
       WHERE name NOT IN ( SELECT name FROM B );
      

      【讨论】:

        【解决方案6】:

        只需反转表格并改用右连接。

        SELECT A.id,
               B.id
        FROM   B
               RIGHT JOIN A
                 ON A.name = B.name  
        

        【讨论】:

        • 如果他不能使用左连接,我怀疑他可以使用右连接。
        【解决方案7】:

        您可以使用子查询,例如:

        select a.id
        ,      nvl((select b.id from b where b.name = a.name), "") as bId
        from a
        

        【讨论】:

          【解决方案8】:
          SELECT A.id, B.id
          FROM A full outer join B
          ON A.name = B.name
          where A.name is not null
          

          【讨论】:

            【解决方案9】:

            我不确定您是不能使用LEFT JOIN,还是根本无法使用任何JOINS。但据我了解您的要求,INNER JOIN 应该可以工作:

            SELECT A.id, B.id
            FROM A 
            INNER JOIN B ON A.name = B.name
            

            【讨论】:

              【解决方案10】:

              使用纯简单的 sql 模拟左连接:

              SELECT A.name
              FROM A
              where (select count(B.name) from B where  A.id = B.id)<1; 
              

              在左连接中,B 中没有引用 A 的行,因此 B 中的 0 名称将引用 A 中没有匹配的行 + 或 A.id = B.id 在 where 子句中模拟内连接

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2020-05-15
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2011-10-01
                • 1970-01-01
                相关资源
                最近更新 更多