SQL筛选逻辑疑问:双IN子查询为何能获取目标数据集?
一、当前SQL为何能生效
你的SQL核心逻辑是筛选出同时满足两个条件的Subset_ID:
- 该Subset_ID下存在至少一条
Parent_ID IS NULL的记录 - 该Subset_ID下存在至少一条
Parent_Name IS NULL的记录
在你的测试数据里,只有Subset_ID=9876同时符合这两个条件(它有一条记录的Parent_ID和Parent_Name全为NULL),而Subset_ID=9877没有任何一条记录的Parent_ID或Parent_Name为NULL,因此被排除。外层查询只要Subset_ID在这个交集里,就会返回该Subset_ID下的所有行——刚好命中了你的测试需求,所以得到了预期结果。
二、是否始终有效?
不是。你的SQL逻辑和原需求的匹配是巧合:原需求是「同一Subset_ID下,部分记录的Parent列(ID+Name)全有值,另一部分记录的Parent列全为NULL」,但你的SQL只验证了「该Subset_ID存在Parent_ID为NULL的记录,且存在Parent_Name为NULL的记录」,这两个逻辑并不完全等价,会出现误判或漏判的情况。
三、失效场景与边界情况
1. 误判(选中不符合需求的Subset_ID)
当Subset_ID下的记录没有「Parent列全为NULL」的行,但分别存在Parent_ID为NULL、Parent_Name非空和Parent_ID非空、Parent_Name为NULL的行时,你的SQL会错误选中这个Subset_ID:
示例数据:
| Parent_ID | Parent_Name | Subset_ID |
|---|---|---|
| NULL | SHOP_A | 1000 |
| 111222 | NULL | 1000 |
此时你的SQL会返回Subset_ID=1000的所有行,但它并不符合「部分记录Parent列全有值,部分全为NULL」的需求。
2. 误判(选中无全有值Parent列的Subset_ID)
如果Subset_ID下只有「Parent列全为NULL」的行,和「Parent_ID非空但Parent_Name为NULL」的行,没有任何一条记录的Parent列全有值,你的SQL依然会选中这个Subset_ID,但它完全不符合原需求。
3. 多字段NULL不同步的场景
当Subset_ID下存在多种NULL组合(比如部分行Parent_ID空、部分行Parent_Name空,但没有全空行),同时存在Parent列全有值的行,你的SQL会选中该Subset_ID,但它不符合原需求——原需求是需要「全空行」和「全有值行」同时存在。
四、更准确的实现方案
如果要严格匹配原需求,推荐用窗口函数统计每个Subset_ID下的两种关键记录数量:
SELECT * FROM ( SELECT t.*, -- 统计该Subset_ID下Parent列全非空的记录数 COUNT(CASE WHEN Parent_ID IS NOT NULL AND Parent_Name IS NOT NULL THEN 1 END) OVER (PARTITION BY Subset_ID) AS cnt_non_null_parent, -- 统计该Subset_ID下Parent列全为空的记录数 COUNT(CASE WHEN Parent_ID IS NULL AND Parent_Name IS NULL THEN 1 END) OVER (PARTITION BY Subset_ID) AS cnt_null_parent FROM Sometable t ) sub WHERE cnt_non_null_parent > 0 AND cnt_null_parent > 0
这个方案直接验证了「该Subset_ID下同时存在Parent列全非空和全为空的记录」,完全匹配原需求,不会出现上述失效场景。
内容的提问来源于stack exchange,提问作者SnacknPack

