SQL高效查询:满足多子条件组合的父集数据
高效查询满足多条件组合的父节点SQL方案
表结构与示例数据
T_PARENT表
| IDPARENT | NAME |
|---|---|
| 1 | Carlos |
T_CHILDREN表
| IDPARENT | NAME | AGE | HEIGHT |
|---|---|---|---|
| 1 | Juan | 9 | 120 |
| 1 | Juan | 9 | 110 |
| 1 | Pablo | 9 | 130 |
| 1 | Pablo | 9 | 120 |
| 1 | Pablo | 7 | 110 |
| 1 | Diego | 9 | 110 |
| 1 | Diego | 9 | 100 |
查询需求
需找出满足以下全部条件的父节点:
- 至少存在1个
NAME='Pablo'的子节点(年龄、身高不限); - 至少存在1个
NAME='Juan'且AGE=9的子节点(身高不限); - 至少存在1个
NAME='Diego'、AGE=9且HEIGHT=110的子节点; - 至少存在1个
NAME='Diego'、AGE=9且HEIGHT=120的子节点;
注:T_CHILDREN表中NAME-AGE-HEIGHT列值组合唯一。
高效SQL解决方案
使用GROUP BY结合HAVING子句的方式,只需扫描一次T_CHILDREN表即可完成所有条件验证,相比多次子查询的方案性能更优:
SELECT c.IDPARENT FROM T_CHILDREN c GROUP BY c.IDPARENT HAVING -- 验证存在Pablo的子节点 MAX(CASE WHEN c.NAME = 'Pablo' THEN 1 ELSE 0 END) = 1 -- 验证存在Juan且AGE=9的子节点 AND MAX(CASE WHEN c.NAME = 'Juan' AND c.AGE = 9 THEN 1 ELSE 0 END) = 1 -- 验证存在Diego、AGE=9且HEIGHT=110的子节点 AND MAX(CASE WHEN c.NAME = 'Diego' AND c.AGE = 9 AND c.HEIGHT = 110 THEN 1 ELSE 0 END) = 1 -- 验证存在Diego、AGE=9且HEIGHT=120的子节点 AND MAX(CASE WHEN c.NAME = 'Diego' AND c.AGE = 9 AND c.HEIGHT = 120 THEN 1 ELSE 0 END) = 1;
如果需要关联T_PARENT获取父节点名称,可修改为:
SELECT p.IDPARENT, p.NAME FROM T_CHILDREN c JOIN T_PARENT p ON c.IDPARENT = p.IDPARENT GROUP BY p.IDPARENT, p.NAME HAVING MAX(CASE WHEN c.NAME = 'Pablo' THEN 1 ELSE 0 END) = 1 AND MAX(CASE WHEN c.NAME = 'Juan' AND c.AGE = 9 THEN 1 ELSE 0 END) = 1 AND MAX(CASE WHEN c.NAME = 'Diego' AND c.AGE = 9 AND c.HEIGHT = 110 THEN 1 ELSE 0 END) = 1 AND MAX(CASE WHEN c.NAME = 'Diego' AND c.AGE = 9 AND c.HEIGHT = 120 THEN 1 ELSE 0 END) = 1;
方案优势
- 单表扫描:仅对T_CHILDREN表进行一次全表扫描(或利用索引扫描),避免了多次子查询带来的重复扫描开销;
- 索引优化:若在T_CHILDREN表上建立
(IDPARENT, NAME, AGE, HEIGHT)的联合索引,查询性能会进一步提升,分组和条件判断都能通过索引快速完成; - 逻辑清晰:所有条件集中在HAVING子句中,便于维护和扩展新的条件。
内容的提问来源于stack exchange,提问作者deko
相关产品推荐
相关产品推荐

