MySQL筛选多列全为0的ID 排除含非零值ID的所有行
问题背景
需要对数据表做子集筛选:仅保留var1、var2、var3、var4四个列在同ID所有记录中取值均为0的ID对应的全部行,同ID存在多条记录的,需保留该ID下所有行(含重复行)。
原有SQL写法无法满足需求,会错误返回存在非0值的ID下单条var列全0的记录,比如示例中ID为92403的第一条记录就属于错误返回内容,该ID下其他记录存在非0值,本应被整体排除。
错误写法复现
select id, group, year, var1, var2, var3, var4 from tbl where var1 = 0 and var2 = 0 and var3 = 0 and var4 = 0;
错误原因:该逻辑为逐行判断当前行是否满足var列全0,没有按ID维度校验该ID下所有记录是否都满足var全0的要求,因此会漏排除同ID下存在非0值的记录。
注意:group是SQL保留关键字,作为列名使用时建议加转义符(如MySQL用反引号、PostgreSQL用双引号包裹)避免语法错误。
正确实现方案
通用兼容写法(支持所有SQL版本)
先通过分组聚合筛选出符合要求的ID(即ID下所有行的var1-var4全为0),再匹配这些ID查询所有对应记录:
select id, `group`, year, var1, var2, var3, var4 from tbl where id in ( select id from tbl group by id having max(var1) = 0 and min(var1) = 0 and max(var2) = 0 and min(var2) = 0 and max(var3) = 0 and min(var3) = 0 and max(var4) = 0 and min(var4) = 0 );
如果业务上确认var1-var4的取值均为非负数,可以简化having后的判断逻辑,仅判断四个列的组内最大值为0即可:非负数列最大值为0即可证明该列组内所有值均为0。
窗口函数写法(支持MySQL8.0+、PostgreSQL、SQL Server等支持窗口函数的数据库)
通过窗口函数按ID分区计算各var列的组内最大值,直接筛选所有组内最大值全为0的记录,无需二次关联查询:
select id, `group`, year, var1, var2, var3, var4 from ( select *, max(var1) over(partition by id) as max_v1, max(var2) over(partition by id) as max_v2, max(var3) over(partition by id) as max_v3, max(var4) over(partition by id) as max_v4 from tbl ) t where max_v1 = 0 and max_v2 = 0 and max_v3 = 0 and max_v4 = 0;
内容的提问来源于stack exchange,提问作者PeterKW
相关产品推荐
相关产品推荐

