SQL无需子查询提取sales表不满足双条件的数据方法咨询
问题分析与解决方案
1. 改写语句结果不符合预期的原因
两种写法的过滤逻辑完全不同:
- 原始子查询的逻辑是按sales_id全局过滤:只要某个
sales_id存在任意一条满足「sales_percentage<.02且sales_region in ('SW','SE')」的记录,就直接排除该sales_id对应的所有行,无论其他行是否满足条件。 - 你改写的语句逻辑是按单行过滤:仅排除当前行满足上述两个条件的记录,同一个
sales_id下不满足条件的其他行仍然会保留。
举个简单的例子:如果sales_id=1有两条记录,一条满足过滤条件、一条不满足,原始子查询会把这两条记录全部排除,而改写的语句只会排除满足条件的那一条,保留另一条,自然结果和预期不符。
2. 不使用子查询的最优实现方式
推荐使用自反连接的写法,性能比NOT IN更稳定,还可以避免NOT IN遇到子查询返回空值时结果全空的经典问题,写法如下:
SELECT s1.* FROM sales s1 LEFT JOIN sales s2 ON s1.sales_id = s2.sales_id AND s2.sales_percentage < 0.02 AND s2.sales_region IN ('SW','SE') WHERE s2.sales_id IS NULL;
逻辑说明
将sales表和自身做左连接,连接条件为两侧sales_id一致,且右表s2的行符合要排除的过滤规则,最后只保留右表匹配不到的行,就是所有没有任何一条符合排除规则的sales_id对应的全量数据,和你原始的子查询逻辑完全一致。
如果你使用的数据库支持QUALIFY语法(如Snowflake、BigQuery、PostgreSQL 15及以上版本),还可以用更简洁的窗口函数写法,无需嵌套:
SELECT * FROM sales QUALIFY SUM(CASE WHEN sales_percentage < 0.02 AND sales_region IN ('SW','SE') THEN 1 ELSE 0 END) OVER(PARTITION BY sales_id) = 0;
内容的提问来源于stack exchange,提问作者Drummerpolo15
相关产品推荐
相关产品推荐

