如何在 Oracle SQL 中获得过去三天每天的滚动不同计数?

Posted

技术标签:

【中文标题】如何在 Oracle SQL 中获得过去三天每天的滚动不同计数?【英文标题】:How to have the rolling distinct count of each day for past three days in Oracle SQL? 【发布时间】:2018-10-21 09:41:42 【问题描述】:

我搜索了很多,但我还没有找到解决方案。让我通过示例数据和我想要的输出来解释我的问题。 样本数据:

datetime           customer
----------         --------
2018-10-21 09:00   Ryan
2018-10-21 10:00   Sarah
2018-10-21 20:00   Sarah
2018-10-22 09:00   Peter
2018-10-22 10:00   Andy
2018-10-23 09:00   Sarah
2018-10-23 10:00   Peter
2018-10-24 10:00   Andy
2018-10-24 20:00   Andy

我想要的输出是过去三天相对于每一天拥有不同数量的客户:

trunc(datetime)   progressive count distinct customer
---------------   -----------------------------------
2018-10-21         2
2018-10-22         4
2018-10-23         4
2018-10-24         3

解释:对于 21th,因为我们只有 Ryan 和 Sarah,所以计数是 2(也因为我们在 21th 之前没有其他记录);对于 22 日,安迪和彼得被添加到不同的列表中,所以它是 4。对于 23 日,没有添加新客户,所以它将是 4。对于 24 日,但是,因为我们只应该考虑过去 3 天(根据业务逻辑),我们应该只取 24、23 和 22;所以不同的客户将是莎拉、安迪和彼得。所以计数是 3。

我相信它被称为累进计数,或移动计数或滚动计数。但我无法在 Oracle 11g SQL 中实现它。显然,使用 PL-SQL 编程(存储过程/函数)很容易。但是,最好我想知道我们是否可以通过单个 SQL 查询来获得它。

【问题讨论】:

【参考方案1】:

你似乎想要的是:

select date,
       count(distinct customer) over (order by date rows between 2 preceding and current row)
from (select distinct trunc(datetime) as date, customer
      from t
     ) t
group by date;

但是,Oracle 不支持带有count(distinct) 的窗口框架。

一种相当蛮力的方法是关联子查询:

select date,
       (select count(distinct t2.customer)
        from t t2
        where t2.datetime >= t.date - 2
       ) as running_3
from (select distinct trunc(datetime) as date
      from t
     ) t;

这应该在少数日期具有合理的性能。随着日期数量的增加,性能会线性下降。

【讨论】:

以上是关于如何在 Oracle SQL 中获得过去三天每天的滚动不同计数?的主要内容,如果未能解决你的问题,请参考以下文章

Oracle 取过去一个小时每分钟的数据应该如何写sql?

sql 语句:一个字段,连续几天值大于0,获得天数 怎么解决的?请教

oracle第三天

如何使用 sql 中的每 n 行(例如第 24、48 和 72 行)计算移动平均值?

选择一个Id每天的最新记录 - Oracle pl sql

sql 语句:一个字段,连续几天值大于0,获得天数 怎么解决的?请教