求助:按月份和年龄组统计唯一客户Coverage总和的SQL实现
按月份和年龄组统计唯一客户Coverage总和的SQL解决方案
需求描述
按月份(cmpgn_mth)和年龄组(age_band)统计唯一客户的coverage总和,同一客户同一月份多次出现时,仅计一次该客户对应的coverage值(若同一客户同一月份存在多个coverage值,取最大值,例如既有0又有1时计1)。
原始数据表(mytable)
| cust_id | cmpgn_mth | age_band | coverage |
|---|---|---|---|
| 1 | 202309 | 18-34 | 1 |
| 1 | 202309 | 18-34 | 1 |
| 1 | 202308 | 18-34 | 1 |
| 2 | 202309 | 35-45 | 1 |
| 2 | 202308 | 35-45 | 0 |
| 2 | 202308 | 35-45 | 1 |
| 3 | 202309 | 18-34 | 1 |
| 3 | 202308 | 18-34 | 1 |
| 3 | 202308 | 18-34 | 1 |
预期结果
| cmpgn_mth | age_band | coverage |
|---|---|---|
| 202309 | 18-34 | 2 |
| 202309 | 35-45 | 1 |
| 202308 | 18-34 | 2 |
| 202308 | 35-45 | 1 |
尝试的错误SQL
SELECT cmpgn_mth, age_band, SUM(cross_sell) OVER (PARTITION BY cust_id) AS coverage FROM mytable GROUP BY cmpgn_mth, age_band, cross_sell, cust_id
错误原因
- 字段名错误:语句中使用了不存在的
cross_sell字段,应为coverage; - 逻辑错误:窗口函数结合GROUP BY的方式无法实现去重聚合,反而保留了客户的多条重复记录,导致统计结果重复计算。
正确SQL实现方案
方案一:先去重再聚合(通用可靠)
先对每个客户、月份、年龄组的coverage取最大值(确保同一客户同一月份仅保留有效覆盖值),再按月份和年龄组求和:
SELECT cmpgn_mth, age_band, SUM(cust_coverage) AS coverage FROM ( -- 第一步:获取每个客户每个月份每个年龄组的唯一有效coverage值 SELECT cust_id, cmpgn_mth, age_band, MAX(coverage) AS cust_coverage FROM mytable GROUP BY cust_id, cmpgn_mth, age_band ) AS unique_cust_data GROUP BY cmpgn_mth, age_band ORDER BY cmpgn_mth DESC, age_band;
方案二:简化写法(限特定场景)
如果同一客户同一月份的coverage值全部相同(无0和1共存的情况),可以用以下简化写法:
SELECT cmpgn_mth, age_band, COUNT(DISTINCT cust_id) * MAX(coverage) AS coverage FROM mytable GROUP BY cmpgn_mth, age_band;
注:方案二更简洁,但仅当同一客户同一月份的
coverage值无冲突时有效,建议优先使用方案一。
内容的提问来源于stack exchange,提问作者xboraxe
相关产品推荐
相关产品推荐

