- ベストアンサー
[VBA] ADOの Clone と AddNew
- 初心者向けに、VBAのADOのCloneメソッドとAddNewメソッドについての質問です。
- Cloneメソッドを使用してレコードのコピーを行い、AddNewメソッドで新しいレコードを追加していますが、If Not rs.EOF が必要な理由がわかりません。
- 一つ目の要約文と同様の内容ですが、特にエラーメッセージが表示されないようなので、EOFの確認は不要なのではないかという疑問もあります。
- みんなの回答 (5)
- 専門家の回答
質問者が選んだベストアンサー
我流の私で良ければ・・・(正しいのかは、専門家に聞いていただくとして) 1)rsClone での判別が正しいと思います。 ただし、> 次行からの処理 ではないと思います。 2)そのような話は聞いた事がありません。 VBA記述で気になった点 a)私なら、こう記述します > cnt = 0 > For Each myField In rsClone.Fields > rs.Fields(cnt) = myField > cnt = cnt + 1 > Next ↓ For cnt = 0 To rs.Fields.Count - 1 rs.Fields(cnt) = rsClone.Fields(cnt) Next b)変数名に気をつけます rsClone → rsC つまり、ドット?ピリオド?( . )の、あり/なしで同じ綴りになるものは使いません。 以下の ★ 部分の記述は間違いですよね > rs.Clone.Close ' ★ > Set rsClone = Nothing 参考になるかどうかわかりませんが、私が記述したとしたら以下の様な感じに (未検証ですので、雰囲気で・・・ということに) Dim rs As New ADODB.Recordset Dim rsC As ADODB.Recordset Dim i As Long rs.Source = "SELECT * FROM 名簿 WHERE 名簿 = '山田 太郎';" rs.Open , CurrentProject.Connection, adOpenStatic, adLockOptimistic If (Not rs.EOF) Then Set rsC = rs.Clone rsC.AddNew For i = 0 To rs.Fields.Count - 1 rsC(i) = rs(i) Next rsC.Update rsC.Close Set rsC = Nothing End If rs.Close rs を得る時にコピー元を抽出しておきます。 なかったら処理しない様に・・・・ なお、コピーする中で、オートナンバ「an」を除外するとしたら For i = 0 To rs.Fields.Count - 1 Select Case rs.Fields(i).Name Case "an" Case Else rsC(i) = rs(i) End Select Next の様にすると思います。 ※ rsC(i) = rs(i) は rsC.Fields(i) = rs.Fields(i) でも 上記は単なるコピーの例なので、コピー元が複数レコード存在する等々・・・ 修正点はいっぱいあると思います。
その他の回答 (4)
- 30246kiku
- ベストアンサー率73% (370/504)
#4です > ここを見たのですが、見る場所、理解が間違っていますでしょうか・・・ > http://msdn.microsoft.com/ja-jp/library/cc376486.aspx 見てみました。 コード例からしてみると EOF = True 判別で良いみたいですね。 Access2007のヘルプでは、 > Recordset から、指定した条件を満たす行を検索します。必要に応じて、検索の方向、開始行、および開始行からのオフセットを指定できます。条件が一致すると、カレント行の位置は、検出されたレコードに設定されます。条件を満たす行がない場合は、Recordset の最後 (または最初) に設定されます。 という記述のほかに、メモとして > レコードセットに対して Find メソッドを呼び出す場合で、レコードセット内の現在の位置が最後のレコードまたはファイルの最後 (EOF) の場合、何も検索されません。あらかじめ MoveFirst メソッドを呼び出して、現在の位置またはカーソルをレコードセットの先頭に設定する必要があります。 引数 SearchDirectionEnum の説明では、 > 一致するレコードが見つからない場合、レコード ポインタは EOF に移動します。 という記述もあるんですけどね。 言葉の遊びなのかもしれませんが、 ・「Recordset の最後」 ・「ファイルの最後 (EOF)」 使い分けている?表現を変えている?っていう事は、何かあるんじゃないですかね・・・ と疑ったわけです。 msdn での説明でも > 条件に合うレコードを検索できない場合、前方 (EOF = True) に検索していたときは、現在のレコードが Recordset オブジェクトの一番後ろに置かれます。 っていう表現で、EOF = True 判別されているので、ヘルプ内の表現 「Recordset の最後」=「ファイルの最後 (EOF)」 と、解釈した方が良さそうですね。(#4のコード例は、いらないという事で・・・) 迷わせてしまって申し訳ありません。
お礼
ありがとうございました。 色々悩ませてしまいましたが、結果的に最初の回答で問題ありませんでしたので #1をベストアンサーにさせて頂きます。 テキストの誤字から始まりましたが、色々検索したりテストしたり、ご意見もお聞きし、 大変勉強になりました。
- 30246kiku
- ベストアンサー率73% (370/504)
#3です たびたびの連投ですみません。 Find 後の EOF についてなんですが、私の環境では対象がなければ EOF = True となってました。 そういう動きを想定していたので、フムフム・・・ということでヘルプ等は参照してませんでした。 その中で、あの回答を目にし、改めてヘルプを読んでみると・・・ 私の場合、動作が食い違っていた時にはヘルプ側を信じて見る事をします。 で、その動きを再現する様にいろいろとやってみます。 (今もですが)#3ではその時間がないので・・・で記述していました 私の場合、Find を使ったものは、あまり作ってないので、 今後、ヘルプ通りの動きになったとしても、さほど影響は無いのですが・・・ どうしても再現できなかった場合、どちらでも動く記述にしておきますか・・・ 例えば、 Dim sS As String Dim bNext As Boolean ・・・・・・ ・・・・・・ sS = "山田 太郎" rsC.Find "名簿 = '" & sS & "'" bNext = True If (rsC.EOF) Then bNext = False Else If (rsC("名簿") <> sS) Then bNext = False End If If (bNext) Then ' 見つかった時の処理・・・ ※ Find はあまり使った事がないです。 Find よりも Filter を使った絞り込みの方を良く使ってました。 Filter 後は、RecordCount でレコード数を知る事が出来るし・・・ (EOF を見た単純ループでクルクル処理できる・・・・等など) Filter は Find より遅くなると思いますが、想定したデータ量で満足できる応答であれば・・・ ※ 今もチョコチョコと再現を試みていますが難儀しています(Vista + 2007) 現状では、 ・対象がなかったら EOF = True になるし、 ・他の部分 AbsolutePosition は負値になるみたい 惑わせてすみません。 回答としては、ヘルプ(仕様?)を提示すべきだったんでしょうか・・・ ※ #2で記述したものはそのまま生きると思います。 失礼しました。(識者の回答を待ってください)
お礼
MSのサイト見ましたが、EOFにならないのはDAOの場合でないでしょうか? ADOの場合、#3のお礼に記載した通りのようです。
補足
あ、すみません。 DAOならNoMatchプロパティ・・・は当然のこととして、 ADOの時EOFで判断出来ない、というヘルプが存在しているということでしょうか? ここを見たのですが、見る場所、理解が間違っていますでしょうか・・・ http://msdn.microsoft.com/ja-jp/library/cc376486.aspx
- 30246kiku
- ベストアンサー率73% (370/504)
#2です 連投すみません 1)について、私の勘違いもあって・・・件名は違いますが以下の#1さんの回答を参照ください。 Access 重複しないメールをテーブルに取り込む http://okwave.jp/qa/q8056866.html なので、Find は使わない方向が良いのかも・・・・
お礼
引き続きありがとうございます。 テキストには、Findの検索方向が「adSearchForward」(規定値)の場合、 レコードが見つからなかったらEOFと書いてあるのですが。 動きも確認したような・・・次回スクールで再度確認します。
- 30246kiku
- ベストアンサー率73% (370/504)
#1です 試されるという事なので、補足等記述できるように回答しておきます。 > 実は某PCスクールのテキストに・・・・ であれば、まずはソコソコ動くものを・・・ で、徐々に環境/条件を変化させて・・・以前の記述ではエラーになるね・・・とか? というストーリーも考えられます。 > 1.を疑問に思い講師に質問したところ、2.と言われたのです。 推測するに、たぶんですが ・ Find では必ず一致するものがある これが前提であり、If Not rs.EOF Then としたのは、テーブルが空だったら・・・・ という事になるんでしょうか。 チェックがチグハグの様な気がしますが、 元々の上位記述で、対象のレコードがなければ実行しない・・・・ とかしていれば、それなりに動くとは思いますけど・・・ (とは言っても、私は私のスタイルで記述しますけど) > rsのカレントがEOFだとAddNewでエラーになるから・・・ を素直に受け止めると、空のテーブルにレコードは追加できない・・・に、なると思います。 (やはり、何かストーリーがあるような気がします) 私が参考として提示したものは、rs を求める時にコピー元を求めており、 テーブルが空 / 対象がない 時には EOF が True になるので、まとめた判別が出来てます。 (コピー元があって、クローンを作るようにしています) で、コピー元があったら、それは rs のカレント=先頭になっているので、 Clone して クローン側の Bookmark 操作云々を省く事が出来ると思います。 なので、Clone 側に AddNew する事を、私はよくやります。 また、Clone して作った rsC の初期の位置は先頭(???) この辺は、ヘルプに記述があったような・・・で、確認してください。 (余談で、Filter は解除されたものになる?・・・とかも確認ください) ※ rs.Clone.Bookmark = rs.Bookmark も、変数名・・・・での記述ミスでしょうか ※ 次行 については、勘違いをしていました。 Find で求めた次の行(レコード)と・・・・失礼しました。
お礼
引き続きありがとうございます。悩ませてしまってすみません 本日、わざわざ別の校舎の講師に話を聞きに行きました。 結果は 1.rs→rsClone にすべき 2.AddNewがEOFでエラーになるという話はない ※その講師も「エラーになる」と言った講師からそのように習ったそうで 最初は「エラーになる」と言っていたのですが、 どこのテキストにもヘルプにも載っていない、実際EOFでもエラーにならないことを見せ、 確認してもらいました。 まず前提に、そのスクールのオリジナルテキストには誤字が多い、というのがあります。 通常は、テキストで説明された通り、基本に忠実なプロシージャが載っています。 テキストの解説には「対象のレコードがあった場合・・・」と書いてあって、 rsClobeでレコードを探してるのに If Not rs.EOF Then となっていることに 違和感を感じました。 >・Find では必ず一致するものがある >これが前提であり、If Not rs.EOF Then としたのは、テーブルが空だったら・・・・ >という事になるんでしょうか。 >チェックがチグハグの様な気がしますが、 チグハグですよね。 「rsがEOFだとエラーになるから」と言われた後、 「対象レコードがあった場合、という条件になっていないですよね」と言ったら、 「必ず一致する前提で進んでいますね」と言われました。 If Not rs.EOF Then は 「通常Openしたら先頭レコードがカレントですがEOFのこともあるので」 と言われました。 「そうしたら、EOFの時にコピーできるように対応してないのは何故ですか」と聞いたら 「テキストの例ですので、実務とは違います」と言われました。 そんなチグハグをおかしいと思わない講師にこれ以上聞いても 納得行く回答はされないだろうとあきらめ、 こちらに相談させて頂き、違和感を感じるのは私だけではないはずと確信し、 他の校舎の講師をわざわざ訪ねてみました。 愚痴になってすみません。 >rs.Clone.Bookmark = rs.Bookmark も、変数名・・・・での記述ミスでしょうか そうです!すみません。 これも直した上で、教えていただいたオートナンバーの処理も確認しました! ちなみにですが、 「イメージしやすいようにBookmarkの処理を入れていますが、なくても結果は同じです。」 と書いてありました。 (それなくてもイメージ出来るのに、そんなことより誤字をなくして欲しい・・・)
お礼
ご回答頂きまして、ありがとうございました。 非常に助かりました。 >1)rsClone での判別が正しいと思います。 安心しました。 rsCloneで氏名検索したのに、何故rsで判別?と悩んでしまいました。 クローンと複製元はカレントが同期するの?いやそうでもなさそうだし・・・と。 > ただし、> 次行からの処理 ではないと思います。 rsClone で山田太郎さんがいたら(EOFでなかったら)、rsにAddNewして値を代入・・・ とIFの中の処理のことを「次行からの処理」と表現してしまったのですが、 使い方が良くなかったでしょうか。 あ、下の方で書いて頂いたコードを拝見しましたが、複製元からクローンにコピーをされていますね。 元は「クローンで検索して、複製元にコピーする」の例だったのですが、 (初心者へのCloneメソッドの説明のための例なのでおかしいのかもしれませんが) そうではないと思われて「次行からの処理ではない」という意味でしたでしょうか。 >2)そのような話は聞いた事がありません。 実は某PCスクールのテキストに記載のあったプロシージャで (転記NGとのことですのでSELECT文など一部変えています) 1.を疑問に思い講師に質問したところ、2.と言われたのです。 あまりに腑に落ちないテキストと講師の説明を信用出来ず、 実際にADOを使われている方のご意見をお聞きしたかったのです。 ありがとうございます。 >a)私なら、こう記述します その方がわかりやすいですね! 参考にさせて頂きます。 >b)変数名に気をつけます >ドット?ピリオド?( . )の、あり/なしで同じ綴りになるものは使いません。 非常に役立ちます!ありがとうございます。 >以下の ★ 部分の記述は間違いですよね >> rs.Clone.Close ' ★ これは私の打ち間違いです。すみません。 これも変数名に気を付けると、間違いを防げそうに思います。 >参考になるかどうかわかりませんが、私が記述したとしたら以下の様な感じに どういう構造にしたらわかりやすいかなど、参考になります。 オートナンバの部分も、スクールに行った時に打ち込んで試してみます。 ありがとうございました。
補足
わざわざ補足するほどでもないかもしれませんが、修正し忘れたので・・・ >SELECT文など一部変えています 元々SELECT文使われていないです。条件等変更しました。