表 A 有数据:
id | n |
---|---|
1 | 100 |
2 | 150 |
3 | 120 |
表 B 有数据:
id | m |
---|---|
1 | 80 |
2 | 200 |
最后的查询结果是:也就是说表 A 和 B 分别以 id 为升序,表 B 的 m 从表 A 的 n 中消耗,最后查询的结果是这个消耗的过程。
id | d |
---|---|
1 | 80 |
1 | 20 |
2 | 150 |
3 | 30 |
m 80(id=1) 从 n 里的 100(id=1)消耗 80(生成 d 的第一条记录),m 80 消耗完。m 200(id=2) 从 n 的 20(id=1,100 消耗了 80 的剩余,生成 d 的第二条记录),m 剩下 180 从 n 150(id=2) 消耗 150(生成 d 的第三条记录),m 剩下 30 从 n 120 里消耗 30(生成 d 的第四条记录)m 200 消耗完。
我也有想过把这个计算结果再放一张表里。但表 B 的数据插入顺序不一定与计算的顺序(表 B 的 id)一致,这就导致了有时候表 B 一条记录的插入,这个计算结果表里存在大量的更新,最坏的情况也许是整张表数据的重建,这怎么玩?
这个基本上和财务数据的逻辑是一致的,是一个类似单向 (qu) 链 (kuai) 表 (lian) 的结构。中间有一个节点变化,至少会引起之后所有的数据都必须要重算。最坏的情况是变更第一个值,就不得不触发全表重建。
这样肯定比你从数据库各种 Join 得到的结果快的多,毕竟 O(m+n). 要不只能写过程了,像写 ruby 代码一样在 sql 里遍历一遍。。。
翻完评论才看明白什么意思。我觉得这个计算逻辑不适合用 SQL 做,因为它的关注点并非在集合,而在集合中的每条元素。用两个链表做计算(递归比较头节点)反而更容易,计算结果再保存进数据库就行。
如果有非常特殊的原因一定要在 SQL 里实现,可以看一下 lateral join 和 with recursive。
其实这个问题看了评论后第一直觉就是用一个计算结果表去解决,但是用计算结果表可能让解决这个问题变得烦琐起来,因为计算结果表的数据与表 B 里数据的顺序有关,表 B 数据的计算顺序又不一定与产生顺序一致。这就导致要维护计算结果表数据的正确性,需要做很多事情,我目前想到的有:表 B 插入一条数据后,要向计算表里插入若干条结果数据(也可能同时需要删除更多旧的不正确的数据);也许这个计算过程还没结束,表 B 又插入了一条数据呢?...诸如此类的。 所以我想这可能是题主选择用 sql 解决这个问题的原因,这样可能比较省事(如果这样的 sql 写得出来)
@wootaw 是的,如果按照 LZ 的计算过程描述,其实是有不少中间数据的,比较过程化,这并声明式的 SQL 适合表达的领域。而且如果不考虑存储因素的话化,这个需求本质上就是一个链表计算。因此把计算过程和存储分开思考,解决方案的适用性会广很多。