【问题标题】:SQL to Generate Periodic Snapshots from Transactions TableSQL 从事务表生成定期快照
【发布时间】:2014-12-06 01:42:17
【问题描述】:

我正在尝试在事后从数据库的事务表中创建定期快照视图。事务表有以下字段:

  • account_id(外键)
  • event_id
  • status_dt
  • status_cd

每次帐户在应用程序中更改状态时,都会在具有新状态的事务表中添加一个新行。我想生成一个视图,显示每个日期按状态显示的帐户数;它应该有以下字段:

  • snapshot_dt
  • status_cd
  • count_of_accounts

这将获得任何一天的计数,但不是所有天的计数:

SELECT status_cd, COUNT(account_id) AS count_of_accounts
FROM transactions
JOIN (
      SELECT account_id, MAX(event_id) AS event_id
      FROM transactions
      WHERE status_dt <= DATE '2014-12-05') latest
USING (account_id, event_id)
GROUP BY status_cd

谢谢!

【问题讨论】:

  • 您使用的是什么数据库?我猜是 Oracle,但你应该明确地使用问题上的标签。
  • 是的甲骨文。谢谢你的提示!我主要发现将专有扩展从一种 SQL 转换为另一种 SQL 并不难,但最好不必这样做。

标签: sql oracle data-warehouse


【解决方案1】:

好的,这很难解释。

在每个状态的每个日期,您应该计算两个值:

  • 以该状态开始的客户数量。
  • 以该状态离开的客户数量。

第一个值很简单。它只是按日期和状态汇总的交易。

第二个值几乎同样简单。您获得上一个状态代码并计算该状态代码在该日期“离开”的次数。

那么,关键是第一个值的累积和减去第二个值的累积和。

我承认以下代码未经测试(如果您有 SQL Fiddle,我很乐意对其进行测试)。但这就是结果查询的样子:

select status_dte, status_cd,
       (sum(inc_cnt) over (partition by status_cd order by status_dt) -
        sum(dec_cnt) over (partition by status_cd order by status_dt)
       ) as dateamount
from ((select t.status_dt, t.status_cd, count(*) as inc_cnt, 0 as dec_cnt
       from transactions t
       group by t.status_dt, t.status_cd 
      ) union all
      (select t.status_dt, prev_status_cd, 0, count(*)
       from (select t.*
                    lag(t.status_cd) over (partition by t.account_id order by status_dt) as prev_status_cd
             from transactions t
            ) t
       where prev_status_cd is null
       group by t.status_dt, prev_status_cd
      ) 
     ) t;

如果您有一个或多个状态没有变化的日期并且您希望将这些状态包含在输出中,那么上述查询需要使用 cross join 首先创建行在结果集中。目前尚不清楚这是否是一项要求,因此我将省略该复杂性。

【讨论】:

  • 太棒了,非常感谢!您的代码中有一个错字(应该是prev_status_cd is **not** null),但除此之外,它的效果很好。
  • 我想要没有状态变化的日期的快照。有没有比这更优雅的方法:SELECT DISTINCT status_dte, status_cd, (SUM(inc_cnt) OVER (PARTITION BY status_cd ORDER BY status_dte) - SUM(dec_cnt) OVER (PARTITION BY status_cd ORDER BY status_dte)) AS dateamount FROM (( SELECT status_dte, status_cd, 0 AS inc_cnt, 0 AS dec_cnt FROM ( SELECT DISTINCT status_cd FROM transactions) CROSS JOIN ( SELECT DISTINCT status_dte FROM transactions)) UNION ALL ( ...
猜你喜欢
  • 1970-01-01
  • 2022-12-10
  • 2015-11-22
  • 1970-01-01
  • 1970-01-01
  • 2014-05-20
  • 1970-01-01
  • 2017-02-14
  • 1970-01-01
相关资源
最近更新 更多