数据库设计:计算帐户余额

时间:2010-12-07 06:28:15

标签: sql-server database sql-server-2008 database-design

如何设计数据库以计算帐户余额?

1)目前我从交易表中计算账户余额 在我的交易表中,我有“描述”和“金额”等。

然后我会将所有“金额”值相加,这将计算出用户的帐户余额。


我向我的朋友展示了这个,他说这不是一个好的解决方案,当我的数据库增长它会减慢????他说我应该创建单独的表来存储计算的帐户余额。如果这样做,我将不得不维护两个表,而且风险很大,帐户余额表可能会不同步。

有什么建议吗?

编辑:选项2:我应该在我的交易表“余额”中添加一个额外的列。 现在我不需要经过多行数据来执行计算。

实施例 约翰购买了100美元的信贷,他的债务为60美元,然后他增加了200美元的信贷。

金额$ 100,余额$ 100。

金额 - 60美元,余额40美元。

金额$ 200,余额$ 240。

9 个答案:

答案 0 :(得分:58)

一个从未得到优雅解决的古老问题。

我所使用的所有银行业务套餐都将余额存储在账户实体中。从运动历史中动态计算它是不可想象的。

正确的方法是:

  • 移动桌有一个'开口 平衡每个账户的交易。你需要 这在几年的时间里 需要将旧动作移出 主动运动表到历史 表
  • 帐户实体有余额 字段
  • 机芯上有一个触发器 更新帐户的表 贷记和借记账户的余额。显然,它有承诺 控制。如果您无法触发,那么需要一个唯一模块,该模块在承诺控制下编写动作
  • 你有一个'安全网'计划 可以离线运行,重新计算 所有的余额和显示(和 可选地纠正)错误 余额。这非常有用 测试

有些系统将所有动作存储为正数,并通过反转from / to字段或带有标志来表示信用/借记。就个人而言,我更喜欢信用额度,借记字段和签名金额,这使得逆转更容易理解。

请注意,这些方法适用于现金和证券。

证券交易可能会更加棘手,特别是对于公司行为,您需要提供一笔交易,以更新一个或多个买方和卖方的现金余额,其担保头寸余额以及可能的经纪人/存款。

答案 1 :(得分:4)

您应该存储当前帐户余额并始终保持最新状态。交易表只是过去发生的事情的记录,不应仅用于获取当前余额的高频率。考虑到许多查询不只是想要平衡,他们想要对它们进行过滤,排序和分组等。在复杂查询的中间总结您创建的每个事务的性能损失甚至会削弱适度大小的数据库

这对表的所有更新都应该在一个事务中,并且应该确保所有内容保持同步(并且帐户永远不会超出其限制)或事务回滚。作为额外措施,您可以运行定期检查此问题的审计查询。

答案 2 :(得分:2)

此问题的常见解决方案是在快照架构中维护(比方说)月度期初余额。可以通过将月份的交易数据添加到月度期初余额来计算当前余额。这种方法通常在帐户包中使用,特别是在您可能进行货币转换和重估的情况下。

如果您遇到数据量问题,可以存档旧余额。

此外,如果系统上没有专用的外部数据仓库或管理报告工具,则余额可用于报告。

答案 3 :(得分:2)

这是一个数据库设计,我只使用一个表来存储操作/事务的历史记录。目前在许多小项目中充当魅力。

这并不能取代特定的设计。这是一个适用于大多数应用程序的通用解决方案。

<强> ID :INT     标准行ID

<强> operation_type :INT     操作类型。支付,收取,利息等

<强> SOURCE_TYPE :INT     从哪里开始运作。     目标表或类别:用户,银行,提供商等

<强> SOURCE_ID :INT     数据库中源的id

<强> TARGET_TYPE :INT     应用什么操作。     目标表或类别:用户,银行,提供商等

<强> target_id :INT     数据库中目标的ID

金额:十进制(19,2签名)     总价值为正或负的价值

account_balance :十进制(19,2签名)     结果平衡

extra_value_a :十进制(19,2签名)[这是不使用字符串存储的最通用选项]     你可以存储一个额外的数字:利息百分比,折扣,减少等。

<强> created_at :时间戳

对于source_type和target_type,最好使用枚举或表appart。

如果您想要特定的余额,您只需查询按created_at降序限制排序的最后一个操作为1.您可以按来源,目标,operation_type等进行查询。

为了获得更好的性能,建议将当前余额存储在所需的目标对象中。

答案 4 :(得分:1)

当然,您需要在每行存储当前余额,否则速度太慢。为了简化开发,您可以使用约束,这样您就不需要触发器和定期检查数据完整性。我在这里描述了Denormalizing to enforce business rules: Running Totals

答案 5 :(得分:0)

你的朋友错了你是对的,我建议你现在不要改变一切 如果你的db因此而变慢,并且在你验证了所有其余的(正确的索引)之后,可能会使用一些非规范化。
然后,您可以在Accounts表中放置一个BalanceAtStartOfYear字段,并仅汇总今年的记录(或任何类似的方法)。
但我当然不会事先推荐这种方法。

答案 6 :(得分:0)

以下是建议您如何以非常简单的方式存储期初余额: -

  1. 在事务表上创建一个触发器函数,仅在更新或插入后调用。

  2. 在名为期初余额的帐户主表中创建一个名称列。

  3. 在主表格的期初余额栏中保存数组中的期初余额。

  4. 您甚至不需要使用服务器端语言使用此存储数组,只需使用PostgreSQL中提供的数据库数组函数即可。

  5. 如果要重新计算数组中的期初余额,只需将事务表与数组函数分组,并更新主表中的整个数据。

  6. 我在PostgreSQL中做到了这一点并且工作正常。

    在您的事务表变重的那段时间内,您可以在日期的基础上对事务表进行分区,以加快性能。 这种方法非常简单,不需要使用任何额外的表,如果连接表会降低性能,因为连接中较小的表会为您提供高性能。

答案 7 :(得分:0)

我的方法是将借记存储在借方列中,信用列中存入贷方,并且在获取数据时创建两个数组,借记和贷记数组。然后继续将所选数据附加到数组并为python执行此操作:

def real_insert(arr, index, value):
    try:
        arr[index] = value
    except IndexError:
        arr.insert(index, value)


def add_array(args=[], index=0):
    total = 0
    if index:
        for a in args[: index]:
            total += a
    else:
        for a in args:
            total += a
    return total

然后

for n in range(0, len(array), 1):
    self.store.clear()
    self.store.append([str(array[n][4])])
    real_insert(self.row_id, n, array[n][0])
    real_insert(self.debit_array, n, array[n][7])
    real_insert(self.credit_array, n, array[n][8])
    if self.category in ["Assets", "Expenses"]:
        balance = add_array(self.debit_array) - add_array(self.credit_array)
    else:
        balance = add_array(self.credit_array) - add_array(self.debit_array)

答案 8 :(得分:-3)

简单回答:做三件事。

存储当前余额;并且在每个交易中存储该时间点的当前余额的移动和快照。这将在任何审计中提供额外协调。

我从未参与过核心银行系统,但我从事过投资管理系统,根据我的经验,这就是它的完成方式。