Ale*_*lex 20 sql database accounting database-design relational-database
假设有一家银行、一家大型商店等,希望正确地为内部帐户和跟踪客户帐户进行会计处理。而不是实现满足当前简单而狭隘的要求,这将是“家酿”:结果证明这些只是当前简单要求的临时拐杖,并且在出现新要求时很难或不可能扩展。
据我了解,复式记账法是一种行之有效的方法,可满足所有会计和审计要求,包括目前未考虑的要求。如果实施,它将:
我研究了另一个问题的答案:简单银行账户的衍生账户余额与存储账户余额?,它为内部帐户提供了很好的信息。需要一个数据模型,以便理解实体;他们的互动;他们的关系,@PerformanceDBA 已经给出了这一点。该模型取自该答案:
虽然这对于简单的内部账户来说是令人满意的,但我需要看到一个提供完整复式记账方法的数据模型。
需要添加的文章是Journal
; 内部 vs 外部Transactions
;等等..
理想情况下,我想看看这些双条目行在数据库方面的样子,整个过程在 SQL 中的样子,在每种情况下哪些实体受到影响等等。案例如下:
让我们称之为System
而不是Bank
,Bank
可能太复杂而无法建模,让问题是关于使用帐户和资产操作的假想系统。客户与系统(存款、取款、后期费用、批量费用)以及彼此之间(转账)执行一组操作。
Per*_*DBA 71
首先,我必须赞扬你的态度。很少有人不仅在扎实的基础上思考和工作,而且希望了解和实施复式记账系统,而不是:
要么不实施 DEA,从而遭受多次重写,并且在每次增量、每个新需求时都感到痛苦,
或者实施 DEA,但从头开始重新发明轮子,通过自己解决问题,并在每次暴露错误和要求的错误修复时承受痛苦,这是一个永无止境的序列。
避免这一切,并寻求标准方法,是高度赞扬的。
此外,(f)您希望以关系数据模型的形式出现,您不受日期的奴役;达文; 费金; 等人的观点规定了Record ID
基于记录归档系统,该系统削弱了建模练习和由此产生的“数据库”。这些天,有些人沉迷于原始 RFS 并压制了 EF Codd 博士的关系模型。
如果您不介意,我会按照逻辑顺序从头开始解释,这样我就可以避免重复,而不仅仅是回答您的特定要求。如果您完全了解这些要点,我深表歉意。
理想情况下,我想看看那些双条目行在数据库方面的样子
这是建模或定义任何东西所需的正确方法的障碍。
ID
在每个文件上标记一个字段并使其成为“键”一样,会削弱建模练习,因为它会阻止对数据的分析(数据实际上代表的是什么),期望 Credit 有两行/Debit pair 在开始时会削弱对事物是什么的理解;会计行为是什么;这些行动有什么影响;最重要的是,数据将如何建模。尤其是在学习的时候。亚里士多德教导我们:
最初对真理的最小偏离后来会成倍增加…… 一个原则是伟大的,与其说是力量,不如说是范围;因此,开始时很小的[错误]在最后变成了一个巨大的[错误]。
解释为,开始时的小错误(例如原则;定义)结果是最后的大错误。
因此,智力上的要求,第一件事,就是在建模练习结束时清除你的头脑。当然,当人们在会计方面了解它是什么时,这也是必需的。
假设有一家银行、一家大型商店等,希望正确地为内部帐户和跟踪客户帐户进行会计处理。
让我们称之为System
而不是Bank
,Bank
可能太复杂而无法建模...
客户与系统(存款,取款,后者费用,批量费用)以及彼此(转账)执行一组操作。
需要明确的是,我确定的范围如下。如果不是,请纠正我:
System
or Bank
,我会称它为House
。稍后将清楚其相关性。任何人士为复式方法只是在总帐,无需外部客户账户,可以从这个回答搜集,很容易。
同样,这里给出的数据模型很容易扩展,Ledger
可以比给出的简单模型更大。
知道它是什么名字;它具有巨大的价值;它比自己制作的系统更好,是一回事,知道什么足以实施它,又是另一回事。
首先,一个人需要对总账和一般会计原则有一个很好的理解。
第二,理解金钱代表价值的概念。价值不能被创造或破坏,它只能被移动。 从账户中的一个存储桶到另一个存储桶,也称为借方(从账户)和贷方(到账户)。
虽然SUM( all Credits ) = SUM( all Debits )确实可以从 DEA 系统中获得这样的报告,但这不是实施所需的理解,这只是一个最终结果。还有更多。
虽然每笔交易确实由一对组成:相同金额的一个 Credit 和一个 Debit,但还有更多。
对的每条腿;贷方和借方不在同一个账户或分类账中,它们在不同的账户、分类账或账户和分类账中。
该SUM(所有学分)并不简单,因为它们在这些不同的地方(套)。它们不在同一个表的两行中(它们可能是,稍后更多)。同样,SUM( all Debits )。
因此,两个 SUM() 中的每一个都涵盖了完全不同的集合(关系集),并且必须首先获得,然后才能比较两个 SUM()。
在尝试实施 DEA 之前,我们需要正确理解我们正在实施的事物。我建议如下:
这是要持有的首要心态,与需要在这个或那个账户或分类账中完成的任何事情分开。
我已经把它放在了顶部;左边,在数据模型中,这样所有文章的从属关系都在视觉上呈现。
消除(不仅仅是减少)所谓的:
“丢钱
“丢失”交易(贷方/借方对的一方或另一方)
以及在追逐它上浪费的时间。
不仅可以轻松找到钱,而且可以快速确定它到底发生了什么以及现在在哪里。
完整的审计功能
保持良好的账户是不够的,对于一个负责他人资金的企业来说,易于审计是必不可少的。也就是说,任何会计师或审计师都必须能够不受阻碍地检查账簿。
最大的好处虽然是第三级,但每天或月末的任务,例如试算表或结账,都可以轻松快速地结束。所有报告;声明;资产负债表; 等,可以简单地获得(SELECT
如果数据库是关系,则使用单个)。
互联网上有很多误导性信息,维基百科尤其糟糕,它永远在变化(真相不会改变,虚假会随着天气而变化),但抱歉,这就是我们所拥有的。仅使用它来获得概览,尽管它很长,但它没有结构或逻辑描述。按照链接获取更好的信息。
我不完全同意维基百科文章中的术语。尽管如此,为了避免可避免的混淆,我将使用这些术语。
网络上有可用的教程,有些教程比其他教程好。这些推荐给正在实施适当的会计系统的任何人,无论是否有 DEA。这需要时间,它与这样的答案无关,这就是我链接维基百科文章的原因。
理想情况下,我想看看
这些双条目行在数据库方面的样子,整个过程在 SQL 中的样子,在每种情况下哪些实体受到影响等。
好的。让我们先了解事务,然后逐步了解支持它们的数据模型,然后检查示例行。任何其他顺序都会适得其反,并导致不必要的来回。
你的编号。绿色是House
一般Ledger
,蓝色是外部客户Account
,黑色是中性。
这是Treatment的第一个增量,即在不同情况下如何处理事物(您的关注以及您对具体示例的要求是完全正确的)。
Credit/Debit Pairs
这是 DEA 的第一原则,理解对,作为对,除了对之外别无他物。
不要担心 GeneralLedger
或 theAccount
是如何设置的,或者数据模型是什么样的。从会计师的角度思考(必须在书中完成什么),而不是从开发人员的角度(必须在系统中完成的任务)。
请注意,该对的每条腿都在一组 (the Ledger
) 中,或分成两组(一条腿在Ledger
,另一条腿在Account
)。没有两条腿都在的对Account
。
- 客户将现金存入他的账户
HouseCash
银行认为日常现金交易所需的所有现金都放在那里HouseReserve
。
- 银行每月向所有客户账户收取一次费用(样本批量作业)
Account
用Fee
Fee
依赖于 AccountType_Ext
Fee
依赖于其他东西,例如 中的交易数量Account
;或CurrentBalance
低于或高于某个限度;等等,没有显示。我相信你能弄清楚。
- 客户在柜台进行一些操作,银行收取费用(提现+提现费用),
House
必须与提供国际结算和货币兑换服务的当地大银行进行互动。这与我们无关,也未显示。在任何情况下,所有这些类型的Interbank
事务都是每天批处理和处理一次,而不是每个AccountTransaction
.House
并没有在外币账户Ledger
。这很容易实现。
- 玛丽从她的账户中汇出一些钱到约翰在同一家银行的账户
HouseReserve
,而不是HouseCash
HouseReserve
in 转入HouseCash
是因为约翰今天可能会进入银行并将其取出。HouseCash
在所有Accounts
将被移动到HouseReserve
。未显示。现在让我们看看数据建模者做了什么来支持会计师的需求,即业务交易。
这当然是Treatment的第二个增量,建模者已经理解现实世界的业务事务是什么,用关系术语(FOPC; RM ; Logic; Normalisation )表示
这不是满足重述范围所需的最简单的数据模型。
有一些更简单的模型(稍后会详细介绍),但它们有这个模型没有的问题,这些问题如果不是必须的,也是需要避免的。
图像太大,无法在线查看。在新选项卡中打开图像,以全尺寸欣赏它。
我的IDEF1X 简介对于那些不熟悉关系模型或其建模方法的人来说是必不可少的读物。请注意,IDEF1X 模型具有丰富的细节和精确度,显示了所有必需的细节,而本土模型不了解标准的必要性,定义要少得多。这意味着,需要完全理解符号。
由其他人,而我产生了真正的关系数据模型之间的主要区别是:
一个商业交易(通常两个动作;两条腿,每个信用卡/借记一个)与两面,每学分一个受单行/借记,
在AccountTransaction
或LedgerTransaction
。
大多数建模者会为贷方/借方对建模两行,每条腿或边各一个(嘿,一条腿是贷方,另一条腿是借方,如果我将其标准化,我会得到两行)。
错误的。如果我告诉你 Fred 是 Sally 的父亲,你知道,从那个事实来看,Sally 是 Fred 的女儿。
A 只FOREIGN KEY
需要声明一次,而不是每一方都声明一次。
同样,信用/借记对是一个单一的商业交易,
一个单一的原子文章,可以从任何一方看到,就像一枚硬币的两个面。建模成这样。
防止了所有可预防的错误,消除了对“丢失”腿的搜索。
即使对于那些不符合标准的 OLTP 代码,这会导致相当可预防的并发问题,如果实现了这种方法,这也是一篇不会出现这些问题的文章。
此外,%Transaction
表中的行数减半。
我已经安排的条款,使得
外部 Account
内部 Ledger
和LedgerTransaction
内外 AccountTransaction
都清楚。
连同来自Wikipedia 条目的定义块。
熟悉 DEA 贷方/借方对后,现在研究对的处理。请注意,处理是不同的,它基于许多标准(三种帐户类型;六种Ledger
类型;等等),而这些标准又基于总帐的复杂性。
这Ledger
很简单,只有Asset/Liability
帐户。当然,您可以自由扩展它。
老鹰眼会注意到AccountStatement.ClosingBalance
并且LedgerStatement.ClosingBalance
实际上可以派生,因此(从表面上看)不应存储。然而,这些是公布的数字,例如。每个账户的每月银行对账单,因此需要审计,因此必须存储。
全面处理该问题,包括考虑因素;定义; 治疗,参考这个问答:
在结束本节时,我们应该已经达成了这样的理解:
DEA 的总体原则,贷方/借方对,纯智力
典型的商业交易,总是一个贷方/借方对,两条腿,会计账簿中的两个条目
更深入地了解上述交易的处理方式
该环境House
管理(内部(;合作赌场中小银行)Ledger
和外部客户Account
)
首先看一下被提议用来处理所有这些的数据模型。
这里又是一整套样本数据。
重新主键:
请注意,LedgerNo
andAccountNo
不是代理,它们对组织有意义,在排序和构建Ledger
等方面。它们是稳定的数字,而不是AUTOINCREMENT
或IDENTITY
或任何类型的数字。
主键为LedgerTransaction
和AccountTransaction
是纯的,复合关系的按键。
它不是纸质会计师所钟爱的某种交易编号。
这也不是瘫痪Record ID
。
的可选键是更有意义的人类,因此我已经在实施例中使用它们(商业交易,[2]上面,下面和[5])。这个答案已经分层,这将是试图涉及的数百个噩梦1's, 2's
,并3’s
给对方。
如果我们想了解某事物的含义,我们需要抓住事物存在的意义,而不是通过给它一个数字来去除它的意义。
在示例数据中,主键为粗体。
理想情况下,我想看看
这些双条目行在数据库方面的样子,整个过程在 SQL 中的样子,在每种情况下哪些实体受到影响等。
现在我们了解了业务事务以及为需求提供服务的数据模型,我们可以检查业务事务以及受影响的行。
在 DEA 的术语中,每个业务交易都有两条腿,在纸质账簿中的两个条目,对于每个贷记/借记对,
仍然是一个单一的业务交易,现在:
它受到具有两个的单行的影响边,对于每个贷方/借方对。
这是理解处理的第三个增量:业务交易;实现它们的数据模型;现在,受影响的行
示例数据库行以简短形式的表名作为前缀。
加号表示INSERT
减号表示DELETE
等于号UPDATE
。
- 客户将现金存入他的账户
- 银行每月向所有客户账户收取一次费用(样本批量作业)
- 客户在柜台进行一些操作,银行收取费用(提现+提现费用),
- 玛丽从她的账户中汇出一些钱到约翰在同一家银行的账户
通常有几种方法可以给猫剥皮(代码),但如果猫还活着,则很少(代码用于高并发系统)。
的关系模型是建立在一阶谓词演算(又名一阶逻辑),所有的定义(DDL),因此所有查询(DML)是完全逻辑。
因此,符合这种理解的数据模型完全是逻辑的。
针对这种数据模型的查询非常简单:逻辑和直接。他们没有Record ID
基于文件系统所需的复杂代码。
因此,在SQL代码请求可能的几种方法中,我给出了最直接和合乎逻辑的。
代码示例是适合 SO 的代码示例,您必须捕获错误并从错误中恢复;你不会尝试任何会失败的事情(在使用动词之前检查操作的有效性),并遵循 ACID 事务的 OLTP 标准。
由于这个代码段在很多地方都会用到,让我们做正确的事情并创建一个视图。
请注意,在真正的 SQL 平台上,源代码在提交时编译并运行,存储过程和视图以其编译形式存储,从而消除了每次执行时的编译。与米老鼠的 NONsql 套件不同。
高端商业 SQL 平台做得更多,例如缓存视图的查询计划,以及存储过程中的查询。
CREATE VIEW Account_Current_V
AS
SELECT
AccountNo,
Date = DATEADD( DD, -1, GETDATE() ), -- show previous day
ClosingBalance,
TotalCredit = (
SELECT SUM( Amount )
FROM AccountTransaction
WHERE AccountNo = @AccountNo
AND XactTypeCode_Ext IN ( "AC", "Dp" )
-- this month
AND DateTime >= CONVERT( CHAR(6), GETDATE(), 2 ) + "01"
),
TotalDebit = (
SELECT SUM( Amount )
FROM AccountTransaction
WHERE AccountNo = @AccountNo
AND XactTypeCode_Ext NOT IN ( "AC", "Dp" )
AND DateTime >= CONVERT( CHAR(6), GETDATE(), 2 ) + "01"
),
CurrentBalance = ClosingBalance +
<TotalCredit> - -- subquery above
<TotalDebit> -- subquery above
FROM AccountStatement -- 1st day of this month
WHERE Date = CONVERT( CHAR(6), GETDATE(), 2 ) + "01"
Run Code Online (Sandbox Code Playgroud)
另一个 DEA 业务交易的过程。
CREATE PROC Account_Withdraw_tr (
@AccountNo,
@Amount
)
AS
IF EXISTS ( SELECT 1 -- validate before verb
FROM AccountCurrent_V
WHERE AccountNo = @AccountNo
AND CurrentBalance >= @Amount -- withdrawal is possible
)
SELECT @LedgerNo = LedgerNo
FROM Ledger
WHERE Name = "HouseCash"
BEGIN TRAN
INSERT AccountTransaction
VALUES ( @LedgerNo, GETDATE(), "Cr", "Wd", @AccountNo, @Amount )
COMMIT TRAN
Run Code Online (Sandbox Code Playgroud)
一个 proc,设置为 SQL 事务,用于执行 DEA 业务事务。
CREATE PROC Account_Withdraw_tr (
@AccountNo,
@Amount
)
AS
IF EXISTS ( SELECT 1 -- validate before verb
FROM AccountCurrent_V
WHERE AccountNo = @AccountNo
AND CurrentBalance >= @Amount -- withdrawal is possible
)
SELECT @LedgerNo = LedgerNo
FROM Ledger
WHERE Name = "HouseCash"
BEGIN TRAN
INSERT AccountTransaction
VALUES ( @LedgerNo, GETDATE(), "Cr", "Wd", @AccountNo, @Amount )
COMMIT TRAN
Run Code Online (Sandbox Code Playgroud)
将任何业务交易添加到 的过程LedgerAccount
。它总是:
LedgerTransaction.LedgerNo
,这是Credit
腿LedgerTransaction.LedgerNo_Dr
,这是Debit
腿。CREATE PROC Account_Deposit_tr (
@AccountNo,
@Amount
)
AS
-- IF EXISTS, etc -- validate before verb
BEGIN
SELECT @LedgerNo ...
BEGIN TRAN
INSERT AccountTransaction
VALUES ( @LedgerNo, GETDATE(), "Dr", "Dp", @AccountNo, @Amount )
COMMIT TRAN
END
Run Code Online (Sandbox Code Playgroud)
只有一个任务,在 proc 中处理月末AccountStatement
,作为批处理作业执行。
CREATE PROC Ledger_Xact_tr (
@LedgerNo, -- Credit Ledger Account
@LedgerNo_Dr, -- Debit Ledger Account
@Amount
)
AS
... IF EXISTS, etc ...
BEGIN TRAN
INSERT LedgerTransaction
VALUES ( @LedgerNo, GETDATE(), @LedgerNo_Dr, @Amount )
COMMIT TRAN
Run Code Online (Sandbox Code Playgroud)
虽然SUM(all Credits) = SUM(all Debits)确实如此,并且可以从 DEA 系统获得这样的报告,但这不是理解。还有更多。
希望我已经给出了方法和细节,并涵盖了理解和更多内容,以便您现在可以轻松编写SELECT
生成所需报告所需的内容。
或者也许是 external 的 Monthly Statement Accounts
,带有运行总计AccountBalance
列。想想:银行对账单。
SELECT
命令提供服务。最后但并非最不重要的一点是,最好将所有这些内嵌图形组织到一个PDF 中,格式为 A3(我的美国朋友为 11x17)。为了学习和注释,请用 A2 (17x22) 打印。
这是我的架构(以 sqlite 为例),有 2 个表:
表格
-- This is a list of your chart of accounts
CREATE TABLE "accounts" (
"name" TEXT,
"number" INTEGER,
"normal" INTEGER
)
-- This is a table of each transaction
CREATE TABLE "transactions"
(
"id" INTEGER,
"date" TEXT,
"amount" REAL,
"account" INTEGER,
"direction" INTEGER
)
Run Code Online (Sandbox Code Playgroud)
根据此约定,accounts.normal
和transaction.direction
字段设置1
为借方和-1
贷方。最终用户永远不会看到这一点,但它使算术变得容易。
当您创建日记帐分录时,表中至少有 2 行transactions
- 借方和贷方。他们应该共享相同的id
。
要查看您的余额,您可以运行以下查询:
select
(account) as a,
name,
sum(amount * direction * normal) as balance
from
transactions
left join accounts on a = accounts.number
group by
name
order by
a,
name;
Run Code Online (Sandbox Code Playgroud)
要查看分类帐,您可以运行以下命令:
select
id,
date,
name,
case when direction == 1 then amount end as DR,
case when direction == -1 then amount end as CR
from
transactions
left join accounts on account = accounts.number
order by
id,
date,
CR,
DR;
Run Code Online (Sandbox Code Playgroud)
我有一篇更详细的文章,其中介绍了您可以运行的不同查询以及示例数据。但是,通过上面两个表,您可以创建一个有效的复式记账系统。