SQL NOT EXISTS查询未返回预期结果,需筛选无D1事件的记录
SQL NOT EXISTS查询未返回预期结果,需筛选无D1事件的记录
我来帮你梳理下这个问题~你想要的是找出同一ID和stopid组合下完全没有'D1'事件的所有记录对吧?你当前写的NOT EXISTS逻辑没抓到核心点,所以没得到预期结果。
先说说原查询的问题
你原来的子查询里加了s_inner.Events=s.Events和s.Events='D1',这其实是在判断「当前行本身是不是D1」,然后排除这类行,但这不是你要的逻辑——你真正要排除的是整个ID+stopid组里存在D1的那些组,而不是单个D1行。
正确的查询写法
这里给你两种可行的方案,都能得到你要的预期输出:
方案1:修正NOT EXISTS逻辑
SELECT ID, stopid, Events FROM #tmp s WHERE NOT EXISTS ( SELECT 1 FROM #tmp s_inner WHERE s_inner.ID = s.ID AND s_inner.stopid = s.stopid AND s_inner.Events = 'D1' -- 检查当前行所属的ID+stopid组是否存在D1 ) AND s.ID = 1; -- 按需保留ID=1的筛选条件
这个逻辑是:对每一行,检查它对应的ID+stopid组里有没有出现过D1,如果没有,就保留这一行。这样stopid=2的组因为存在D1会被整体排除,剩下的就是stopid=1下的所有记录,正好符合你的预期。
方案2:用LEFT JOIN筛选无D1的组
SELECT s.ID, s.stopid, s.Events FROM #tmp s LEFT JOIN ( -- 先找出所有包含D1的ID+stopid组合 SELECT DISTINCT ID, stopid FROM #tmp WHERE Events = 'D1' ) AS d1_groups ON s.ID = d1_groups.ID AND s.stopid = d1_groups.stopid -- 筛选出没有匹配到D1组的记录,也就是无D1的组 WHERE d1_groups.ID IS NULL AND s.ID = 1;
这个思路更直观:先把所有存在D1的分组拎出来,再通过左连接排除这些分组,剩下的就是我们需要的记录。
预期输出
执行上面任意一个查询,都会得到你想要的结果:
| ID | stopid | Events |
|---|---|---|
| 1 | 1 | AF |
| 1 | 1 | X1 |
备注:内容来源于stack exchange,提问作者Red Devil
相关产品推荐
相关产品推荐

