基于当前和上一行数据的自动计算列,将用于即将到来的行SQL,Django



背景:一个ERP工具,它将保存所有交易信息,如期初余额&用户的交易金额和期末余额。当前行的期初余额取决于前一行的期末余额。期末余额是根据期初余额&交易金额。这个计算的期末余额将用作下一行的期初余额&

注意:交易金额等交易信息来自库存中的产品购买

问题:考虑我有100个条目。由于某种原因,管理员想要更改第一个条目的交易金额。因此,我第一排的期末余额将发生变化。但问题是,所有其他99行都取决于第一行的期末余额。如何创建一个SQL表来解决这个依赖列数据的问题。

PS:我使用Django作为框架,但是Raw SQL查询&解释也将在一定程度上解决我的问题。

你真的应该发布你的模型。。。

但给定一个这样的基本结构:

from django.db import models, transaction
from django.utils import timezone

class Account(models.Model):
iban = models.CharField(max_length=34, primary_key=True)
@property
def balance(self):
return self.mutations.last().end

class AccountMutation(models.Model):
id = models.BigAutoField(primary_key=True)
account = models.ForeignKey(
Account, on_delete=models.PROTECT, related_name="mutations"
)
start = models.DecimalField(decimal_places=4, max_digits=12)
timestamp = models.DateTimeField(default=timezone.now)
amount = models.DecimalField(decimal_places=4, max_digits=12)
end = models.DecimalField(decimal_places=4, max_digits=12)
objects = AccountMutationManager()
class Meta:
ordering = ("timestamp", "pk")

我们可以实现这样的自定义管理器:

class AccountMutationManager(models.Manager):
@transaction.atomic
def recalculate(self, from_: "AccountMutation"):
qs = self.filter(
account=from_.account, timestamp__gte=from_.timestamp, id__gt=from_.id
).select_for_update()
prev = from_
for mutation in qs:
mutation.start = prev.end
mutation.end = mutation.start + mutation.amount
mutation.save()
prev = mutation

当然,这是基于时间戳的突变来确定排序的。如果使用前一个指针链接事务,则选择略有不同,并且需要一个reorder((方法以防时间戳发生更改。但这实际上取决于它的存储方式。

通常,我不会用突变来存储开始和结束余额,而是使它们成为计算字段,并且每个账户都有每个"账户"的期初余额;财政年度";,从中开始计算。

一些澄清:

  • 我们对原子事务使用要么全有要么全无的方法
  • 此外,我们用select_for_update()锁定所有将要受到影响的行,这样就不会同时发生影响相同数据的两次重新计算
  • from_是被改变并被认为具有正确末端平衡的突变

最新更新