SQL subselect 基于多个子行的过滤

SQL subselect filtering based on multiple sub-rows

我有两个表,想根据第二个表的 'child' 数据从第一个表中提取某些列。


Table 1) 让我们称之为 Projects

proj_id | Name  
--------+---------        
10      | Proj_1
20      | Proj_2
30      | Proj_3
40      | Proj_4

Table 2) 让我们称之为 tasks

proj_id | task_id | Status
--------+---------+-----------
10      | 1       | Ready
10      | 2       | Cancelled
10      | 3       | Ready
20      | 1       | Complete
20      | 2       | Ready
30      | 1       | Ready
30      | 2       | Not Ready
30      | 3       | Complete
40      | 1       | Ready
40      | 2       | Ready

我想做的是找出哪些'projects''tasks''ready'.

这里棘手的部分是,如果其他 任务 完成 就没问题,但如果它们不是完成准备就绪

所以换句话说输出应该是这样的:

Name   | Status
-------+--------
Proj_2 | Ready
Proj_4 | Ready

不想在结果集中看到Proj_1(任务是已取消)或Proj_3(任务未准备好

我不会发布任何 SQL,因为我不确定这是否可能....

通常我会在 C++ 中用 2 个多语句执行类似的操作,但在这种情况下我需要在单个语句中执行此操作,因为我需要将数据传递给第三方打印程序。

NOT EXISTS 解决方案,即 return 一个项目,如果它有一个就绪任务,并且除了就绪和完成之外没有其他任务:

select p.*
from Projects p
  join tasks t on p.proj_id = t.proj_id
where t.Status = 'ready'
  and not exists (select * from tasks t2
                  where t2.proj_id = t.proj_id
                    and t2.Status NOT IN ('ready', 'Complete'))

有多种方法可以处理此类查询。我喜欢将聚合与 having 子句一起使用,因为它非常灵活并且所有逻辑都在 having 子句中:

select t.proj_id
from tasks t
group by t.proj_id
having sum(case when status = 'ready' then 1 else 0 end) > 0 and
       sum(case when status not in ('complete, 'ready') then 1 else 0 end) = 0;

having 子句中的每个条件都会计算具有特定条件的任务数。第一个计算就绪任务的数量,> 0 表示至少有一个。第二个统计non-ready、non-complete的个数。 = 0 表示有 none.