複雑な計算式を DB化するテクニック ―元帳と決算帳票の作成

Access 2000 で学ぶ業務アプリケーション開発―経理システムを作ってみよう―
第6回
複雑な計算式を
DB 化するテクニック
― 元帳と決算帳票の作成 ―
金宏 和實
今回は経理システムのかなめである「元帳(総勘定元帳と補
助元帳)
」と「決算帳票(貸借対照表と損益計算書)
」を作成
します(図 1)
。前回作成した月次集計処理 * 1 というバッチ処
当月末残高 = 前月までの残高 + 当月の借方発生額
理で出力した元帳データ(T̲元帳)と,科目ごとに月単位の
-当月の貸方発生額
(貸方残の科目の場合)
発生額を集計した科目残高マスター(M̲科目残高)を基に,
これらのレポートを作成していきます。ただし,貸借対照表や
当月末残高 = 前月までの残高-当月の借方発生額
損益計算書の計算は後述するように複雑です。下手に計算式プ
+ 当月の貸方発生額
ログラムを実装してしまうと,後でメンテナンスするのが面倒
という計算式を使います。当月末残高から残高試算表を作成し
になります。そこで今回は「計算式そのものをメンテナンス可
たら,貸借のバランスが正しいかどうかをチェックして,損益
能なデータとして定義する」というテクニックを紹介しましょ
計算書と貸借対照表を仕上げるわけです。これら一連の作業を
う。経理システムに限らず,さまざまな業務処理で応用できる
コンピュータ化する一番のメリットは,残高試算表で試算する
必要がなくなることでしょう。総勘定元帳から一気に損益計算
アイデアなので,ぜひマスターしてください。
書と貸借対照表を作れるようになるのですから。
まずは総勘定元帳を作成する
それでは,総勘定元帳レポートを発行するフォームを見てみ
総勘定元帳は,各科目の金額が当月にどのように動いたか
ましょう(図 2)
。レポート発行用フォームでは,科目 CD(コ
(増減したか)を表す明細表です。手書きで経理処理をしてい
ード)を指定して印刷できるようにテキストボックスを配置し
たころは,まず仕訳伝票を起票し,総勘定元帳の該当する科目
ています。また,科目名表示用のテキストボックス(txt科目
のページに発生額を書きこんでいました。科目には借方残,貸
名)と科目検索フォーム* 2 を開くためのコマンドボタン(btn
方残のいずれかで科目の残高を計算するという属性があるので,
科目検索)も配置しています。科目 CDが入力された場合は,
(借方残の科目の場合)
その科目の元帳だけを印刷し,何も入力されなければ,すべて
図 1●今回は経理システムで最も重要な帳票を作成する
仕訳伝票
仕訳チェックリスト
第4回
第5回
金宏 和實 (かねひろ かずみ)
筆者には 3 人の子供がいます。長男は「こうしろうの
Mindstorms日記」の宏志郎,次男は和也。筆者のペンネー
ムには2 人の名前が1文字ずつ入っています。でも,実は長
女の名前が入っていません。彼女の名前は「ほのか」
。どう
やってペンネームに入れればいいでしょう? 金宏マルほ和實
にしようかな(^^;
216
H 2001 年 2 月号
図 2●総勘定元帳レポートを印刷す
るフォーム
総勘定元帳
貸借対照表
補助元帳
損益計算書
集計処理
今回作成する部分
* 1 第 5回までの月次集計処理を含
むデータベース(kei.mdb と
kei̲dt.mdb)は 本 誌 Web サ イ ト
(http://software.nikkeibp.co.jp/)でダ
ウンロードできます。
複雑な計算式を DB 化するテクニック
図 3●総勘定元帳レポートのサンプル
Office 2000 SR-1 は適用しましたか?
ところでみなさん,前回作成した仕訳チェックリストはうま
く印刷できましたか? ページ設定で横方向に設定しても,デー
タベースの最適化を行うと縦方向になってしまって,困られた
方はいらっしゃいませんでしたか?
実は初期のAccess2000には「データベースの最適化を行うと,
ページ設 定 が既 定 値 に戻 る」(http://www.microsoft.com/
JAPAN/support/kb/articles/J049/8/41.htm)というバグがありま
した。この問題は,Office 2000 Service Release 1(SR-1)で解消
されています。もし,まだ SR-1を適用されていなければ,ぜひ
インストールすることをオススメします。
の科目の元帳を印刷します。
総勘定元帳レポートを見てみましょう(図 3)
。このレポート
で重要なのは,どう金額が動いたかが見えることです。例えば
前月末残高は,科目残高マスターの各フィールドから次の計算
式で算出します。
(借方残の科目の場合)
表 1● W̲ 元帳のテーブル構造
NO
名称
データ型
サイズ
備考
1
科目 CD
テキスト型
4
主キー
2
科目名
テキスト型
20
3
前月末残高
通貨型
4
借方貸方区分
数値型
長整数型
前月末残高 = 前期末残高 + 当年借方-当年貸方
(貸方残の科目の場合)
前月末残高 = 前期末残高-当年借方 + 当年貸方
借方残か貸方残かは,科目マスターの借方貸方区分(0:借方,
ートのデータを計算し,それをプリントするようにプログラム
するには,複雑なクエリー処理を記述するなど結構面倒な手間
が必要です。
1:貸方)で判断し,明細部は元帳テーブル(T̲元帳)から印
業務アプリケーション開発では,処理効率はもちろん,開発
刷して借方/貸方の発生額を合計します。当月の残高は前月末
効率の向上も重要なテーマです。アプリケーションのライフ・
残高と上記の合計から求めます。
サイクルはどんどん短くなっているので,簡単にプログラミン
さて以上のことから,総勘定元帳レポートを作成するには,
1)元帳データ(T̲ 元帳)からデータをセレクトする
2)科目残高マスター(M̲科目残高)から前月末残高を計算す
る
の2点が必要なことがわかったと思います。
グできて,かつほかの人にもメンテナンスしやすいようなシス
テムを作ることを忘れてはいけません。
そこで今回は,元帳データと科目残高マスターから一気にレ
ポートを作成するのではなく,いったん計算用のワークテーブ
ルを作って計算結果を保存して,レポートを出力する方法を紹
介しましょう。この方法なら,ワークテーブルをレポートのレ
ワンポイント・レッスン
ワークテーブルを使ってメンテナンスを容易にする
コードソースとすればいいので,レポート作成そのものはぐっ
と簡単になります。
ここまで読んだ皆さんの多くは「元帳データと科目残高マス
ターさえあれば,直接レポートを作成するのは簡単だな」と思
総勘定元帳レポートを作成するためのワークテーブルは,科
ったかもしれません。しかし実は二つのテーブルから直接レポ
目残高マスターの計算結果を保存する「W̲元帳」
(表 1)と,
* 2 科目検索フォームの使い方は,
2000年 12月号の本連載を参照。
H 2001 年 2 月号
217
Access 2000で学ぶ業務アプリケーション開発
― 経理システムを作ってみよう―
元帳テーブルからデータのセレクトを行う「W̲元帳明細」
(表
は,W̲元帳と同様にWHERE条件でレコードをセレクトして出
2)の二つです。W̲元帳は,科目残高マスターと科目マスター
力します。こうしてW̲元帳とW̲元帳明細ができたら,それら
を等結合* 3 で結合したレコードセットから,科目 CD,科目名,
を等結合してクエリー「Q̲総勘定元帳」を作成します(図 4)
。
借方貸方区分を取り出して作成します。科目名を取り出すの
これで,総勘定元帳レポートのレコードソースができました。
は,印刷用のクエリーが複雑になるのを避けるためです。また
肝心の総勘定元帳レポートをデザインビューで見てみましょう
同時に,前述した計算式に従って前月末残高も出力します。印
刷フォームで科目 CDが指定された場合,W̲元帳は1レコード
(図 5)
。
総勘定元帳での並べ替えは,科目 CD,伝票日付,伝票番号,
だけになります。一方,W̲元帳明細は,T̲元帳から各項目を
明細番号の昇順に設定し,グループ化 * 4 は科目 CDに設定しま
取り出して作成します。フォームで科目 CDが指定された場合
す。図 5を見て,
「あれっ?」と思った方がいたらうれしいので
すが,科目の前月末残高が,科目 CDが変わったら出力される
表 2● W̲ 元帳明細のテーブル構造
科目 CDヘッダーではなく,ページヘッダーに配置されている
NO
名称
データ型
サイズ
備考
のがわかりますか? もちろんこれは,間違ったわけではなく,
1
元帳キー
オートナンバー型
長整数型
主キー
レポートを見やすくするための工夫です。科目 CDヘッダーに
2
科目 CD
テキスト型
4
ある改ページのプロパティを「カレント・セクションの前」* 5
3
相手先 CD
数値型
長整数型
に指定して,科目 CDが変わるたびに改ページが行われるよう
4
伝票日付
日付/時刻型
5
伝票番号
数値型
長整数型
同じように扱えるわけです。科目 CDフッターでは借方,貸方
6
明細番号
数値型
長整数型
の金額をそれぞれSUM関数 * 6 で集計しています。
7
摘要
テキスト型
30
8
相手科目 CD
テキスト型
4
9
借方金額
通貨型
10
貸方金額
通貨型
に設定していますので,ページヘッダーも科目 CDヘッダーと
科目 CDフッターとページヘッダーには,非連結 * 7 のテキス
トボックスが合わせて三つ配置されています。これらのテキス
トボックスの値は,標準モジュールではなく,レポートのクラ
図 5●「総勘定元帳レポート」をデザインビューで開いたところ
図 4●クエリー「Q̲ 総勘定元帳」
* 3 テーブルの結合(JOIN)には,
等結合(INNER JOIN)
,左外部結合
(LEFT JOIN)
,右外部結合(RIGHT
JOIN)の 3 種 類 の結 合 方 法 がある。
等結合では,双方のテーブルから結
合に指定したフィールドに同じ値を
218
H 2001 年 2 月号
持つレコードが選択される。左(右)
外部結合では,片方のテーブルの全
レコードともう一方のテーブルの結
合されたレコードが選択される。
* 4 グループ化の詳細は 2001年 1月
号の本連載を参照。
* 5 改ページのプロパティには「
(改
ページを)しない」/カレント・セク
ションの前」/「カレント・セクショ
ンの後」
,
「カレント・セクションの
前後」の四つの選択肢がある。
* 6 SUM関数は,引数として与えら
れたフィールドの値の合計を算出す
る関数。
* 7 データベースのテーブルなどか
ら直 接 データを取 得 しない場 合 を
「非連結」と呼ぶ。
複雑な計算式を DB 化するテクニック
リスト 1●総勘定元帳レポートのクラス・オブジェクトのコード
ス・オブジェクト* 8(この場合はReport̲総勘定元帳)
で設定します(リスト 1)
。(1)のページヘッダー・フォ
ーマット時の処理では,Dlookup関数 * 9 を使って基本
情報マスター(M̲基本情報)の月次締日を取得して
います。(2)の科目 CDフッターのフォーマット処理で
は,非表示でレポートに配置した借方貸方区分テキス
トボックスの値に従って,当月末残高(借方残高/貸
方残高)を計算しています。Dlookup関数による値の
取得は,レポートのクラス・オブジェクトに記述せず
に,テキストボックスのコントロールソースに設定す
ることもできますが,クラス・オブジェクトに書いた
方が見やすいでしょう。この例のように,クラス・オ
ブジェクトを使ってデータの取得や計算を行えば,レ
ポートのレコードソースを準備する標準モジュールや
フォーム・モジュールの処理をシンプルにすることが
できます。
Option Compare Database
Option Explicit
Private Sub ページヘッダー _Format(Cancel As Integer, _
FormatCount As Integer)
[月次締日] = DLookup("月次締日", "M_ 基本情報", _
"基本情報キー =1")
End Sub
(1)
Private Sub 科目 CD フッター _Format(Cancel As Integer, _
FormatCount As Integer)
If [借方貸方区分] = 借方貸方区分 _ 借方 Then
[借方残高] = [前月末残高] + [借方金額合計] _
- [貸方金額合計]
[貸方残高] = ""
Else
[借方残高] = ""
[貸方残高] = [前月末残高] + [貸方金額合計] _
- [借方金額合計]
End If
End Sub
(2)
集計情報や計算式の情報を
テーブルに持たせる
しかし単純に
総勘定元帳の処理はできました。次はいよいよ経理システム
「利益」と言っても,
開発後半戦のメイン・イベント,損益計算書と貸借対照表の
実 際 には売 上 総 利
作成です。まず損益計算書レポートのイメージをながめながら,
益 ,営 業 利 益 ,経
どんな仕組みが必要なのかを考えていきましょう(図 6)
。
常 利 益 ,税 引 前 当
図 6を見ると,まず階層構造になっていることに気が付きま
期 利 益 ,当 期 利 益
すね。売上高は商品売上高からサービス売上高までの四つの科
と五つのカテゴリに
目で構成されています。それぞれの当月発生/今期累計の金額
分かれ,それぞれ表
は科目残高マスターから求め,売上高にはその合計を印刷しま
3のように計算方法
す。注意してほしいのは,製品売上高やサービス売上高は科目
が異なります。それ
マスターに登録されている科目ですが,売上高は単なる集計用
に企業は「生き物」
の項目にすぎない,ということです。
ですから,科 目 は
売上原価は期首商品棚卸高以下の三つの科目の計算結果で
図 6●損益計算書レポートのサンプル
追 加 されたり使 わ
す。売上高から売上原価を引いた値が売上総利益になります。
れなくなったりします。計算式をプログラムの中にコードとし
つまり損益計算書というのは,その名の通り,収益−費用=利
て持たせると,
「もう科目の追加はできません」とか「変更で
益(当期利益)を求めるための帳票なのです。
きません」などというように,メンテナンス上の問題が発生す
* 8 Access 2000のソースコードは,
Accessクラス・オブジェクト(フォ
ームやレポートのソースコード)
,標
準モジュール,クラス・モジュール
の三つに分けて記述できる。
* 9 DLookupは選択条件を指定して,
テーブルやクエリーから特定のレコ
ードのフィールドを取得するために
使用する。DLookup("取得したいフィ
ールド名", "テーブルやクエリー名","
検索条件式")のように使う。
H 2001 年 2 月号
219
Access 2000で学ぶ業務アプリケーション開発
― 経理システムを作ってみよう―
る可能性があります。
す。例えば上に空白行を 1行作りたい場合は,この値を 2に設
そこで,冒頭に紹介したように今回のシステムでは,これら
定します。一方,集計レベルは計算の順序を指定します。集計
の集計情報や計算式を,テーブルにレコードとして持たせるこ
レベルが0の場合は,科目残高マスターからの金額の集計を意
とにします。損
味します。集計範囲開始と集計範囲終了には集計すべき科目
益計算書計算定
CDを範囲指定します。集計レベル1〜 Nのレコードは,集計値
表 3●損益計算書に印字する各「利益」とその計算
方法
分類
項目
A
売上高
a
売上原価
1
計算式
売上総利益
b
2
A− a
販売費および一般管理費
営業利益
C
営業外収益
c
営業外費用
3
1− b
特別収益
d
特別損失
4
5
減算 CDにマイナス要素のPLCDを記入します。集計レベルの1
義)を見てくだ
〜 Nは計算の順序を示します。このようにして,集計レベルの
さ い ( 表 4 )。
順に計算をしていけば損益計算書の階層構造に対応でき,つじ
PLCD(損 益 コ
つまのあった計算ができるのです。このテーブルをメンテナン
ード)はこのテ
スするフォームを作成しておけば,ユーザーが容易に計算定義
ーブルの主キー
を変更することができるでしょう。
ワンポイント・レッスン
でのレコードの
2+ C− c
税引前当期利益
e
の計算を意味します。加算 CDにプラス要素のPLCDを記入し,
で,テーブル内
経常利益
D
義 マ ス タ ー
(M̲PL 計 算 定
3+ D− d
法人税等
当期利益
4− e
位置を示します。
計算式をテーブルに保存するメリット
印刷名称は損益
損益計算書計算定義マスターにデータを登録する作業は,実
計算書の区分欄
は結構面倒です。しかし,プログラム中にコード番号を埋め込
に印刷する名称
んで, 特別計算
で ,改 行 数 は 1
る必要がないので,イレギュラーな処理のない構造的なプログ
を既定値としま
ラミングが可能になります。
なんてコメントを付けて計算処理を作成す
表 4●損益計算書計算定義マスター(M̲PL 計算定義)の例
PLCD
改行数
集計レベル
0001 (営業損益)
1
0
0002
売上高
1
0
5001
0003
商品売上高
1
0
5001
0004
商品卸売上高
1
0
5004
5004
0005
製品売上高
1
0
5002
5002
0006
サービス売上高
1
0
5003
5003
0007
売上原価
2
1
0008
期首商品棚卸高
1
0
5110
5110
0009
当期商品仕入高
1
0
5100
5100
0010
期末商品棚卸高
1
0
5120
5120
0012
売上総利益
2
2
0020
販売費及び一般管理費
2
0
5200
5600
0021
役員報酬
1
0
5200
5200
0022
給与手当
1
0
5210
5210
0023
雑給
1
0
5220
5220
0024
賞与
1
0
5230
5230
220
印刷名称
H 2001 年 2 月号
集計範囲開始 集計範囲終了
加算 CD1
今期累計
当月発生
¥0
¥0
5004
¥2,120,000
¥2,120,000
5001
¥120,000
¥120,000
¥2,000,000
¥2,000,000
¥500,000
¥500,000
¥500,000
¥500,000
¥1,620,000
¥1,620,000
¥66,667
¥66,667
0008
0002
加算 CD2
0009
減算 CD1
0010
0007
複雑な計算式を DB 化するテクニック
実はこのテクニッ
クは,15 年前に筆者
図 7●損益計算書レポートを印刷するフォ
ーム
が COBOL プログラ
補助元帳(相手先別元帳)を作るには
元帳データには,本文で説明している総勘定元帳のほかに,
マだった時代に考え
補助元帳(相手先別元帳)があります。これは,総勘定元帳を
たものです。決算書
科目 CDと相手先 CDをキーとして相手先別に分類した帳票で
の計算の仕方として
す。科目マスター(M̲科目)で,
「相手先有り」に設定されて
は,例えば科目コー
いる科目が対象となります。フォームやモジュールの構造は総
ド 3000 から 3999 ま
では売上高の科目で,
4000から 4999までが販売費および一般管理費などとルールを
勘定元帳レポートと同じですが,科目残高マスターではなく,
相手先別残高マスターを使う点と,科目 CDと相手先 CDでグル
ーピングを行う点だけが異なります。ぜひ,総勘定元帳レポー
トを例に,ご自分でプログラミングしてみてください。
決めておいて集計し,それ以降の計算はプログラム内に計算方
法をコードとして持つ方法が考えられます。自社のシステム開
発なら科目コードの体系そのものはそんなに変化しないので,
リスト 2●フォーム「F̲ 損益計算書」の一部
これも良い方法でしょう。しかし,もしその経理システムをほ
かの企業が使うとしたら,その企業の科目コードを経理システ
ム規定のコード体系に合わせてもらわなくてはいけません。筆
者の経験から言うと,科目のコード付けルールは業種や企業規
模で結構異なります。今回の方法なら,企業が従来から使って
いる科目コードをそのまま適用させることができます。
複数の関数に処理を分散する
Private Sub btn計算実行 _Click()
Dim intRet As Integer
Dim intMaxN As Integer
Dim i As Integer
If Not 項目設定([txt 期間終了日]) Then
Exit Sub
End If
DoCmd.Hourglass (True)
それでは損益計算書計算定義マスター(M̲PL計算定義)を
使って,損益計算書を作成する手順を解説していきましょう。
まず,印刷処理をキックするフォームからです(図 7)
。
このフォームには,計算実行,プレビュー,印刷,終了の四
つのボタンを配置します。フォームのロード時には,プレビュ
ー,印刷ボタンのEnabledプロパティをFalse(使用不可)に設
定し,計算実行ボタンがクリックされて計算処理が完了した時
点で,Enabledプロパティを True(使用可)にします。計算処
理に少し時間がかかるからです。期間開始日,終了日,会社名
などのテキストボックスには基本情報マスター(M̲基本情報)
のフィールドを表示しています。
計算実行ボタンが押された時の処理を見てみましょう(リス
intMaxN = 損益計算 _ 集計レベル _ 最大値取得()
intRet = 損益計算 _ 科目集計 _ 削除()
intRet = 損益計算 _ 科目集計 _ 残高()
intRet = 損益計算 _ 計算定義 _ クリヤ()
intRet = 損益計算 _ 計算定義 _ 集計()
For i = 1 To intMaxN
intRet = 損益計算 _ 計算定義 _ 計算(i)
Next i
intRet = 損益計算 _ 損益 _ 削除()
intRet = 損益計算 _ 損益 _ 出力()
(1)
(2)
(3)
(4)
(5)
MsgBox "集計しました。"
DoCmd.Hourglass (False)
btn プレビュー.Enabled = True
btn 印刷.Enabled = True
End Sub
ト 2)
。ポイントは,ほとんどの計算処理を複数の関数(Func-
H 2001 年 2 月号
221
Access 2000で学ぶ業務アプリケーション開発
― 経理システムを作ってみよう―
tion)に分散していることです。概略は,
計算 ̲計算定義 ̲クリヤ( )で,レベル0のレコードすべてについ
(1)M̲PL計算定義の集計レベルの最大値を取得
てフィールド「今期累計」と「当月発生」をクリアします。そ
(2)科目残高マスターの科目 CDごとに,今期累計と当月発生を
して,損益計算 ̲計算定義 ̲集計( )関数を使って,(2)で作成し
集計
た W̲科目集計を選択・集計し,M̲PL計算定義の今期累計,
(3)集計レベル0 の科目ごとに今期累計と当月発生を集計
当月発生フィールドに結果を格納します(図 9)
。
(4)集計レベル1 から最大値までの科目について,今期累計と当
集計レベルに応じて損益を計算
月発生を計算
(5)損益計算書印刷用のワークテーブルにデータを出力
リスト2の(4)は,集計レベル1から最大値(intMaxN)までの
計算処理です。For i = 1 To intMaxNが集計レベル1〜 Nに対応
という手順になります。
まず最初の(1)の処理で,M̲PL計算定義から集計レベルの最
大値(intMaxN)を取得します。リスト 2にはありませんが,
SELECT MAX(集計レベル) AS 最大値 FROM M̲PL計算定義
というSQL文 * 10 を使っています。
しています。損益計算 ̲計算定義 ̲計算(i)のコードを見てみま
しょう(リスト3)
。
まず,M̲PL計算定義で集計レベルが変数 iのレコードをセレ
クトしてレコードセットを作成します(リスト3の(1))
。次に,
(2)では,W̲科目集計というワークテーブルに,科目残高マ
その時点の集計レベルよりも小さい値の集計レベルを持つデー
スターの金額を集計します。事前に,損益計算 ̲科目集計 ̲削
タをセレクトして,レコードセットを作成します(2)。このレコ
除( )で W̲科目集計の全レコードを削除しておき,損益計算 ̲
ードセット(rs1)が集計対象になります。rsレコードセットの
科 目 集 計 ̲残 高 ( )
加算 CD,減算 CD(それぞれ 1〜 10まで登録可)で rs1レコー
で,今 期 累 計 と当
ドセットから対象のレコードをFind * 12 して(3),今期累計と当
月 発 生 を格 納 しま
月発生を加算もしくは減算していきます。i=1の計算が終了し
す(図 8)* 11。
た時点のM̲PL計算定義は,例えば図 10のようになっています。
図 8●リスト2の(2)の処理を実行後のワーク
テーブル「W̲ 科目集計」
続 いて(3)は,
集計レベル1の売上原価が計算されていることがわかりますか?
M̲PL計算定義で集
このようにして集計レベルの最大値まで計算を繰り返すと当期
計レベルが0の科目
利益が求まり,損益計算書ができあがるのです。
の処 理 です。こち
計算実行ボタンクリック時処理のラストは,またしてもワー
らも事 前 に,損 益
図 9●リスト 2の(3)の処理を実行後のテーブル「M̲PL 計算定義」
* 10 MAX関数はSQLの集計関数で,
指定されたフィールドの最大値を返
す。
* 11 損益計算 ̲科目集計 ̲残高( )で
は,科目残高マスターと科目マスタ
ーを等結合してセレクトする SQL文
222
H 2001 年 2 月号
を基にレコードセットを作成し,科
目マスターのBSPL区分と借方貸方区
分に応じて,今期累計と当月発生分
を集計している。
*12 Findはレコードセットから,指
定した条件を満たす行を検索するメ
図 10 ●リスト2の(4)で,i=1 について実行後のテーブル「M̲PL 計算
定義」
。集計レベル 1の売上原価が計算されている
ソッド。ADO(ActiveX Data Objects)
には DAO(Data Access Objects)の
ように FindFirstなどのメソッドがな
い。そこでリスト3では,Findを実行
する前に,MoveFirstでポインタの位
置をレコードセットの先頭に移動さ
せている。
複雑な計算式を DB 化するテクニック
リスト 3●損益計算 ̲計算定義 ̲ 計算( )のコード
Function 損益計算 _計算定義 _計算(level As Integer)
Dim strSQL As String
'計算レベルでM_PL計算定義をSELECT
Dim strSQL2 As String
Dim j As Long
strSQL = 損益計算 _SQL_定義計算(level)
strSQL2 = 損益計算 _SQL_定義計算 2(level)
(1)
(2)
Set cn = Application.CurrentProject.Connection
Set rs = New ADODB.Recordset
Set rs1 = New ADODB.Recordset
rs.Open strSQL, cn, adOpenDynamic, adLockOptimistic
rs1.Open strSQL2, cn, adOpenDynamic, adLockReadOnly
cn.BeginTrans
Do While Not (rs.EOF)
For j = 1 To 10
If Trim(rs.Fields(j) & "") <> "" Then
rs1.MoveFirst
rs1.Find "PLCD = '" & rs.Fields(j) & "'"
If Not rs1.EOF Then
rs![今期累計] = Nz(rs![今期累計], 0) _
+ Nz(rs1![今期累計], 0)
rs![当月発生] = Nz(rs![当月発生], 0) _
+ Nz(rs1![当月発生], 0)
Else
MsgBox "加算コード = " & rs.Fields(j) _
& "が見つかりません"
End If
End If
Next j
For j = 11 To 20
If Trim(rs.Fields(j) & "") <> "" Then
rs1.MoveFirst
rs1.Find "PLCD = '" & rs.Fields(j) & "'"
If Not rs1.EOF Then
rs![今期累計] = Nz(rs![今期累計], 0) _
- Nz(rs1![今期累計], 0)
rs![当月発生] = Nz(rs![当月発生], 0) _
- Nz(rs1![当月発生], 0)
Else
MsgBox "減算コード = " & rs.Fields(j) _
& "が見つかりません"
End If
End If
Next j
rs.Update
rs.MoveNext
Loop
cn.CommitTrans
rs.Close
rs1.Close
Set rs = Nothing
Set rs1 = Nothing
cn.Close
Set cn = Nothing
End Function
Private Function 損益計算 _SQL_定義計算(level As Integer) _
As String
Dim strSQL As String
Dim strWHERE As String
strWHERE = " WHERE 集計レベル = " & level
(3)
(3)
(1)
strSQL = "SELECT PLCD, 加算 CD1, 加算 CD2, 加算 CD3,"
strSQL = strSQL & "加算 CD4, 加算 CD5, 加算 CD6, 加算 CD7,"
strSQL = strSQL & "加算 CD8, 加算 CD9, 加算 CD10,"
strSQL = strSQL & "減算 CD1, 減算 CD2, 減算 CD3, 減算 CD4,"
strSQL = strSQL & "減算 CD5, 減算 CD6, 減算 CD7,"
strSQL = strSQL & "減算 CD8, 減算 CD9, 減算 CD10,"
strSQL = strSQL & "今期累計, 当月発生"
strSQL = strSQL & " FROM M_PL計算定義"
strSQL = strSQL & strWHERE
strSQL = strSQL & " order by PLCD"
損益計算 _SQL_定義計算 = strSQL
End Function
Private Function 損益計算 _SQL_定義計算 2(level As Integer) _
As String
Dim strSQL As String
Dim strWHERE As String
strWHERE = " WHERE 集計レベル < " & level
strSQL
strSQL
strSQL
strSQL
strSQL
=
=
=
=
=
"SELECT PLCD,"
strSQL & "今期累計, 当月発生"
strSQL & " FROM M_PL計算定義"
strSQL & strWHERE
strSQL & " order by PLCD"
(2)
損益計算 _SQL_定義計算 2 = strSQL
End Function
H 2001 年 2 月号
223
Access 2000で学ぶ業務アプリケーション開発
複雑な計算式を DB 化するテクニック
― 経理システムを作ってみよう―
クテーブル(W̲損益)への出力処理です(リスト2の(5))
。こ
ドウに出力した値をレビューした方が効率的なことがあるので
こでは,M̲PL計算定義からSELECT文でPLCD,印刷名称,改
す。しかし,このデバッグ用のコードを完全に削除しないでリ
行数,今期累計,当月発生のフィールドを選択し,レコードセ
リースしてしまったら…。こんなうっかりミスを防ぐために古
ットを作成して W̲損益に出力しています。なぜ,こんなこと
くから使われているテクニックを紹介します。
をしているのかと言うと,改行数に応じて空白のレコードを付
加して出力するためです。Accessのレポート上で改行をコント
ロールするのは困難だからです。具体的には次のように,
Do While Not (rs.EOF)
If rs![改行数] > 1 Then
For j = rs![改行数] To 2 Step - 1
まず標準モジュールにグローバル定数を宣言します。
Public Const ctDEBUG = True
デバッグのための処理は,
if ctDEBUG then
Debug.print 変数名
end if
rs1.AddNew
のように ctDEBUGが真の時のみ実行するように,必ず IF 文で
rs1.Update
くくります。そしてプログラム完成後,ユーザーに使ってもら
Next j
End If
rs1.AddNew
rs1![印刷名称] = rs![印刷名称]
うときに,標準モジュールの定数宣言の部分を,
Public Const ctDEBUG = False
のように書き換えます。
こうすれば,プログラムのあちこちにデバッグ用のコードを
rs1![今期累計] = Nz(rs![今期累計], 0)
埋め込んでいたとしても,ctDEBUGの値を修正するだけで,す
rs1![当月発生] = Nz(rs![当月発生], 0)
べてオフにできます。
rs1.Update
rs.MoveNext
一つの目的/一つの関数
今回のソースコード,特にリスト2を見て,
「処理を小分けに
Loop
改行数が1より大きい場合に,改行数に応じて空白行を出力し
しすぎではないか」と思われた方もいたかもしれません。確か
ています。このようにして作成した W̲損益をレコードソース
に個々の関数の機能を増やせば,関数の数を減らせるかもしれ
にして,損益計算書レポートを作成します。
ません。ですが筆者は「一つの関数が,一つの目的のみを果た
ワンポイント・レッスン
古典的なデバッグ・テクニック
変数の値を表示する「msgbox 変数名」のようなコードや,
す」ように作成することを心がけています。プログラムをわか
りやすいものにしたいからです。
筆者も20代のころは難しいプログラムを作ることに快感を感
じていました。複雑なロジックのプログラムを作成し一発で動
変 数 の値 の推 移 をイミディエイト・ ウィンドウに出 力 する
いた時なんか,ひとり悦に入っていました。しかし,業務用ア
「Debug.print 変数名」などのコードを,プログラムの中に入れ
プリケーションも工業生産物の一つです。いかに製造工程を簡
ることがあります。デバッグや実行後にどこで処理がおかしく
略化するか――これもソフトウエア開発者の腕の見せ所です。
なったかを見つけるための措置です。もちろん,Accessの開発
誌面の都合で説明できませんでしたが,貸借対照表も損益計算
環境にあるウォッチ式やブレークポイントを使ってデバッグす
書と同じ要領で作成します。詳細はmdbファイルをダウンロー
ることも可能ですが,複雑な処理ではイミディエイト・ウィン
ドしてお確かめください。ではまた!
224
H 2001 年 2 月号
A