} I言語 Lesson4 家計簿の時間起動による自動入力化の学習


●家計簿には新聞代や電気代等ほぼ決まっていで人間が入力しなくても自動入力出来る物も有ります、そこで時間起動の機能を使った自動化の学習をします。
●まず最初に現状を調査し、どのようなプログラムとすれば良いか検討します。新聞代毎月27日前後3000円、電気代毎月12日前後ほぼ2万円、水道代2か月おき25日前後にほぼ2万円、火災保険12月28日前後3万円等が有ります。これでどのような物か整理します。
☆自動登録しようとしているデータは内容と年月日と金額です。まずキーは内容で良さそうなので家計簿内容実表に追加すれば良い事になります。
☆新たな項目として必要な物を検討します。
☆間隔を見ると毎月、2か月おき、12月と有るのでこの間隔を情報として持つ必要があます。どのような表現するかは色々考えられますが、今回はその月は月をそのまま書き、以外は先頭にMを付けて間隔を数値1文字で表現する方法としてみます。この方法で表現すると、毎月="M1"、2か月おき="M2"(1月を起点),12月="12"と成ります。
☆金額は決まった額の物と、決まっていない物があるので、決まっていない物は近い値を設定し、仮設定している旨の表示が必要と思われるので、仮設定を設け仮設定の時は"仮"、以外は空白とする事にします。
☆年月日は1回の自動登録の範囲に関係するので自動登録のタイミングを決める必要があります。今回は月末に翌月分を登録する事とします、よって年月日の年月は不要で日が必要と成ります。尚、日は前後となって居ますが、殆どが日を決めその日が銀行の休日の場合は前にずらす方法が多いのでこの方法を取りますが、銀行単位のカレンダーを作るのも大変ですので、インストールで提供されているカレンダーの稼働日を使って計算する事にします。 ここで1点問題が有るので注意が必要です、例えば日が1日とした場合1日が休日であると当然前は前月になってしまいます。このシステムでは内容はその月に1個と決めたので、毎月登録している場合は同じ月に同じ内容を作成しようとしてしまい、作成出来ない問題が発生します、この問題に対処する事も当然可能ですが、プログラムが結構複雑に成るので、今回は7日以前の物は日を前では無く後にずらす事で対応とします。
☆検討の結果、間隔、日、仮設定、金額を新たに家計簿内容実表に作成する必要があるとなりました。
■テーブル名=ZZZYAA_家計簿内容実表(追加項目)
■列名1=ZZZYAA_間隔 CHAR(2) (""=自動化対象外,"M1"=毎月、"M2"=1月から2か月おき,"12"=その月のみ)
■列名2=ZZZYAA_日 DECIMAL(2,0) (1から31まで)
■列名3=ZZZYAA_仮設定 NCHAR(2)(仮設定は"仮"以外は空白とする)
■列名4=ZZZYAA_金額(既に設定済)

(1.1)データ辞書に間隔、日、仮設定を作成します。(金額は設定済みなので不要です)

(1.2)家計簿内容実表に間隔、日、仮設定、金額を追加します。

(1.3)家計簿内容更新プログラムに間隔、日、仮設定、金額のデータを作成します。
◆1010 =IF{_DATA=}SET{.~+_日=0,.~+_仮設定=}EXIT{.~+_金額};
★間隔が空白の場合は時間起動は不要なので、日を0、仮設定を空白にしてEXIT{.~+_金額}で最後の金額の入力に行きます。
★I言語ではデータの最後の入力項目を解析し、その項目で'Enter'が押された場合更新処理に行くように設計されているので、必ず最後の入力項目で入力できるようにプログラムを作って下さい。
★「DATA={}.?.DATA&~+_日?]で宣言されている物のデータ名は「DATA={}」と「?.DATA&」と最後の「?」を除いた「.」と「~+_日」を合わせた「.~+_日」と成ります。

(1.4)該当データを登録した所です。

(2.1)ZZZZ010222で時間起動プログラムを作成します。
★3行目に「{LINE 1(1)/2 3/2}{2,,9}{(08,17),(50,99)}」と表示されています、ポイントは3番目の{(08,17),(50,99)}です、これがCHECK1で設定された内容を表示しているので入力出来る範囲を示しています、つまり08から17までと50から99までの間が入力できます。

(2.2)08から17までの時間が時間起動出来る範囲で、これは混在テーブルに時間起動の開始時間(ZZZZZZ_START_TIME,08:30)と終了時間(ZZZZZZ_LIMIT_TIME、17:30)が設定されているのを使って制限しています。開始時間をこれ以外早く又は遅くしたい場合は混在テーブルを変更する必要があります。

(2.3)時の08と入れると35から55までの5分おきのリストボックスが表示されます。ZZZZZZ_START_TIMEで指定された08:30にその日の起動予約をするようになって居るので時間起動は余裕を見て5分後から起動出来るようになっています、取りあえず08:55起動とします。

(2.4)M1は3行目が{(50,99)}となっているので50から99までを使用します、00から40まではメニュー起動ジョブが使い41から49まではメニュ-のCOPYで呼び出して使用します。今回は50と50を使用します。

(2.5)ここで起動するタイミングを指定します。色々なタイミングが考えられますは今回は毎月の稼働末日で翌月の登録とします。毎月はタイミングはMで稼働末日は 始末が"-"で何日を"01"とします。

(2.6)時間起動情報作成後"0"(選択)を押してメニュー作成画面行きます。

(2.7)M0、M1、M2は時間起動で設定いた値と同じ物を使いM3で複数のジョブを連続して起動出来るようになっています。今回はM3が"01"の1個のジョブで対応します。

(2.8)時間起動プログラムはPROGRAM=もSET=もDATA=も使えません。=で始まるセクションとして手入力で対応します。
◆100 =SET{WC.TODAY=_TODAY,W0.Y=WC.TODAY[1;4],W0.M=WC.TODAY[5;2]};
◆200 =COMPUTE{W0.M+=1};IF{W0.M>12}SET{W0.M=01}COMPUTE{W0.Y+=1};
◆300 =SET{WC.Y=W0.Y,WC.M=W0.M};
★数値を文字列に転送し、前に"0"付けた場合でも無視されないようにします。(数値のままでは"01"は"1"として扱われます)
◆400 =IF{WC.M@LENGTH=1}SET{WC.M='0'+WC.M};
★翌月の年「WC.Y」と月「WC.M」を計算しています。
◆500 =COMPUTE{W0=W0.M%2};
◆600 =IF{W0=1}SET{WC.M2=',''M2'''}JUMP{};SET{WC.M2=};
★奇数月は'M2'の間隔も採用します。「WC.M2に設定」
◆700 =SQL1{SELECT ~+_内容,~+_日,~+_仮設定,~+_金額
◆800 = FROM ?_MM?_家計簿内容実表
◆900 = WHERE ZZZYAA_間隔 IN('M1'?WC.M2?,'?WC.M?') ORDER BY 1};
★毎月「M1」か奇数月「?WC.M2?」か同じ月「?WC.M?」の間隔のデータを抜き出すSQLを実行します。
◆1000 =SQL1_NEXT:SQL1_NEXT{WN.~+_内容,W0.~+_日,WN.~+_仮設定
◆1100 = ,W0.~+_金額}JUMP{SQL1_END};
★1件づつ処理します。SQLは基本的には1件づつ処理しなくても、SQLだけで対応出来ますが、今回は件数も少なく、SQLだけでは複雑な処理となるので、1件づつ処理する事でプログラムをより簡単にしました。
◆1200 =IF{W0.~+_日<8}SET{WC.FUNC='MIN',WC.GL='>'}JUMP{};
◆1300 = SET{WC.FUNC='MAX',WC.GL='<'};
★8日以前は後方の一番小さい(MIN)稼働日、8日以降は前方の一番大きい(MAX)稼働日を選びます。JUMP{}のように空のJUMP命令は以降のセミコロン(;)2個を飛ばすので、一般的なプログラムのELSEと同じ動きをします。
◆1400 =SET{WC.~+_日=W0.~+_日};
★数値の日を文字列の日に転送します。
◆1500 =IF{WC.~+_日@LENGTH=1}SET{WC.~+_日='0'+WC.~+_日};
★日が1桁の物は先頭に"0"を付けて2桁にします。
◆1600 =SQL_SET{WC.~+_年月日}{SELECT ?WC.FUNC?(ZZZZZZ_DATE) FROM
◆1700 = ?_MP_ZZZZ?ZZ_CALENDAR_TABLE WHERE ZZZZZZ_HOLIDAY=' '
◆1800 = AND ZZZZZZ_DATE?WC.GL?='?WC.Y??WC.M??WC.~+_日?'
◆1900 = AND Z_CANCEL=' '};
★システム提供のカレンダー(?_MP_ZZZZ?ZZ_CALENDAR_TABLE)で稼働日を抜き出し年月日を決定します。

(2.9)2ページ目の説明です。
◆2000 =IF{WC.~+_年月日=}ERROR{カレンダー未作成};
★カレンダー無しはエラーとします。(データが一件もないとMAXやMINの付いた項目は1件のNULLデータが設定されるので、WC.~+_年月日に空白が設定されます)
◆2100 =SQL{UPDATE ?_MM?_家計簿実表 SET ?_Z_UPDATE_ADD?
◆2200 = ,?_VRE&W0.~+_金額?,?_VRE&WN.~+_仮設定? WHERE Z_CANCEL<>' '
◆2300 = AND ?_VRE&WC.~+_年月日? AND ?_VRE&WN.~+_内容?
◆2400 = AND NOT EXISTS(SELECT 0 FROM ?_MM?_家計簿実表 WHERE
◆2500 = LEFT(~+_年月日,6)='?WC.~+_年月日[1;6]?'
◆2600 = AND ?_VRE&WN.~+_内容? AND Z_CANCEL=' ')};
★削除済データは論理削除されているのでデータが存在します、よってUPDATEで追加します。
★年月と内容が一致のデータが有る場合は処理しません。
◆2700 =SQL{INSERT INTO ?_MM?_家計簿実表 (?_Z_INSERT_NAME?
◆2800 = ,~+_年月日,~+_内容,~+_金額,~+_仮設定)
◆2900 = SELECT ?_Z_INSERT_VALUE?,?_VC&WC.~+_年月日?
◆3000 = ,?_VC&WN.~+_内容?,?_VC&W0.~+_金額?,?_VC&WN.~+_仮設定?
◆3100 = WHERE NOT EXISTS(SELECT 0 FROM ?_MM?_家計簿実表 WHERE
◆3200 = LEFT(~+_年月日,6)='?WC.~+_年月日[1;6]?'
◆3300 = AND ?_VRE&WN.~+_内容? AND Z_CANCEL=' ')};
★年月と内容が一致のデータが無い場合INSERTします。
◆3400 =BACK{SQL1_NEXT};
★次のデータの処理に戻ります。
◆3500 =SQL1_END:
★これで終了です。

(2.10)操作でT(TEST)で実行してみると、「カレンダー未作成」のエラーが出ました。
★尚、このメッセージはサーバーで実行しないと出ません。
★実行はサービスが起動している為、画面上には実行中の画面は何も表示されないので注意して下さい。(Windowsはサービスから起動した処理は画面を表示出来ません)
★カレンダーは朝一の時間起動処理で作られますが、起動処理をまだ一度も実行していないのでカレンダー未作成で落ちてしまいました。作業を一旦中断して朝の起動処理を実行します。尚、本番のカレンダーを作ると同時にテスト用カレンダーも作られます。

(3.1)ZZZZZ010521の「時間起動の予約,中止,即実行」に行きます。朝の立ちあげ処理はM0=ZZZZ,M1=99,M2=99(SYSTEM START)ですので"0"で選択します。

(3.2)処理を実行したいので"RUN"を選びます。

(3.3)ここで開始したいジョブを選びますが、今回は先頭から全て実行したいので、最初のジョブを"0"で選びます。

(3.4)ここで全てのジョブを実行したいので"ALL"を選びます。

(3.5)しばらく実行後Endの文字が付いたメッセージが出れば正常終了です。
朝一の起動処理を実行するとカレンダーの次の稼働日の朝ーの処理がタスクスケジューラに記憶されます。時間起動させて良い場合はそのままにします、起動しては困る場合はZZZZ010521で起動予約をキャンセルして下さい。

(3.6)カレンダーが出来ているか確認してみます。ZZZZ010220の「メニュー テスト 本番 切り替え」に行き”YES"で切り替えます。

(3.7)ZZZZ010113の「カレンダー 検索」に行き検索します。テスト用カレンダーにもデータが作られている事が確認できました。
★カレンダーの春分の日と秋分の日は日が変動するので、確認し違う場合は修正する必要が有ります。
★ZZZZ010220の「メニュー テスト 本番 切り替え」を再度実行しメニューを本番に戻します。

(4.1)再度テスト実行すると「列名 'ZZZYAA_仮設定’が無効です」のエラーがでました。これは家計簿実表にZZZYAA_仮設定の列が設定されていないのが原因です。

(4.2)ZZZZ020226の「テスト テーブル 更新」最終列にZZZYAA_仮設定を追加します。

(4.3)ZZZZ010222で再度Tでテスト実行してEndで成功しました。

(4.4)ZZZZ010221で仮設定のDATA=を追加します。

(4.5)Tでテスト実行しすると電気代と新聞代が登録されましたので、これで完成です。
All Rights Reserved, Copyright (C) 2016-2016 Nobumichi Harasawa.