【问题标题】:Is it possible to modify a LEFT JOIN to return a null row where there is a match as well as the match?是否可以修改 LEFT JOIN 以返回有匹配项和匹配项的空行?
【发布时间】:2015-03-07 15:10:29
【问题描述】:

我有一个表示层次结构的表,因此它同时具有idparent_id。此层次结构只有两个级别,并且父级在parent_id 中具有空值。我正在尝试为父级具有特定属性的层次结构中的每个项目获取记录。以这个数据为例:

CREATE TABLE t (id int, parent_id int, property bit);
INSERT INTO t VALUES
    (1, null,    0),
    (2,    1, null),
    (3, null,    1),
    (4,    3, null),
    (5, null,    1);

我想找回:

======
| ID |
======
| 3  |
| 4  |
| 5  |
======

我可以像这样使用UNION 来做到这一点:

SELECT
   id
FROM
   t
WHERE
   property = 1 AND parent_id is null
UNION
SELECT
   child.id
FROM
   t parent
   INNER JOIN t child
       ON parent.id = child.parent_id
WHERE
   parent.property = 1
ORDER BY
   id;

但是,这会扫描表 3 次。我试图对此进行一些优化,所以尝试了这个:

SELECT
   ISNULL(child.id, parent.id)
FROM
   t parent
   LEFT JOIN t child
       ON parent.id = child.parent_id
WHERE
   parent.property = 1 

但这只是给了我:

======
| ID |
======
| 4  |
| 5  |
======

没有返回第 3 行,因为 LEFT JOIN 没有为第 3 行提供单独的行,因为它与第 4 行中的 parent_id 匹配。有没有办法修改 LEFT JOIN 以提供我需要的额外行?是否有另一种方法来执行此查询,而不像 UNION 方法那样扫描表三次?

【问题讨论】:

  • 一个连接会链接两个表,它不会返回两次。
  • 无论如何,左连接也在做两次表扫描
  • @Jaques 好的,我错了,左连接进行了两次表扫描,而联合进行了三次。它有点复杂,因为涉及到索引,但这并不是问题的重点。

标签: sql-server sql-server-2008 tsql join


【解决方案1】:
 SELECT 
   ISNULL(child.id, parent.id)
FROM
   t child
   LEFT JOIN t parent
       ON child.parent_id = parent.id
WHERE
   parent.property = 1  OR child.property = 1
   /* you might want to do this instead to be sure to include only the parent nodes 
      with the property set to 1 :
      parent.property = 1  OR (child.property = 1 AND parent.id IS NULL)
   */

返回:

ID
3
4
5

并提供更好的性能

【讨论】:

    【解决方案2】:

    这也可行,但执行计划变得讨厌

    WITH n(id, parent_id) AS 
       (SELECT id, parent_id
        FROM t
        WHERE property = 1
        UNION ALL
        SELECT nplus1.id, nplus1.parent_id
        FROM t as nplus1 
        inner join n on n.id = nplus1.parent_id)
    SELECT id FROM n
    order by id
    

    【讨论】:

    • 为什么需要在这个简单的层次结构上使用递归 CTE?一个连接就足够了,而且性能要好得多
    • 就像我说的,它也有效。我没有说这是正确的解决方案。你的解决方案比我的要好得多。而且根据我的检查,性能其实是完全一样的
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-18
    • 1970-01-01
    • 2022-01-01
    • 2010-10-24
    • 2021-07-16
    • 1970-01-01
    相关资源
    最近更新 更多