SQL中能否用ANY结合OVER(PARTITION BY)实现分区内条件判断?
如何判断每行所属公司是否存在Tom?
针对你的问题先直接给结论:你写的any(people = 'Tom') over (partition by company order by company)语句在大多数SQL数据库里无法运行——因为ANY通常是用于子查询的比较运算符(比如WHERE col = ANY(...)),并不支持作为窗口聚合函数使用。不过我们有几种更合适的方法来实现你的需求:
方法1:用布尔聚合函数直接实现(部分数据库支持)
如果你的数据库支持布尔聚合函数(比如PostgreSQL),可以直接用BOOL_OR来判断分区内是否存在符合条件的行,写法更简洁:
select *, bool_or(people = 'Tom') over (partition by company) as find_tom from t1;
这个语句会直接返回每个公司分区内是否存在Tom(true表示存在,false表示不存在)。
方法2:你的两步替代方案(通用所有数据库)
你给出的两步方案逻辑清晰,完全可以实现需求,而且适配所有主流SQL数据库。我们再梳理并优化一下:
- 第一步:给每行标记是否为Tom,生成中间表
t2
-- step 1: 生成是否为Tom的二进制标记 select *, case when people = 'Tom' then 1 else 0 end as has_tom into t2 from t1;
- 第二步:用窗口函数
MAX()统计每个公司的标记最大值,判断是否存在Tom
-- 统计每个公司是否存在Tom select *, case when max(has_tom) over (partition by company) = 1 then 'has tom' else 'no tom' end as find_tom from t2;
这里可以去掉order by company,因为已经按company分区,排序不会影响MAX()的结果,语句更简洁。
执行后会得到你预期的结果:
| company | people | has_tom | find_tom |
|---|---|---|---|
| apple | Jessi | 0 | has tom |
| apple | Tom | 1 | has tom |
| fb | Alex | 0 | no tom |
| fb | Nick | 0 | no tom |
方法3:合并成单语句(无需中间表)
如果不想创建中间表,可以把两步逻辑合并成一个语句,避免额外的表操作:
select *, case when max(case when people = 'Tom' then 1 else 0 end) over (partition by company) = 1 then 'has tom' else 'no tom' end as find_tom from t1;
这个语句和你的两步方案逻辑完全一致,但更高效。
内容的提问来源于stack exchange,提问作者YJZ
相关产品推荐
相关产品推荐

