如何仅选择包含至少一个子元素的父行?

19

我有一个简单的一对多关系。我想只选择父行,当它们至少有一个子孙时。因此,如果没有子孙,则父行不会在结果集中返回。

例如:

Parent:
+--+---------+
|id|   text  |
+--+---------+
| 1|  Blah   |
| 2|  Blah2  |
| 3|  Blah3  |
+--+---------+

Children
+--+------+-------+
|id|parent| other |
+--+------+-------+
| 1|   1  | blah  |
| 2|   1  | blah2 |
| 3|   2  | blah3 |
+--+------+-------+

我希望得到以下结果:

+----+------+
|p.id|p.text|
+----+------+
|  1 | Blah |
|  2 | Blah2|
+----+------+
4个回答

27
你可以使用EXISTS来实现,像这样:
SELECT *
FROM Parent p
WHERE EXISTS (SELECT 1
              FROM Chilren c
              WHERE c.Parent = p.id)

或者使用像这样的IN

SELECT *
FROM Parent p
WHERE p.id IN (SELECT c.Parent
               FROM Chilren c)

3
我没有进行测试,但我猜想这比使用连接慢。 - Hogan
8
@Hogan - EXISTS 是最快的方法。优化器会为 null 检查外连接执行相同的执行计划......这将与 EXISTS 一样快,但 EXISTS 永远不会更慢。 - Nick Craver
好的。谢谢@Nick。这对于mysql、ms sql和oracle都是适用的吗? - Hogan
1
@Hogan - 存在性更快,是的这是正确的...优化器有多聪明,使得等价的左连接具有相同的执行计划,在MS SQL中我不确定。 - Nick Craver

15

inner join 只会返回两个表中匹配的行:

select distinct p.*
from Parent p
inner join Children c on c.parent = p.id

2
这是我认为最直接的方法,应该被接受为答案。 - adriandz

3
Select p.id, p.text
from Parent p
inner join Children c on p.id = c.parent 
group by p.id, p.text

1
SELECT p.*
FROM Parent p
WHERE EXISTS (SELECT 'X' FROM Children c WHERE c.parent = p.id);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接