聚合依赖值场景:如何筛选同时含email和sms docType的发票对应行
筛选同时存在两类docType的发票全记录实现方法
现有如下结构的业务表,需要取出所有**同时存在docType = 'email'和docType = 'sms'**的Invoice_ID对应的全部行数据。
示例表原始数据
| ID | Invoice_ID | docType |
|---|---|---|
| 1 | 100 | |
| 2 | 100 | sms |
| 3 | 200 | |
| 4 | 200 | |
| 5 | 300 | sms |
方案1:子查询+分组聚合(兼容性最高,支持所有主流SQL数据库)
SELECT * FROM 你的表名 WHERE Invoice_ID IN ( SELECT Invoice_ID FROM 你的表名 WHERE docType IN ('email', 'sms') GROUP BY Invoice_ID HAVING COUNT(DISTINCT docType) = 2 );
实现逻辑:内层子查询先按Invoice_ID分组,通过HAVING COUNT(DISTINCT docType) = 2过滤出同时包含两类指定docType的发票ID,外层查询直接匹配这些ID拉取全量行即可。
方案2:窗口函数实现(性能更优,适合大数据量表)
WITH invoice_flag AS ( SELECT *, COUNT(DISTINCT CASE WHEN docType IN ('email','sms') THEN docType END) OVER(PARTITION BY Invoice_ID) AS type_cnt FROM 你的表名 ) SELECT ID, Invoice_ID, docType FROM invoice_flag WHERE type_cnt = 2;
实现逻辑:通过窗口函数直接对每个发票ID下的docType类型做去重计数,不需要二次扫表,执行效率更高,支持MySQL 8.0+/PostgreSQL/SQL Server等支持窗口函数的数据库。
最终运行结果
两种方案执行后输出的结果一致:
| ID | Invoice_ID | docType |
|---|---|---|
| 1 | 100 | |
| 2 | 100 | sms |
补充说明:如果需要保留同一Invoice_ID下除了email、sms之外其他类型的docType,上述代码无需修改;如果仅需要保留email和sms两类记录,在外层查询的WHERE条件中追加
docType IN ('email', 'sms')即可。
内容的提问来源于stack exchange,提问作者FeMn
相关产品推荐
相关产品推荐

