需要在 SQL 中计算日期之间滚动的 30 天期间内的操作数

Posted

技术标签:

【中文标题】需要在 SQL 中计算日期之间滚动的 30 天期间内的操作数【英文标题】:Need to count the number of operations within a rolling 30-day period between dates in SQL 【发布时间】:2021-09-09 12:37:33 【问题描述】:

我有一个表 Mytable,其中 id - 成员的 id 和 dp_id - 部门的 id:

    date                     id      dp_id
  2020-11-14 01:22:10.260  300000  002    
  2020-11-14 01:41:13.260  352575  001
  2020-11-14 16:39:31.910  352575  001
  2020-11-14 23:39:52.510  352575  001
  2020-11-14 00:00:00.260  300000  002
  2020-11-15 00:01:20.710  352575  001
  2020-11-15 01:00:43.600  352575  001
  2020-11-15 13:41:19.410  352575  002

如果id - dp_id (352575 - 001) 对的第一次交易后 30 天内的操作数超过 5,则应标记为 over_lim

例如,如果id-dp_id 的第一个操作是在01: 41: 13.260,因此,在接下来的 30 天内,我需要计算那里有多少操作,如果有超过5.

2020-11-15 01: 00: 43.600 352575 001 操作将是 id-dp_id 对的第一个条目的第 5 个操作,因此我们将其标记为 over_lim。以此类推 - 我们需要获取该期间的第一笔交易,然后查看接下来 30 天的交易量。

预期输出,其中tr_count - 每对交易的计数id-dp_idover_lim- 我们的标记,这是一个超限交易(>=5):

  date                     id      dp_id tr_count over_lim
2020-11-14 01:22:10.260  300000  002   1        False
2020-11-14 01:41:13.260  352575  001   1        False
2020-11-14 16:39:31.910  352575  001   2        False
2020-11-14 23:39:52.510  352575  001   3        False
2020-11-14 00:00:00.260  300000  002   2        False
2020-11-15 00:01:20.710  352575  001   4        False
2020-11-15 01:00:43.600  352575  001   5        True
2020-11-15 13:41:19.410  352575  002   1        False

【问题讨论】:

为什么最后一行没有被标记?它是大于 5 的第 6 个。 @GordonLinoff 因为它是一个新的 id-dp_id 对 352575 - 002,所以它是它的第一个条目 【参考方案1】:

您可以将count(*)range 一起使用:

select t.*,
       count(*) over (partition by id
                      order by date
                      range between interval '30' day preceding and interval '0' day preceding
                     ) as tr_count,
       (case when count(*) over (partition by id
                                 order by date
                                 range between interval '30' day preceding and interval '0' day preceding
                           ) >= 5
             then 'true' else 'false'
        end) as over_lim
from t;

如果您只希望第五个是'true',则将>= 5 更改为= 5

Here 是一个 dbfiddle。

【讨论】:

我认为使用间隔'-30'前一天和当前行之间的范围会更好 @GordonLinoff 我没有得到 tr_count 列中每个条目的正确累积总数,我如何更改此脚本以达到上述预期输出中的结果 @Kurasao 。 . .我修正了错别字。我认为它现在会起作用。不过,我不确定你想要>= 5 还是= 5 @GordonLinoff 看起来它与 row_number() 一起使用效果更好,但是当我在 tr_count 应用它而不是 count(*) 时,我得到了缺少右括号的错误。同样在您的虚拟数据库示例中,您得到了正确答案,但在我的海量表格中,它只是将每对 id 的总计数 - tr_count 中的 dp_id 用于 ex 6,而不是 1、2、3 等 @Kurasao 。 . . row_number() 不接受 range 窗框规范。【参考方案2】:

类似的方法给了我你想要的结果(我将字段 date 更改为 date_oper

SQL> with t as
  2   (
  3     select to_date('2020-11-14 01:22:10','yyyy-mm-dd hh24:mi:ss') date_oper, 300000 id, '002' dp_id from dual union all
  4     select to_date('2020-11-14 01:41:13','yyyy-mm-dd hh24:mi:ss') date_oper, 352575 id, '001' dp_id from dual union all
  5     select to_date('2020-11-14 16:39:31','yyyy-mm-dd hh24:mi:ss') date_oper, 352575 id, '001' dp_id from dual union all
  6     select to_date('2020-11-14 23:39:52','yyyy-mm-dd hh24:mi:ss') date_oper, 352575 id, '001' dp_id from dual union all
  7     select to_date('2020-11-14 00:00:00','yyyy-mm-dd hh24:mi:ss') date_oper, 300000 id, '002' dp_id from dual union all
  8     select to_date('2020-11-15 00:01:20','yyyy-mm-dd hh24:mi:ss') date_oper, 352575 id, '001' dp_id from dual union all
  9     select to_date('2020-11-15 01:00:43','yyyy-mm-dd hh24:mi:ss') date_oper, 352575 id, '001' dp_id from dual union all
 10     select to_date('2020-11-15 13:41:19','yyyy-mm-dd hh24:mi:ss') date_oper, 352575 id, '002' dp_id from dual
 11   )
 12   select t.*,
 13   count(*) over (partition by id, dp_id order by date_oper range between interval '30' day preceding and current row) as tr_count,
 14   (case when count(*) over (partition by id, dp_id order by date_oper range between interval '30' day preceding and current row) >= 5
 15    then 'true' else 'false'
 16    end) as over_lim
 17*  from t order by date_oper
SQL> /

DATE_OPER                   ID DP_   TR_COUNT OVER_
------------------- ---------- --- ---------- -----
2020-11-14 00:00:00     300000 002          1 false
2020-11-14 01:22:10     300000 002          2 false
2020-11-14 01:41:13     352575 001          1 false
2020-11-14 16:39:31     352575 001          2 false
2020-11-14 23:39:52     352575 001          3 false
2020-11-15 00:01:20     352575 001          4 false
2020-11-15 01:00:43     352575 001          5 true
2020-11-15 13:41:19     352575 002          1 false

8 rows selected.

你可以在这里查看

db<>fiddle

【讨论】:

看起来它与 row_number() 一起使用效果更好,但是当我在 tr_count 应用它而不是 count(*) 时,我得到了缺少右括号的错误。同样在您的虚拟数据库示例中,您得到了正确答案,但在我的海量表格中,它只是将每对 id 的总计数 - tr_count 中的 dp_id 用于 ex 6,而不是 1、2、3 等 @Kurasao, row_number() 不承认范围,所以它不能工作。关于结果,也许您应该更好地解释所需的输出,据我所见,我的查询得到了您按预期放置的输出。您可以编辑问题并添加更多行以更好地理解您期望的逻辑吗? 刚刚解决了我的问题,应该使用时间戳日期列 11/11/2020 6:13:45,000000 ,而不是日期 11/11/2020,它会导致总数。非常感谢!

以上是关于需要在 SQL 中计算日期之间滚动的 30 天期间内的操作数的主要内容,如果未能解决你的问题,请参考以下文章

如何根据滚动的 30 天窗口 SQL 选择行

在 where 子句中从当前日期减去 30 天

SQL数据库怎么查询,between 当前日期 and 当前日期前30天,之间的数据

如何用excel计算月份和天数?

如何计算没有任何一个月的 31 日的 2 个日期之间的天数

使用 T-SQL 滚动 DAU、MAU