web-dev-qa-db-ja.com

単純な銀行口座の派生口座残高と保存口座残高?

つまり、通常の銀行口座のように、お金の流入または流出を引き起こす多くのトランザクションがあります。口座残高は、常にトランザクション値を合計することによって常に導出できます。この場合、更新された口座残高をデータベースに保存するか、必要に応じて再計算するほうが良いでしょうか?

アカウントあたりの予想取引量:<5毎日

予想されるアカウント残高の取得:トランザクションが発生したときは常に、それ以外の場合は平均して1日に1回。

これについてどのように決定することを提案しますか?どうもありがとう!

34
Anmol Gupta

序文

客観的な真実があります:監査要件。さらに、公的資金を扱う場合、遵守しなければならない立法機関があります。

完全な会計要件を実装する必要はありません。必要な部分だけを実装できます。

逆に、何かを実装することはお勧めできません以外標準の会計要件(その一部)は、バグまたは負荷の数がしきい値を超えた場合、またはシステムが拡張した場合に保証されるため、再実装する必要があります。回避できる、したがって回避すべきコスト。

また、資格のない、認定されていない「監査人」を雇わないでください。資格のない開発者を雇った場合と同じ結果が生じます。税務署があなたに罰金を科せば、それはもっと悪いかもしれません。

方法

それほど原始的でない国々の標準的な会計方法はこれです。他の人にとっては、「ベストプラクティス」。

この方法は、同様の操作を持つすべてのシステムに適用されます。ニーズ;過去の月次の数値と当月の要件(在庫管理など).

考慮

最初に、考慮事項。

  1. データを複製しないでください。
    現在の残高を導き出すことができる場合(ここではそれは単純です)、集計列と重複させないでください。このような列はデータの複製です。正規化ルールに違反します。さらに、それはcreates更新異常であり、それ以外の場合には存在しません。

  2. サマリー列を使用する場合、トランザクションが更新されるたびに(新しいトランザクションが挿入されたときではなく、変更された場合)、サマリー列valueは廃止されるため、すべてのトランザクションを更新する必要があります。とにかく時間。これは、更新異常の結果です。それはそれを持つことの価値を排除します。

  3. 外部公開。
    別のポイント。毎月の銀行取引明細書のように残高が公開される場合、そのような文書には通常法的制限と影響があるため、公開後の現在の残高値は公開後に変更してはなりません。

    • 公開日以降のデータベースでの外部公開された図の変更は、不正行為、詐欺などの証拠です。

      • 公開された歴史を変えようとするそのような行為は、初心者の特徴です。初心者や精神病患者は、歴史を変えることができると主張するでしょう。しかし、誰もが知っているように、法律の無知は正当な弁護を構成するものではありません。
    • 2015年4月に、銀行が銀行取引明細書で2014年12月に発行した現在の残高を銀行に変更してほしくありません。

    • その図は監査図と見なされ、公開され、変更できません。

  4. 過去に発生した、現在では修正されているエラーを修正するために、必要な修正または調整が当月の新しいトランザクションとして行われます(前の月または期間に適用される場合でも)。

    これは、該当する月が閉じているためです。監査済み;なぜなら、それが起こって記録された後では、人は歴史を変えることができないからです。 有効な月だけが現在の月です。

    • それほど原始的ではない国の利付システムなどの場合、エラーが見つかり、それが歴史的な影響を及ぼします(たとえば、2015年4月に、証券で計算された利子が12月以降間違っていることがわかりました) 2014)、修正された利払い/控除の値が、エラーのあった日数に対して今日計算され、その合計が当月のトランザクションとして挿入されます。繰り返しますが、唯一有効な月は現在の月です。

      そしてもちろん、証券の金利も修正する必要があるため、そのエラーは繰り返されません。

    • 銀行の普通預金(利付)口座の利息の計算でエラーが見つかり、それを修正した場合、当月に調整値全体を構成する単一の預金を取得します。それは今月のトランザクションです。

      銀行は以下を行いません。変更履歴。歴史的な各月に関心を適用します。歴史的な銀行声明を思い出してください。歴史的な銀行取引明細書を再発行します。いいえ。多分第三世界の国々を除いて。

    • 同じ原則が在庫管理システムに適用されます。正気を保ちます。

  5. すべての実際の会計システム(つまり、ミッキーマウスの「パッケージ」ではなく、該当する国の監査機関によって認定されているもの)は、トランザクションにダブルエントリーシステムを使用しています。最も重要なのは、資金が「失われる」ことがないことです。そのためには、総勘定元帳と複式簿記が必要です。

    • あなたはそれを要求していません、あなたはそれを必要としないので、ここではそれについて説明しません。しかし、お金が「行方不明」になった場合に備えて、それを実装する必要があるため、バンドエイドソリューションではなく、覚えておいてください。まだ別の無認可の「パッケージ」ではありません。

    この回答は、質問ではない複式簿記です。
    その主題の完全な扱い(詳細なデータモデル、会計トランザクションの例、影響を受ける行、SQLコードの例)については、次のQ&Aを参照してください。
    ダブルエントリアカウンティングのリレーショナルデータモデル

  6. パフォーマンスに影響を与える主要な問題はこの質問の範囲外であり、本物のリレーショナルデータベースを実装するかどうか(たとえば、_Record IDs_によって特徴付けられる1960年代のレコードファイリングシステム)便宜上SQLデータベースコンテナ)。

    • 正規の関係キーなどを使用すると、テーブルの数に関係なく、高いパフォーマンスが維持されます。

    • 逆に、RFSのパフォーマンスは悪く、単に実行することはできません。 「スケール」はRFSのコンテキストで使用される場合、不正な用語です。原因を隠し、原因以外のすべてに対処しようとします。最も重要なのは、そのようなシステムにはリレーショナルインテグリティがないことです。関係力;または関係システムの関係速度。

実装

リレーショナルデータモデル•アカウント残高

Acct

リレーショナルデータモデル•インベントリ

Inv

表記

  • すべてのデータモデルは、1993年以降のリレーショナルデータベースのモデリングの標準であるIDEF1Xでレンダリングされます。

  • IDEF1Xの紹介リレーショナルモデルを初めて使う人にとって不可欠な読み物です。モデリング方法。 IDEF1Xモデルは詳細と精度が豊富で、必要なすべての詳細が表示されますが、自社開発モデルはそれよりはるかに少ないことに注意してください。つまり、表記法を理解する必要があります。

コンテンツ

  1. アカウントごとに、ClosingBalanceAccountStatementテーブルにあり(AccountNoごとに1行/月)、明細書日付(通常は月の最初の日) )およびその他のステートメントの詳細。

    • これは、監査と健全性の目的で要求されるため、複製ではありません。

      Inventoryの場合、これはQtyOnHandテーブルのPartAudit列です(PartCodeごとに1行/月)

    • 追加の値があり、クエリが必要なトランザクション行のスコープを制限するから現在の月

      • ここでも、テーブルがリレーショナルの場合、AccountTransactionの主キーは(AccountNo、Transaction DateTime)になり、ミリ秒の速度でトランザクションを取得します。

      • レコードファイリングシステムの場合、「主キー」はTransactionIDになり、現在の月をトランザクション日付で取得します。これは、正しくインデックス付けされている場合とされていない場合があり、必要な行が分散されます。ファイル。いずれの場合も、ClusteredIndexの速度よりもはるかに低速で、スプレッドが原因で、テーブルスキャンが発生します。

  2. AccountTransactionテーブルは単純なままです(銀行口座トランザクションの実際の概念は単純です)。単一の正のAmount列があります。

  3. Accountごとに、CurrentBalanceは次のようになります。

    • 前月の_AccountStatement.ClosingBalance_、便宜上、翌月の最初の日付

      (在庫の場合、_PartAudit.QtyOnHand_)

    • プラス、当月の_AccountTransaction.Amounts_の合計。ここで、TransactionTypeは預金を示します

      (在庫の場合、_PartMovement.Quantity_)

    • 今月の_AccountTransaction.Amounts_の合計からマイナスします。`MovementTypeは撤退を示します。

  4. このメソッドでは、当月のAccountTransactionsのみが流動的な状態にあるため、それらを導出する必要があります。前の月はすべて公開され、締め切られるため、監査の数値を使用する必要があります

  5. AccountTransactionテーブルの古い行は削除できます。公的資金については10年以上、それ以外の場合は5年以上、ホビークラブシステムについては1年以上。

  6. もちろん、会計システムに関連するコードはすべて、正規のOLTP標準と正規のSQL ACIDトランザクションを使用する必要があります。

  7. この設計には、スコープレベルのパフォーマンスに関する考慮事項がすべて組み込まれています(これが明らかでない場合は、拡張を依頼してください)。データベース内のスケーリングは問題ではありません。残っているスケーリングの問題はデータベースの外側にあります。


是正アドバイス

これらの項目は、多くのSO Answersで提供されており(もちろん、民主的に、大衆によって賛成票が投じられている)、インターネットには不正確な情報がぎっしり詰まっているため、説明する必要があります。アドバイス(アマチュアは主観的な「真実」を公開するのが大好きです):

  1. 明らかに、一部の人々は、明確なデータモデルに対して操作するために、技術用語でメソッドを指定したことを理解していません。そのため、特定の国の特定のアプリケーションの疑似コードではありません。メソッドは有能な開発者向けであり、手でリードする必要がある人には十分に詳細ではありません。

    • 彼らはまた、月の締切期間がの例であることを理解していません:税務署の目的での締切が四半期の場合、必ず、四半期ごとのカットオフを使用してください。唯一の法的要件が年次である場合は、年次を使用します。

    • カットオフが外部またはコンプライアンスの目的で四半期ごとに行われる場合でも、会社は内部監査および健全性の目的で(つまり、流動状態の期間の長さを最小限に保つために)毎月のカットオフを選択することがあります。 。

      例えば。オーストラリアでは、企業の税務署の締め切りは四半期ですが、大企業は毎月在庫管理を締め切ります(これにより、長期間にわたってエラーを追跡する必要がなくなります)。

      例えば。銀行には毎月の法的コンプライアンス要件があるため、月次で数値の内部監査を実行し、帳簿を閉じます。

    • 原始国とならず者国家では、銀行は明らかに悪質な目的のために、流動状態の期間を最大に保ちます。一部の企業は、毎年コンプライアンスレポートを作成しています。これが、オーストラリアの銀行が破綻しない理由の1つです。

  2. AccountTransactionテーブルでは、[金額]列に負/正を使用しないでください。お金は常に正の値を持ち、負の20ドル(または借りているのはマイナス50ドル)などはなく、二重の負の値が別の意味を持っていることを確認します。

  3. 移動の方向、つまり資金で何をするかは、(_AccountTransaction.Amount_に対して)別個の個別の事実です。これには別の列が必要です(1つのデータの2つのファクトが正規化規則に違反しているため、コードが複雑になります)。

    • TransactionType参照テーブルを実装します。その主キーは(_D, W_)で、Deposit/Withdrawalを開始点とします。システムの成長に合わせて、調整クレジットに(_A, a, F, w_)を追加するだけです。調整デビット;銀行の手数料; ATM_Withdrawal;等.

    • コードを変更する必要はありません。

  4. 一部の原始国では、訴訟要件として、トランザクションをリストするレポートでは、現在の合計をすべての行に表示する必要があると規定されています。 (これらは裁判所の要件よりも優れているため(上​​記の方法を参照)、監査人は弁護士よりも愚かさが少ないなどの理由で、これは監査要件ではありません。)

    明らかに、私は裁判所の要求に異議を唱えません。問題は、プリミティブコーダーがそれを次のように変換することです。oh、oh、我々は、a _AccountTransaction.CurrentBalance_ columnを実装する必要があります。彼らはそれを理解することができません:

    • レポートに列を印刷する要件は、データベースに値を保存するための命令ではありません

    • あらゆる種類の累計は派生値であり、簡単にコーディングできます(簡単でない場合は質問を投稿してください)。必要なコードをレポートに実装するだけです。

    • 実行合計を実装します。列としての_AccountTransaction.CurrentBalance_は恐ろしい問題を引き起こします:

      • 派生可能であるため、重複した列を導入します。正規化を解除します。更新異常を紹介します。

      • 更新異常:トランザクションが過去に挿入された場合、または_AccountTransaction.Amount_が変更された場合、その日付から現在までのすべての_AccountTransaction.CurrentBalances_再計算して更新する必要があります。

    • 上記の場合、法廷での使用を目的として提出されたレポートは現在は古くなっています(オンラインデータのすべてのレポートは、印刷された時点で古くなっています)。つまり。印刷;レビュー;トランザクションを変更します。再印刷;あなたが幸せになるまで、再確認してください。いずれにしても無意味です。

    • そのため、あまり原始的でない国では、裁判所は古い印刷された紙を受け入れず、公表された数値のみを受け入れます。銀行の明細書。これはすでに監査の要件の対象となっており(上記の方法を参照)、呼び出したり、変更したり、再印刷したりすることはできません。


コメント

アレックス:
はい、コードを確認してください。ありがとうございます。サンプルの「バケットショップ」であっても、人々が最初のスキーマをいつまでも見ることができるので、世界はより良くなります。

上記のデータモデルの場合。

コード•現在の残高を報告

_SELECT  AccountNo,
        ClosingDate = DATEADD( DD, -1 Date ), -- show last day of previous
        ClosingBalance,
        CurrentBalance = ClosingBalance + (
            SELECT SUM( Amount )
                FROM AccountTransaction
                WHERE AccountNo = @AccountNo
                    AND TransactionTypeCode IN ( "A", "D" )
                    AND DateTime >= CONVERT( CHAR(6), GETDATE(), 2 ) + "01"
                ) - (
            SELECT SUM( Amount )
                FROM AccountTransaction
                WHERE AccountNo = @AccountNo
                    AND TransactionTypeCode NOT IN ( "A", "D" )
                    AND DateTime >= CONVERT( CHAR(6), GETDATE(), 2 ) + "01"
                )
    FROM AccountStatement
    WHERE AccountNo = @AccountNo
        AND Date = CONVERT( CHAR(6), GETDATE(), 2 ) + "01"
_

トランザクションログを非正規化することで、より多くのtxタイプを追加したときに、より便利なクエリとビュー/マテリアライズドビューの変更が少なくなるように正規フォームを交換します

神よ私を救い給え。

  1. 基準に逆らうとき、あなたは第三世界の立場に身を置きます。そこでは、第一世界の国では決して破れないはずの、破られるべきではないものが破られます。

    権威から正しい答えを求め、それに対して反対するか、またはあなたの標準以下の方法について議論することはおそらく良い考えではありません。

  2. 非正規化(ここ)は、TransactionTypeCodeから派生できる複製された列である更新異常を引き起こします。コーディングを簡単にしたいが、1箇所ではなく2箇所でコーディングすることをいとわない。それはまさにエラーが発生しやすい種類のコードです。

    E Fコッド博士の完全に正規化されたデータベースリレーショナルモデルは、最も簡単で最も論理的でわかりやすいコードを提供します。 (私の仕事では、すべてのレポートを単一のSELECTで処理できることを契約で保証しています。)

  3. ENUMはSQLではありません。 (フリーウェアのNONsqlスイートはSQLに準拠していませんが、SQLには不要な追加機能があります。)アプリが商用SQLプラットフォームに移行した場合、これらすべてのENUMsを次のように書き直す必要があります。通常のルックアップテーブル。 PKとしてCHAR(1)またはINTを使用します。次に、それが実際にはPKを持つテーブルであることを理解します。

  4. エラーの値はゼロです(マイナスの影響もあります)。真実の値は1です。私は1を0と交換しません。したがって、それはトレードオフではありません。それはあなたの開発の決定です。

111
PerformanceDBA

これはかなり主観的です。私が考慮に入れることを提案するものは次のとおりです。

  1. 現在、アカウントはいくつありますか?
  2. 将来、アカウントはいくつになると思いますか?
  3. スケーラビリティをどの程度重視していますか?
  4. データベースとコードを更新して、バランスを独自のフィールドとして追跡するのはどのくらい難しいですか?
  5. 注意しなければならない、より差し迫った開発の懸念はありますか?

提案された2つのアプローチのメリットに関して、オンデマンドでトランザクション値を合計すると、アプローチを実装するのがより簡単/迅速になります。

ただし、現在のアカウントの残高をデータベースのフィールドとして維持し、必要に応じて更新することはできません。また、トランザクションごとにクエリを実行して現在の口座残高を計算してから処理を進める必要があるため、全体的なトランザクション処理時間が多少長くなります。実際には、非常に多数のアカウント/トランザクションを持っているか、非常に近い将来に期待しない限り、これらは小さな懸念事項になる可能性があります。

2番目のアプローチの欠点は、最初のセットアップにおそらくより多くの開発時間/労力が必要になることであり、アカウント内のトランザクションを同期する方法を考慮して、それぞれがバランスを正確に認識して更新するようにする必要があるかもしれません。常に。

そのため、ほとんどの場合、プロジェクトのニーズ、つまり現時点で開発時間が最もよく費やされていること、およびパフォーマンスとスケーラビリティが現実になったときに2番目のアプローチを実装するのではなく、ソリューションを将来にわたって保証する価値があるかどうかに帰着します。理論的な問題よりも。

1
aroth