是否可以将 LEFT JOIN 修改为 return 既有匹配又有匹配的空行?
Is it possible to modify a LEFT JOIN to return a null row where there is a match as well as the match?
我有一个代表层次结构的 table,因此它同时具有 id
和 parent_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;
然而,这会扫描 table 三次。我试图对此进行一些优化,所以尝试了这个:
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
方法那样扫描 table 三次?
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)
*/
Returns :
ID
3
4
5
并提供更好的性能
这也行,但执行计划变得讨厌
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
我有一个代表层次结构的 table,因此它同时具有 id
和 parent_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;
然而,这会扫描 table 三次。我试图对此进行一些优化,所以尝试了这个:
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
方法那样扫描 table 三次?
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)
*/
Returns :
ID
3
4
5
并提供更好的性能
这也行,但执行计划变得讨厌
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