哪个是事务表的更好架构:
customer_id
type (enum, 'Debit' or 'Credit')
amount (decimal, unsigned)
Run Code Online (Sandbox Code Playgroud)
要么
customer_id
amount (decimal, signed... negative numbers are debits, positive numbers are credits)
Run Code Online (Sandbox Code Playgroud)
第二个解决方案似乎更简单,但我担心我错过了一些潜在的陷阱.
背景
借方代表你拥有的东西,贷方代表别人拥有的东西。它们不是相同的维度单位,不应存储在同一数据库列中。使用符号位来表示借方或贷方是对复式记账工作方式的过度简化。不过,这种过于简单化的做法在低端和自制会计软件包中不断出现,可能是因为这是外行人对会计的看法。[1]
我发现让软件开发人员跟上复式记账的最简单方法是注意会计系统中的数字不是标量——它是一个向量。矢量元素由维度轴(借方或贷方)和大小(带符号的固定位小数)组成。[2]
解决方案
您的第一个解决方案表示数据的矢量性质,并遵循公认的会计惯例,但仍将幅度元素存储在同一列中,无论它适用于哪个轴。这使得 SELECT 语句更加复杂。
最好将借方和贷方的数量分成不同的列;这摆脱了对轴(枚举)列的需要,简化了 SQL,可能是一种性能改进,并且是更传统的方法。
您的第二个解决方案(重载符号位以表示借方或贷方)每次看到都会让我感到害怕,因为我永远无法确定建筑师是否在其他地方以某种方式补偿丢失的维度信息,或者只是不了解矢量性质的会计数据。从我在 SO 上看到的情况来看,显然有很多以这种方式编写的会计包,但它使代码和数据结构复杂、脆弱、速度较慢,所有这些都是为了节省一小部分数据库空间。
来源
曾几何时,我是一家国际银行的交易系统工程师。角落案例不好,简单的代码很好。
脚注
[1]:我认为人们偶然会认为“负值是借方”,部分原因是银行的运作方式;银行使用的语言让人们对借记是什么产生错误的印象。从银行的角度来看,您的支票账户是其他人拥有的——它有信用余额。当您将钱存入银行时,他们会告诉您他们正在“贷记”您的帐户,而当您取款时,他们会说“借记”。但这都是从银行的角度来看的,所以都是倒退的。在你自己的会计系统中(如果你有的话),借记你的支票账户意味着增加余额,而贷记是减少。从您的角度来看,该帐户有借方余额,因为它“
[2]:如果您的语言支持固定小数位复数,它们可能是一种操作会计数据的便捷方式;借方可能在实轴上,贷方可能在虚轴上。这会创建一些有趣的属性;一组平衡的条目将具有 45 度的相位角,依此类推。但是,除非您的数据库引擎本身支持复数,否则无论如何您最终都会将实数和复数部分分成两列进行存储,这些列将被称为“借方”和“贷方”。
一般来说,拥有以下内容不是更好吗?
entry_id // PK
date
amount // always positive
debit_account_id // FK to accounts table
credit_account_id // FK to accounts table, not equal to debit_account_id
Run Code Online (Sandbox Code Playgroud)
这样您就可以始终拥有匹配的复式记账?
有些账户是客户账户,一个是应收账款账户,等等。
另请参阅Martin Fowler 的《分析模式》一书中的本章。
我曾使用一些大公司使用的会计系统。总帐交易表有单独的借方和贷方列。就像是:
customer_id
DebitAmount (decimal)
CreditAmount (decimal)
Run Code Online (Sandbox Code Playgroud)
只有其中一列的值大于 0,另一列始终为 0。这看起来效率不高,但确实有效。基本上,您必须选择一个约定并使您的代码使用它。