SQL:为事务表中的每个类别选择运行总计,按日期排序

问题描述 投票:0回答:1

我有一个交易表提供: 一个字母数字 PK、一个时间戳、一个 user_id、一个输入/输出字符串列和一个数量列。

id          time                  user_id   io    amount
38hw        2019-10-18 18:35:09   2         in     1
nv49        2019-10-18 18:35:10   3         in    50
83ha        2019-10-18 18:35:11   5         in     2
ja03        2019-10-18 18:35:12   4         out    2
019c        2019-10-18 18:35:13   1         out   75
ac5r        2019-10-18 18:35:14   3         in    20
as30        2019-10-18 18:35:15   3         in     3
34ds        2019-10-18 18:35:16   4         in     7
12my        2019-10-18 18:35:17   2         in    50
dk20        2019-10-18 18:35:18   4         in    50
sk18        2019-10-18 18:35:19   1         in     7
am35        2019-10-18 18:35:20   2         in     3
mc92        2019-10-18 18:35:21   2         out    8
alov        2019-10-18 18:35:22   3         in     4
ap34        2019-10-18 18:35:23   1         out    6

我正在尝试创建另一个列,该列在每次出现时提供该 user_id 的运行总计。这些 user_id 最初不会显示为 0,因此必须在它们第一次出现时假定为 0。

我已经考虑过使用一些辅助列可能会做到这一点。我的思考过程是这样的:

  • 创建一列以指示 user_id 在
    time
    列中的值之前出现的次数。也许叫
    occurence_num
    专栏
  • 创建一个使数量更易于使用的列,例如
    (case when io='in' then amount else -1*amount end) as balance_adjust
  • user_id
    和(在每一行上)
    sum()
    所有
    balance_adjust
    值,其中
    occurence_num
    小于当前记录。

虽然我很难测试这些想法。我在一个相当大的数据库中工作,SQLite 有 2200 万行。该表可以根据需要更改/更新。它以这种方式存储,有利于保持 ETL 尽可能简单,因为有大量数据要提取,还有大量页面要提取。我想要的输出看起来像这样:

id          time                  user_id   io    amount    running_total
38hw        2019-10-18 18:35:09   2         in     1         1
nv49        2019-10-18 18:35:10   3         in    50        50
83ha        2019-10-18 18:35:11   5         in     2         2
ja03        2019-10-18 18:35:12   4         out    2        -2
019c        2019-10-18 18:35:13   1         out   75       -75
ac5r        2019-10-18 18:35:14   3         in    20        70
as30        2019-10-18 18:35:15   3         in     3        73
34ds        2019-10-18 18:35:16   4         in     7         5
12my        2019-10-18 18:35:17   2         in    50        51
dk20        2019-10-18 18:35:18   4         in    50        55
sk18        2019-10-18 18:35:19   1         in     7       -68
am35        2019-10-18 18:35:20   2         in     3        54
mc92        2019-10-18 18:35:21   2         out    8        46
alov        2019-10-18 18:35:22   3         in     4        77
ap34        2019-10-18 18:35:23   1         out    6       -74

我这样可以得到每个用户的总和,但是需要几分钟:

SELECT 
    user_id,
    sum(case when io='in' then amount else -1*amount end) as balance
FROM 
    transactions 
GROUP BY
    user_id

我认为对此进行扩展,

OVER
/
PARTITION
子句将是一个很好的调用,但我不确定考虑到该数据库的大小,这是否是正确的调用。

感谢您的帮助。

编辑:我应该提一下,真实数据可能在时间列中包含重复项。交易可能同时发生,因为它只精确到秒。

sql sqlite group-by cumulative-sum
1个回答
0
投票

对你的尝试做一个小调整就可以了。使用相应的窗口函数将您的总和变成“running sum”就足够了,它将通过按用户分区和按时排序来计算运行量。

如果你有平局,你可以依靠按 id 排序,这将打破平局并使总和正确计算。

SELECT *,
       SUM(CASE WHEN io = 'in' 
                THEN amount 
                ELSE -amount 
           END) OVER(PARTITION BY user_id ORDER BY time, id) as balance
FROM transactions 
ORDER BY time

输出:

id 时间 user_id io 数量 平衡
38hw 2019-10-18 18:35:09 2 1 1
nv49 2019-10-18 18:35:10 3 50 50
83公顷 2019-10-18 18:35:11 5 2 2
ja03 2019-10-18 18:35:12 4 2 -2
019c 2019-10-18 18:35:13 1 75 -75
ac5r 2019-10-18 18:35:14 3 20 70
as30 2019-10-18 18:35:15 3 3 73
34ds 2019-10-18 18:35:16 4 7 5
12我的 2019-10-18 18:35:17 2 50 51
dk20 2019-10-18 18:35:18 4 50 55
sk18 2019-10-18 18:35:19 1 7 -68
am35 2019-10-18 18:35:20 2 3 54
mc92 2019-10-18 18:35:21 2 8 46
阿洛夫 2019-10-18 18:35:22 3 4 77
ap34 2019-10-18 18:35:23 1 6 -74

在这里查看演示.

注意:不需要最后一个

ORDER BY
子句:它只是为了可视化目的。

© www.soinside.com 2019 - 2024. All rights reserved.