我有一个交易表提供: 一个字母数字 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。
我已经考虑过使用一些辅助列可能会做到这一点。我的思考过程是这样的:
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
子句将是一个很好的调用,但我不确定考虑到该数据库的大小,这是否是正确的调用。
感谢您的帮助。
编辑:我应该提一下,真实数据可能在时间列中包含重复项。交易可能同时发生,因为它只精确到秒。
对你的尝试做一个小调整就可以了。使用相应的窗口函数将您的总和变成“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
子句:它只是为了可视化目的。