Oracle SQL筛选:仅保留全年各月均有记录的账户
解决方法:筛选有12个月账单历史的账户
针对你的需求,分两种常见场景给出具体实现,同时纠正你之前思路的问题:
一、筛选有至少12个不同月份账单的账户(非连续也可)
你之前用HAVING COUNT(date) = 12效果不对,大概率是因为同一个账户在某个月有多条账单记录,COUNT(date)会把这些重复记录都算进去,导致统计的是账单条数而非月份数。正确的做法是统计去重后的月份数量:
方法1:先分组统计再关联原表
WITH account_month_stats AS ( SELECT account_id, -- 把日期截断到月份,确保同一个月的记录只算一次 COUNT(DISTINCT DATE_TRUNC('month', bill_date)) AS total_bill_months FROM monthly_bills GROUP BY account_id ) -- 关联原表获取符合条件的所有账单记录 SELECT mb.* FROM monthly_bills mb JOIN account_month_stats ams ON mb.account_id = ams.account_id WHERE ams.total_bill_months >= 12;
方法2:直接用HAVING筛选账户
如果只需要获取符合条件的账户ID,不需要完整账单记录,可以简化:
SELECT account_id, COUNT(DISTINCT DATE_TRUNC('month', bill_date)) AS total_bill_months FROM monthly_bills GROUP BY account_id HAVING COUNT(DISTINCT DATE_TRUNC('month', bill_date)) >= 12;
二、筛选有连续12个月账单记录的账户
如果你的需求是账户必须有连续12个月的账单(比如最近连续12个月,或任意连续12个月),可以用ROW_NUMBER()配合分组筛选,这里关键是要给每个账户单独排序(你之前的问题就是没加PARTITION BY account_id,导致全局排序):
WITH unique_monthly_bills AS ( -- 先去重同一个账户同一个月的重复账单 SELECT DISTINCT account_id, DATE_TRUNC('month', bill_date) AS bill_month FROM monthly_bills ), ordered_months AS ( SELECT account_id, bill_month, -- 按账户分组,对账单月份从小到大排序 ROW_NUMBER() OVER (PARTITION BY account_id ORDER BY bill_month) AS rn FROM unique_monthly_bills ), continuous_groups AS ( SELECT account_id, bill_month, -- 连续的月份会生成相同的group_key bill_month - INTERVAL '1 month' * rn AS group_key FROM ordered_months ) -- 找出每个连续组中月份数>=12的账户 SELECT DISTINCT account_id FROM continuous_groups GROUP BY account_id, group_key HAVING COUNT(*) >= 12;
解释:通过PARTITION BY account_id让ROW_NUMBER()按每个账户单独排序,然后用月份减去排序号乘以1个月,连续的月份会得到相同的group_key,最后统计每个group_key下的月份数,就能找出有连续12个月账单的账户。
对你之前思路的纠正
ROW_NUMBER()的问题:必须加上PARTITION BY account_id,才能让排序在每个账户内部进行,而不是全局排序。COUNT(date)的问题:要统计月份数而非账单条数,必须用COUNT(DISTINCT 月份字段),避免同一个月的多条账单干扰统计结果。
内容的提问来源于stack exchange,提问作者LSP8S
相关产品推荐
相关产品推荐

