假设:
- 我们不能挖掘或接收小于 0。
- 我们不能转移或损失我们没有的金额。
不清楚 FIFO 行为涉及什么。一个更好的测试用例可能会有所帮助。
这是一个更新的测试用例,包含上述数据,然后是一个稍大的数据集,以及一个尝试引入 FIFO 逻辑的解决方案:
The updated test case with more data and FIFO logic
以下解决方案使用一些计算来完成这项工作。
在cte1 中我们得出:
-
run_mined - type = 102(挖掘量)的运行总和(按 id 顺序)
-
tot_xfer - 类型总数 = 103(已转移金额)
-
tot_lost - 类型总数 = 104(丢失数量)
那么由于转移的金额只能从挖出的金额中扣除,我们接下来在cte2 中执行此操作,调整挖出的行数。
如果总转移总和大于挖掘行的当前运行总和,则该金额减少到 0。我们已经转移了所有这些金额。
如果总转帐总和不大于当前挖掘数据的运行总和,我们扣除转帐金额,不大于该行当前已挖掘的金额。
任何后续开采的行都不会被触及,因为没有进一步的转移。
在cte1b 中,我们计算run2_in,这是mined 和received 金额的更新运行总和。请注意,mined 的金额已在 cte2 中进行了调整。
cte3 现在执行类似于cte2 的计算,但这次根据剩余的lost 总量按FIFO 顺序调整received 和mined 两种类型(101 和102)。
最后,我们只选择完全调整后的received 和mined 行来显示,以及相应的id 来指示执行FIFO 操作的顺序。
SQL:
WITH cte1 AS (
SELECT a.*
, SUM(CASE WHEN (transaction_typeid = 102) THEN 1 ELSE 0 END * amount) OVER (ORDER BY id) AS run_mined
, SUM(CASE WHEN (transaction_typeid = 103) THEN 1 ELSE 0 END * amount) OVER () AS tot_xfer
, SUM(CASE WHEN (transaction_typeid = 104) THEN 1 ELSE 0 END * amount) OVER () AS tot_lost
FROM cryptotransactionledger a
ORDER BY id
)
, cte2 AS (
SELECT a.id, a.transaction_typeid, a.transaction_name
, CASE WHEN transaction_typeid <> 102 THEN amount
WHEN run_mined <= ABS(tot_xfer ) THEN 0
WHEN run_mined + tot_xfer >= amount THEN amount
ELSE run_mined + tot_xfer
END AS amount
, run_mined
, tot_xfer
, tot_lost
, amount AS amount1
FROM cte1 a
)
, cte1b AS (
SELECT a.*
, SUM(CASE WHEN (transaction_typeid IN (101, 102)) THEN 1 ELSE 0 END * amount) OVER (ORDER BY id) AS run2_in
FROM cte2 a
)
, cte3 AS (
SELECT a.id, a.transaction_typeid, a.transaction_name
, CASE WHEN transaction_typeid NOT IN (101, 102) THEN amount
WHEN run2_in <= ABS(tot_lost ) THEN 0
WHEN run2_in + tot_lost >= amount THEN amount
ELSE run2_in + tot_lost
END AS amount
, run_mined
, tot_xfer
, tot_lost
, run2_in
, amount1
, amount AS amount2
FROM cte1b a
)
SELECT id, transaction_name, amount
FROM cte3
WHERE transaction_typeid IN (101, 102)
ORDER BY id
;
使用来自原始问题的数据的结果(平凡的案例):
+----+------------------+--------+
| id | transaction_name | amount |
+----+------------------+--------+
| 1 | bitcoin-received | 0 |
| 2 | bitcoin-mined | 10 |
+----+------------------+--------+
在更新的小提琴中,提供了一个包含更多数据的示例:
新数据:
create table cryptotransactionledger as
select 1 as id, 101 as transaction_typeid, 'bitcoin-received' as transaction_name, 5 as amount from dual union all
select 2 as id, 102 as transaction_typeid, 'bitcoin-mined' as transaction_name, 20 as amount from dual union all
select 3 as id, 103 as transaction_typeid, 'bitcoin-transferred' as transaction_name, -5 as amount from dual union all
select 4 as id, 104 as transaction_typeid, 'bitcoin-lost' as transaction_name, -10 as amount from dual union all
select 5 as id, 101 as transaction_typeid, 'bitcoin-received' as transaction_name, 55 as amount from dual union all
select 15 as id, 102 as transaction_typeid, 'bitcoin-mined' as transaction_name, 8 as amount from dual union all
select 16 as id, 102 as transaction_typeid, 'bitcoin-mined' as transaction_name, 20 as amount from dual union all
select 17 as id, 102 as transaction_typeid, 'bitcoin-mined' as transaction_name, 30 as amount from dual union all
select 18 as id, 103 as transaction_typeid, 'bitcoin-transferred' as transaction_name, -5 as amount from dual union all
select 19 as id, 103 as transaction_typeid, 'bitcoin-transferred' as transaction_name, -5 as amount from dual union all
select 20 as id, 103 as transaction_typeid, 'bitcoin-transferred' as transaction_name, -5 as amount from dual union all
select 30 as id, 103 as transaction_typeid, 'bitcoin-transferred' as transaction_name, -5 as amount from dual union all
select 31 as id, 103 as transaction_typeid, 'bitcoin-transferred' as transaction_name, -4 as amount from dual union all
select 40 as id, 104 as transaction_typeid, 'bitcoin-lost' as transaction_name, -16 as amount from dual union all
select 99 as id, 103 as transaction_typeid, 'bitcoin-transferred' as transaction_name, -5 as amount from dual WHERE 1 = 0
;
结果:
+----+------------------+--------+
| id | transaction_name | amount |
+----+------------------+--------+
| 1 | bitcoin-received | 0 |
| 2 | bitcoin-mined | 0 |
| 5 | bitcoin-received | 34 |
| 15 | bitcoin-mined | 0 |
| 16 | bitcoin-mined | 19 |
| 17 | bitcoin-mined | 30 |
+----+------------------+--------+