使用DENSE_RANK模拟COUNT(DISTINCT)遇异常,求解决方案
解决窗口函数统计客户下单次数的问题
首先,咱们来拆解一下你遇到的问题:你用DENSE_RANK()组合的方式模拟统计客户总下单次数,但当客户同一天有多笔订单时,所有同天订单的排名都会相同,导致计算结果出错。比如两笔同一天的订单,升序和降序的DENSE_RANK都是1,相加减1后得到1,而不是你预期的2。
关于ROW_NUMBER()能否解决这个问题?
答案是可以,但它并不是最简洁的方案。
ROW_NUMBER()会给每一行分配唯一的序号,哪怕订单日期完全相同。假设客户同一天有2笔订单:
- 升序排序的
ROW_NUMBER()会得到1, 2 - 降序排序的
ROW_NUMBER()会得到2, 1 - 两者相加再减1:
1+2-1=2、2+1-1=2,刚好符合你想要的2,2结果
不过要注意:当Date_Created完全相同时,ROW_NUMBER()的排序顺序依赖于数据库的默认规则(比如主键ID的顺序),但这不会影响最终的计算结果——因为每笔订单的升序序号+降序序号之和始终等于总订单数+1,减1后就是正确的总订单数。
更简洁的最优方案
其实你的需求完全不需要用Rank类函数,直接用COUNT(*) OVER()窗口函数就能搞定:
COUNT(*) OVER (PARTITION BY CustomerEmail) AS AmountOrdersOverRangeByCustomer
这个语句会直接统计每个客户的总订单数,并把这个数值返回给该客户的每一行订单数据。不管订单是否在同一天,结果都会是正确的总下单次数,完美解决你遇到的问题。
额外说明(如果你的需求是按天去重统计)
如果你的真实需求是统计客户下单的不同天数(而不是总订单数),那可以先按客户和日期分组,再用窗口函数统计:
-- 先子查询按天去重 WITH DailyOrders AS ( SELECT DISTINCT CustomerEmail, Date_Created FROM YourOrdersTable ) SELECT o.*, COUNT(*) OVER (PARTITION BY o.CustomerEmail) AS UniqueOrderDays FROM YourOrdersTable o JOIN DailyOrders d ON o.CustomerEmail = d.CustomerEmail
但根据你的描述,你想要的是总下单次数,所以第一种方案就足够了。
内容的提问来源于stack exchange,提问作者Natan
相关产品推荐
相关产品推荐

