<HOME  <お願い事項  <Access2000 TOP   <Access97 TOP   <サイト内検索
  Ac2002--VBAの沼 > 別のテーブルへレコードを追加する
  



別のテーブルへレコードを追加する

前コーナーからの続きです。ふふふ。

まあ、たいていのことは、「追加クエリ」「更新クエリ」「削除クエリ」でできます。
というか、クエリ使った方が便利だし、処理も速いし、効率もいいです。

じゃあ、どういうときにAddNewだのUpdateだの使うのよ???という疑問が湧いてまいりますが・・・。
使わざるを得ないときも、たまにあるんですよ。たまに・・・。
繰り返しになっちゃいますが、「VBA使える=上級者」と思い込んでる人たちの言うことは、鵜呑みにしてはいけませんよ。
VBAが分からないから追加クエリを使うんじゃない。MS-Accessを使うならば追加クエリでの処理を先に考えるべきです。
私に言わせれば、なんでもかんでもコード書いて処理しようとする人とはすなわち、データベースの設計能力のない人です。
語るに落ちます。

使わざるを得ないときだけ、VBAでコードを書いてプロシージャを実行します。そう考えたほうがいい。
本当にやむをえないときもありますけれども、VBAを使わなきゃならないということは、データベース設計が甘くてダサダサだから・・・という状況がけっこう多い。できれば、コードなんか書かないほうがいい。書かないで済むならそうしてください。
書かないで済むようにするためには、テーブルの設計をしっかりとやることです。
テーブルの設計が甘いと、コードなんか書いてあとからえっちらおっちら処理しないと首が回らなくなる。
VBAでコードが書けることは確かにすごいことかもしれないけれど、シチュエーション的にはシオシオのときが多いので、あんまり喜ばしいことではありませんね。
「私はとても目がよくて手先が器用なので、自分で建てた家の雨漏りを、毎月40回も修復することができるんですよ」と自慢している人みたいなもんです。つまり、雨漏りのするような家を建てて済んでいるいうことですね。でも、建てちゃったんだし、今さら更地にして新しく家を建てるのも大変だし・・・という場合は、修復技術がものを言うかもしれませんけれどもね・・・。



では・・・どうやらVBAを使ってやらないとならなそうだなぁ・・・という状況の練習をしてみましょう。
まずは予習です。
テーブルから、別のテーブルへレコードを移す練習をしましょう。
移すといっても移動させるのとはちょっと違うんですけど・・・
テーブルAのレコードをテーブルBにコピーする、みたいな感じの処理をやります。

次のようなテーブルを用意してみてください。

[番号]というフィールドを主キーにしてます。
まあ、今日は練習なので、別に主キーとかなくてもいいんですけどね。
でも、テーブルを扱うプロシージャの場合、主キーに当たるフィールドがないテーブルって、ややこしいことになるよなぁ、ってこと、なんとなく理解なさってますですよね。

このテーブルは「社員の一覧」です。社員同士の識別は、まあ名前でも付けられないことはないんですが・・・
いちおうそれぞれに「番号」を付けていて、同じ番号の社員は二人といないという社則になっているので、これを主キーにしました。
給料は通貨型にしましたけど、円マークが出るのがちょっとうっとおしいなーと思ったもんで、画面の下のほうの書式で「数値」ってのを選んでます・・・と、いうところはVBAとは関係ないとこだし、お好きに調整してください。練習なので適当でOKです。

テーブルの中には、こんな感じで↑データを入力しました。
今日は練習なので、何件か入ってればOKです。
これが、移動元のテーブルになります。テーブル名は[社員テーブル]にしました。



まったく同じ構造のテーブルをもうひとつ作ります。

フィールド名は同じじゃなくてもいいんですが、データ型は同じにしておいてください。
テーブル名は[社員テーブル2]にしました。2は半角の数字にしてみました。

コチラは、レコードはなし。空っぽです。



これから作るコードのイメージなんですけど、
   [社員テーブル]の1レコード目を読み取る。
   [社員テーブル]の各フィールドの値を、[社員テーブル2]に追加する。
   [社員テーブル]の次のレコードに移動する。
   この処理を、[社員テーブル]の最終レコード(つまりEOF)まで繰り返す、

という処理になります。

[番号]を主キーにしていますから、いくら練習だからといっていいかげんなテストをしていると、エラーがバシバシ出ちゃう可能性があります。
皆さんが命令しないことは、Accessにはできませんので、慌てずに、必要なことをひとつずつ詰めていきましょう。



まず、処理の外枠です。
今回はテーブルをふたつ使うことになるので、レコードセットもふたつ用意します。
片方([社員テーブル])は、1行目から順番に最後まで読み取るだけなので「読取専用」として開こうと思います。一方、書き込むほう([社員テーブル2]は、当然のことながらレコードの追加をするわけなので、書き込みもできる状態で開きましょう。

わたしはこんな感じにしてみました。

では、この中に、処理を作っていくといたしましょう。



rs1(社員テーブル)を開いたら、1レコード目にカーソルを移動させておきます。

これやらなくても多分たいてい1レコード目になっててくれるとは思うんですが、相手はコンピュータで、こちらの都合を理解して処理を繰り返しているわけではありません。しかるべき指示は、必要か否か別にしてしかるべくしておくべきです。

次に、ループの外枠を作ります。

で、[社員テーブル2]のそれぞれのフィールドに、[社員テーブル]の値を代入します。

こんな感じかしら。



では、イミディエイトウィンドウから、テストしてみましょう。

カーソルピカピカ状態になりました?

カーソルピカピカにならず、なーんか画面が固まってるかも・・・という場合は、おそらく永久ループでは・・・。Ctrlキーを押しながらPauseキーを押して、処理を強制的中断させましょう。で、rs1.MoveNextを忘れていないかどうか、もう一度コードを眺めてみてください。
あと、何回も何回も繰り返しテストしちゃだめですよ。エラーが出て止まっちゃったらひとまずプロシージャを中断して、コードの内容を確認しましょう。



テーブルを見てみましょうか。

[社員テーブル2]に、データ入ってます?

ここまでできればしめたもんです。あとは、AddNewのところとか工夫すれば、いろいろなことに使えそうな気がします。
レコードの追加のところをもう一工夫してみましょうか。

テストが完了したら[社員テーブル2]のレコードを全部削除しておいてください。
左上のセレクタ部分を右クリックして全レコード選択し、ショートカットメニューから「レコードの削除」を選べば、全部消えますよ。

全レコード選択した後Deleteキーを押してもいいかもしれません。

なぜ消さなくちゃならないのかって?だって、また[社員テーブル]の1レコード目から読み取って追加するんですよ。[社員テーブル2]のデータがダブっちゃうじゃないですか。[番号]を主キーにしてますから、ダブりは禁物です。既にガメラのデータが入力されているところにもう一回ガメラのデータを追加しようとしたら、「インデックスが重複してます」みたいなえらそうなメッセージがバシバシ出て気分悪くなりますよ。
なぜダブっちゃうのかって?んもーーー!!!自分でお考えなさいっ!!!



では・・・。
全員、給料を500円カットして、[社員テーブル2]へ追加することになりました。
こんなふうにしてみましょう。


実行後、ふたつのテーブル、比較してみてください。

減ってます?
こんなふうに、ちょっとした計算式などを加えることで、更新した値を追加することも可能です。
どういうことができるかは、アイディア次第って感じですね。

確認できたら、[社員テーブル2]のレコード、全部削除しておいてくださいね。



じゃあ、次に・・・。
[社員テーブル2]のテーブルに、日付時刻型のフィールドを追加します。

で、AddNewの中に、一行付け加えます。Date関数を使って、このレコードが[社員テーブル2]に追加された日を記録するようにするわけです。これで、「AddNewした日」が、[社員テーブル2]に記録されていくようになります。

時間まで取りたい場合は、Now関数のほうが手軽かもしれませんね。

今度は、[社員テーブル2]の方、レコード削除せずにそのままにしておいてください。



次に・・・。
常に常に「追加」ではなくて、[社員テーブル]に既にあるレコードは追加をしない、[社員テーブル]にないレコードだけ[社員テーブル2]から追加するという処理を作ってみようと思います。

たとえばですね・・・。
[社員テーブル]側に、新たにひとり、メンバーが追加入力されました。
頼もしいです。

で、この人を、[社員テーブル2]にも入れたいんですよね。
え?入力すればいいじゃないかって?まあそりゃそうなんですが・・・。
でも今日はプロシージャ作りの練習ですし、とりあえずやってみましょうよ。ね。

ループの中身をこんな感じにしてみてはどうでしょう。

まず、今処理中の[社員テーブル]のレコードが、[社員テーブル2]に存在していないかどうか、Findメソッドを使って調べます。
で、一致するものがないまま[社員テーブル2]のEOFになった場合は、新規に追加する必要があるというわけなので、AddNewします。
一致するものがある場合は、[社員テーブル2]のEOFにはたどり着いてないはずなので、AddNewの処理のところは素通りするはずです。
ややこしいんですけど、Loopはrs1の方、Findはrs2の方を見ています。その辺をじっくり理解しながら書いてみてください。

これだけで十分なんですけれども、一致するものがある場合は、なんかメッセージ出してみましょうか。

実際にはいちいちメッセージが出たりしたらうざったいですけどね。でも、ちゃんと処理が成立しているかどうか確認する(デバッグ作業という)作業って、大切です。メッセージボックスをうまく活用して、テストをしてみてください。

レコード数が少ないので、何回かメッセージボックスが出て終わると思います。

メッセージボックスが出た社員は、Elseのところを通過したことになるので、AddNewはされてないはずですよね。
どうでしょう。できました?

[社員テーブル]にレコードを増やしながら、何回かテストをしてみてください。

例えば、[社員テーブル]の方に、社員が1件増えたとしますよね。
この状態でさっきのプロシージャをもう一回実行してみると、ばしばしとメッセージボックスが出ますが、「松井秀喜」の分だけはメッセージが出ないと思います。
つまり、増えた分だけ、[社員テーブル2]への追加対象となるわけです。

うまいこと動くことが確認できたら、メッセージボックスは出なくしておいてもいいかもしれないですね。



追加するだけでなく、両方のテーブルを比較して、給料の金額を更新する、なんてこともアリかもしれませんね。
下の例では、[社員テーブル]より[社員テーブル2]の方が給料が高額な場合、[社員テーブル]の給料に書き換える、という処理をやってます。

例えば、今、テーブルの中身が↑こんなふうになってるとします。
バラゴンさんの給料が、[社員テーブル2]の方がえらく多いんですよね。

コードは、こんなふうに書けばいけるんじゃないかと思います。

Ifばっかりでなんだか見にくいコードですけれど・・・。うまいこと条件判断させていってくださいね。
このプロシージャを実行すれば、バラゴンさんの給料は、[社員テーブル]の方の金額に修正されると思います。

こういう処理の成功不成功はFindメソッドの後ろの式の書き方にかかってきますね。
ヘルプでFindメソッドの書き方の例などを参考にして、範囲を広げていって下さい。