SQLで消費税の処理
こちらで書いた記事のご意見が気になったので少し。
目次
ご意見
> 99%は同意するが一つ言わせてほしい。SQLの最大の弱点は時間の扱いに弱いことで、RDBの理論的基盤の数学が時間を考慮してないからしょうがないとはいえ消費税みたいな時間で変化するマスタへの配慮が無さすぎる。
とのことですが、Window関数以前は、前後のレコードの処理が考慮されていませんでした。現在は、MySQLでもWindow関数が実装されたので、ほとんどの問題は解決されたと思います。
しかし、消費税率の変更程度であれば、通常はテーブルとデータを整備することで処理が可能です。
テーブル設計における消費税率について
消費税で考慮すべき点は、税率は、3種類(通常、軽減税率、非課税品目)あり、顧客(販売相手)に2種類(課税対象、課税対象外)あることにあります。
税率については、商品のカテゴリーに対して税率種別を付けるべきでしょう。
マスタ類の設計例
トランザクション類の設計例
消費税率の登録の仕方
非課税品目や、消費税がなかった時代のデータまで税率をゼロで登録しておくことがミソです!
SQLで処理するとこうなる
上のようなテーブル設計にして、消費税率を登録しておくと、SQLで処理するときは以下のようになります。
SELECT -- 中略 , ss.単価 * ss.個数 * tm.税率 * cm.消費税課税区分 AS 消費税額 -- 中略 FROM 売上テーブル sm INNER JOIN 売上明細テーブル ss ON sm.ID = ss.売上ID INNER JOIN 顧客マスタ cm ON sm.顧客ID = cm.ID INNER JOIN 商品マスタ pm ON ss.商品ID = pm.ID INNER JOIN 商品分類マスタ pc ON pm.商品分類ID = pc.ID INNER JOIN 消費税率マスタ tm ON sm.売上日 >= tm.適応開始日 AND sm.売上日 <= tm.適応終了日 AND pc.消費税区分ID = tm.消費税区分ID WHERE -- 以下略 ;
CASE式すら入らないということに注目してください。
ゼロにするときには、ゼロを掛ければ良い
このブログでも、何度か書いていますが、
・ゼロを得たいときにゼロを掛ける
・変化なしを得たいときにゼロを足す、あるいは1を掛ける
などの処理は、自然言語では行われない表現ですが、数式にするときに工夫すべきです。
つまり、仕様を決めるとき、
「顧客が課税対象のときは税率区分の税率を適用し、課税対象外(海外企業など)のときは消費税額をゼロとする」
などという会話がなされます。それをそのままプログラムにすると、とても複雑な処理が必要になります。
消費税課税区分(名前は課税係数の方が良いかも)を0と1にしておけば、
単価 * 個数 * 税率 * 消費税課税区分
という単純な数式で、すべての組合せの処理が可能になります。