<HOME  <お願い事項   <Access2002 TOP   <Access97 TOP   <サイト内検索
 MS-Access2000--稼働日テーブルを作る
   1 2 3



ココまでいろんなプロシージャ作ってきましたが、細かいのいろいろ作っていくことで、だいぶ慣れてこられたんじゃないかと思います。
「VBAって何ができるんですか?」っていう疑問が、少々ナンセンスだってことも、なんとなく理解いただけたんじゃないでしょうか。
プログラミングですから、「がんばればいろいろできる」「がんばらないと何もできない」っていうことなんで、「何ができるの?」っていう質問自体少々ピントが外れているわけです。

VBAを使って処理を作っていくためには、知っていることはひとつでも多い方がよいです。関数にしても、コードの書き方にしても、どんなことでも、ひとつでも手数が多い方がよいに決まってますよね。今すぐに役立ちそうでなくても、いつかきっと役にたつはず。サンプルとか、書籍に書いてあることとか、あらかじめいろいろ研究しておくとよいと思いますよ。VBAに限ったことではありませんけれど、プログラミングって、

だいたいどんな感じか掴むことができてきたら、プロシージャ作成のための3大要素(自薦)について、どんどん理解を深めていきましょう。

・変数
・条件分岐、ループ
・イベント

すでになにげにごらんいただいていることばかりですけれど、この3つについて、ひとつでも多くの知識や情報を持つことは、プログラミングの強い武器になります。VBAみたいなやつで何か処理を作ろうとしたとき、そのときにいろいろ調べたり考えたりするのでは、実は追っかけ間に合わないことも多いです。いろいろなサンプルとか書籍などを見ておいて、いろんな手法をあらかじめ蓄積しておくとよいでしょう。今役に立たないことでも、きっといつかプラスになりますよ。

祝日とか祭日とかをどうやって考えるかって、けっこう頭痛いですよね。
あと、会社独自の休日とかあったり、期の〆とかがちょっと中途半端な日にあったり・・・カレンダー的な役割を担うテーブルが必要になるときってあると思います。

今日は、こんな感じの「カレンダーテーブル」を作る処理を作ってみようかと思います。

このテーブルは、別コーナーでお話したテーブルです。このテーブルの使い道などについては、別コーナーの方にお立ち寄りいただければ・・・と思います。
今日は「処理の繰り返し、ループ処理」について、いろいろ挑戦してみましょう。

まあ、まず、新規にモジュールをひとつ作って、適当な名前のプロシージャをひとつ作ります。Subプロシージャでよいです。

と、こんな感じになりますよね。
んじゃ、いきますか。

この辺は、処理内容によってだいたいお決まりな記述が多いと思いますので、先に書いてしまいましょう。
変数をふたつ(db、r1)宣言して、それぞれにデータベースへの道筋と、今回の処理で使うテーブル名を代入しておき、変数r1に代入されたそのテーブルを、編集可能な状態で開きます。これで、「このデータベース内にある[稼働日テーブル]という名前のテーブルに、レコードを追加したり削除したり探し出して書き換えたりできる」という意味合いになります。
こういうのも、いちおうパターンはありますけど、ゆくゆくはくわしく理解しておかないといけなさそうですね。がんばりましょう。

今回は[稼働日テーブル]という名前のテーブルがあって、その中に[稼働日][分類][曜日]という3つのフィールドがあることを仮定して作業を進めます。[稼働日]は日付時刻型、[分類]は数値型、[曜日]はテキスト型です。
で、[稼働日]には、2001/1/1、2001/1/2、2001/1/3・・・と、日付を1日ずつずらして入力していきます。[曜日]にはその日が何曜日なのかFormat関数ではじき出した曜日を代入し、[分類]には、土曜日なら1、日曜日なら2、その他の曜日は0という数字を代入しようと思います。

このプロシージャで、1年分くらいの「稼働日データ」を作成して、後はその年のカレンダーを見ながら[分類]を書き換えていけばいいですよね。こうすれば、このテーブルを参照することで、毎年変動する「ハッピーマンデー」も柔軟に設定できるし、会社独自の休日や、特別扱いの日なども、3とか4とか数字を使えばいろいろ設定できると思います。


さて・・・VBAのような感じのプログラミング言語では、できるだけ短い構文にまとめて処理を作るというのが、基本概念になってます。
もちろん、短くするあまり処理が不完全では本末転倒ですんで、きちんと必要な処理は踏まえつつ、無駄のない書き方を心がけていくことが、すなわちトラブルの少ないプロシージャにつながっていく、というものです。2001/1/1から2001/12/31まで、365レコード分のレコードを作るなら、AddNewを365回繰り返せばいいわけなんですが、1行追加するごとに1日ずつ日付を増やしていく必要があります。
まあ、365回分の処理をずらーーーーっと書けばいいんですが、それじゃああんまりにも・・・。こういうとき、処理を必要な回数ループさせるように考えていきます。
ループ処理を作るときに大切なのは、前にもお話したことがありますが、いつループを抜けるのかということを明確にしておくことです。でないと、いわゆる永久ループになっちゃいますよね。

VBAで一般的に利用されるループの方法は、大きく分けるとふたつあります。

Do...Loopステートメント ←条件を満たすまで、処理を繰り返します。
For...Nextステートメント ←指定された回数、処理を繰り返します。

どちらでも同じような処理を作ることができると思います。365日分、ということがわかっていれば

For kazu = 1 To 365
  あれやこれや
Next kazu

こうすると、あれやこれやを365回繰り返すことになります。最初に「Kazuという変数は1から365までだよ」と教えておいてやり、NextのところでKazuを1ずつ増やしています。これで、Kazuが365になるまでくるくるくるくる処理を繰り返すわけです。

繰り返す回数が決まっているときはよいですが、何回繰り返すかはっきりしないときは、Do...Loopがいいかもしれないですね。

kazu = 0
Do While kazu < 10
  あれやこれや
  kazu =kazu + 1
Loop

DoからLoopまでが「ループ文」です。まず、kazuという変数をゼロにしておいて、ループに入ります。
Do While kazu < 10のところで、「kazuは10より小さい?」という判断をします。Whileというのは「〜の間」という意味になるので、「kazuが10より小さかったら、あれやこれやしてください」という意味になります。一番最初はkazuはゼロなので、10より小さいですね。なのであれやこれやします。で、kazuに1を足しておきます。

で、Loopという文章が見つかったら、Doまで戻ります。
今度もまた「kazuは10より小さい?」と聞かれます。今度はkazuは1です。やっぱりまだ10より小さいので、あれやこれやします。で、kazuに1を足します。Loopまで来たら、またDoに戻ります。・・・・
・・・・と、いうことを繰り返すことができるわけです。

同じDo Loopですが、Whileの他にUntilというのもあります。

kazu = 0
Do Until kazu = 10
  あれやこれや
  kazu =kazu + 1
Loop

仕組みはおんなじようなもんですが、Untilの場合は「〜になるまで」という意味合いになります。そこのところがWhileと違う。「kazuが10になるまで」繰り返すことになりますね。
上記のふたつの例だと、繰り返される回数はどちらも10回で、結果的には同じことになります。でも、

kazu = 0
Do While kazu <= 10
  あれやこれや
  kazu =kazu + 1
Loop

こうすると「10以下の間は」という意味になりますから、kazuが10になったときもあれやこれやするので、繰り返しの回数は11回になります。
ダイレクトに数を入れてるとわかりやすいんですが、たとえば、ひとつのテーブルの最後のレコードまで処理を繰り返す、なんてときは、テーブルの終わりを表すEOF(End of file)を使って

Do Until r1.EOF
  あれやこれや
  r1.MoveNext
Loop

と、こういう書き方になりますね。
あるいは、あらかじめそのテーブルの件数を確認しておいて、

kazu=r1.Recordcount
For kazu = 1 To kazu
  あれやこれや
Next kazu

こういうのもいけると思います。
はっきり言って、どれ使ってもループ処理を作ることはできると思います。要は、ちゃんと「いつまでループしなきゃならないのか」を指示してやること。これですね。なんか判断できる数とか、条件式がないと、ループさせることはできませんからね。


んじゃまずは、2001年1月1日から2001年1月31日まで、という範囲でループさせてみましょうか。
「何かが2001年1月31日になるまで処理を繰り返す」または「何かが2001年1月31日以下の間は処理を繰り返す」の、どちらかのやり方になりますね。まあ、2001年1月1日から2001年1月31日までの間が何日か、をDateDiff関数とか使って出して、繰り返しの回数の目安にしてもいいんですが、なんか返ってややこしいことになりそうな感じがしないでもないですが・・・でも、どの方法を使うかは、最終的にはお好みです。いろいろ試してみて、自分にとってしっくりくる方法を使っていけばよいと思いますよ。
わたしは比較的Do Until使いますね。っていうか、Do Untilではどう書くかな・・・ということをまず考えて、他の方法の方が効率よさそうかどうか少し考えたりします。それが正しいやり方っていうわけじゃないですよ。いろんな方法があって、どの方法がよいのか決めるとき、なんか基準がないと決められないと思うし、いろんな書き方をまんべんなく覚えるのも大変なので、まずDo Untilで考えるようにしてる、っていうだけのことなんです。

さて、そんなわけで、「何かが2001年1月31日になるまで処理を繰り返す」というループをしようかと思うんですけど、「何か」ってのをなんか考えないといけないですね。比較するんですから、ええと、何と比較するんでしょう?

「これから[稼働日テーブル]の[稼働日]フィールドに代入しようと思っている日付が、2001/1/31より大きいか小さいか」っていう比較をするんですよね。これを見失っちゃったら実も蓋もありませんぜ。[稼働日]に代入しようと思っている日付は、2001/1/1に1ずつ足して作っていこうと思います。つまり、「稼働日+αが2001/1/31になるまで」処理を繰り返すわけです。
「稼働日+α」は、「稼働日+1」ですね。日付時刻型のフィールドは、数値扱いですんで、1を足すと、翌日、っていうことになるんですよね。
この「稼働日+α」ってやつを、ループの中でうまいこと計算させていこうかと思うんですが、仮に「今回レコードに書き込む稼働日」を入れておく器を用意しておかないとならないんじゃないかと思います。それに、1を足して、1を足したものが、次のレコードで書き込みする稼働日、っていう感じで、どんどんリレーしていこうと思います。
ええと、そんなわけで適当な変数をひとつ宣言します。

わたしはAAAAAにしました。タイプはDate型です(日付時刻型)。なんでDate型なのかは、オッケーですよね。
ついでに、後で使おうと思ってるんですがByte型(256までの数値を入れられる、小さな数値型)の変数も設けちゃっとこうかな。これは後でもよいですけど、よかったらついでに追加しておいてください。何に使うかは後ほど。。。