Access (VBA)

Access VBAに関するフォーラムです。
  • 解決済みのトピックにはコメントできません。
このトピックは解決済みです。
質問

 
(指定なし : Access 2016)
DAOのMoveLastメソッドの失敗について
投稿日時: 23/02/06 21:23:26
投稿者: aokiiiii

Accessで案件管理システムを作成しています。
連結/非連結が混在するフォームにデータ入力後、DAOで新規レコードの登録を行いたいのですが、MoveLastメソッドが想定通り動いていないようです。
考えられる原因等や代替策について、アドバイスいただけますと幸いです。
 
●テーブルについて
オートナンバー型のID、テキスト形式のフィールドのほか、添付ファイル型のフィールドを置いています。
 
●フォームについて
フォーム上では、IDと添付ファイル型のフィールドのみ、連結のコントロールにしています。
他の入力項目は、非連結のテキストボックスにて入力します。
 
●不具合について
・フォーム上の添付ファイルフィールドにファイルを添付すると、連結コントロールのため、自動でレコードがテーブルに追加される。同じく連結のIDのボックスには10番が表示される。
・VBAのDAO MoveLastメソッドで最新のレコードに移動する。(直前に登録した10番が最新であると考えてのことです)
・DAOのEditメソッドで非連結のフィールドを登録すると、なぜか10番ではなく5番に登録されてしまう(過去のレコードに上書きされてしまう)
・続けて11番に新規レコードを登録した場合も、やはり5番に上書きされる。
・10番、11番のレコードには、添付ファイルのみが登録されている。他のフィールドは空白。
 
(上書きの対象となる5番のレコードは、Accessを閉じて開き直すと別のレコードになったりしますが、条件は特定できていません)
 
MoveLastメソッドのあたりに問題がありそうですが、VBAに誤り等があればご指摘頂けないでしょうか。
代替策も是非ご教授いただきたいですが、フォームをすべて連結にするのは避けたいです。
 
拙い説明ですみません。VBA(抜粋)と補足のコメントを記載します。
何卒よろしくお願いします。
 
———————————————
Dim rst As DAO.Recordset
Set rst = CurrentDb.OpenRecordset(“案件一覧”, dbOpenTable)
 
Me.Resresh 'コメント@
 
Dim saveDir As String
saveDir = “・・・・” & “\” & Me!ID 'コメントA
 
If Dir(saveDir, vbDirectory) = “” Then
MkDir saveDir
End If
 
rst.MoveLast 'コメントB
 
Set rstFiles = rst.Fields(“添付ファイル”).Value
 
While not rstFiles.EOF
   rstFiles.Fields(“FileData”).SaveToFile save Dir
   rstFiles.MoveNext
Wend
 
'コメントC
With rst
   .Edit
   .Fields(“日付”) = Me!日付
   .Update
End with
———————————————
 
コメント@
連結コントロールであるIDと添付ファイルとが紐づくよう、確認的にRefreshしています。
フォーム上のIDのテキストボックス(連結)には最新のID(例として10番)が表示されます。
 
コメントA
ここでMe!IDを取得していますが、10番です。
 
コメントB
ここが問題のようです。
このMoveLastメソッドの後に確認のために以下の式を挿入すると、10番ではなく5番が表示されてしまいます・・・。
MsgBox rst.Fields(“ID”)
 
コメントC
上記コメントBのとおり、最新のレコードに正しく移動できていないので、5番のレコードに上書きされてしまいます。

回答
投稿日時: 23/02/07 10:48:30
投稿者: Suzu

Accessはリレーショナルデータベースであり、
テーブルのレコードの並び順 に保証はありません。
 
dbOpenTable のレコードセットに対し、MoveLast を行ったからと言って、
ID が一番大きいレコードになる保証がありません。
 
・ID で Sort を行った上で、Move〜 を行う
・SQL(またはクエリ)で ORDER BY 句を使う
 
今回は、ID が画面上に表示されているのであれば
『最新』ではなく
・レコードセット対し
   Recordset.Index = "ID"
   Recordset.Seek "=", ID
     で ID を指定 を指定
・WHERE句を指定しレコードセットを開く
等で、指定 ID のレコードを特定する様にしましょう。
 
 
ただ・・
何故、連結フォーム上に、編集したいフィールドを連結しないのでしょうか?
日付を流動的にしたいなら、
 日付をコントロールソースにした連結コントロールを配し、非表示にする
 非連結コントロールに日付を入力させ、Save後にレコードセットを閉じ
 その日付の値を 連結コントロールに代入
で良いと思いますよ。
 
また、上記の場合には、
 OpenRecordset で開くのではなく
 Me.RecordsetClone でレコードセットを取得し、
 添付ファイル型フィールドの値からSaveを行えば良いのでは?

回答
投稿日時: 23/02/07 10:57:15
投稿者: sk

引用:
●フォームについて
フォーム上では、IDと添付ファイル型のフィールドのみ、連結のコントロールにしています。
他の入力項目は、非連結のテキストボックスにて入力します。

引用:
フォームをすべて連結にするのは避けたいです。

そのフォームのレコードソースにあるフィールドの値を編集するためのコントロールを
全て連結コントロールにしてしまえば、「フォームのカレントレコードと同じレコードを
DAO.Recordset オブジェクトを介して編集する」ようなコードは(少なくとも
「添付ファイル型のフィールドに格納されたファイルを任意のパスに出力する」部分を除けば)
全く不要であるはずですが、具体的にどういった目的からそのような処理を実行しようと
されているのでしょうか。
 
引用:
・フォーム上の添付ファイルフィールドにファイルを添付すると、
連結コントロールのため、自動でレコードがテーブルに追加される
同じく連結のIDのボックスには10番が表示される。

その際のフォームのカレントレコードが新規レコードならそうなるでしょうけど、
カレントレコードが既存のレコードならばそうはならないでしょう。
その辺りの判別や制御はされているのでしょうか。
 
引用:
●テーブルについて
オートナンバー型のID、テキスト形式のフィールドのほか、添付ファイル型のフィールドを置いています。

引用:
・VBAのDAO MoveLastメソッドで最新のレコードに移動する。
(直前に登録した10番が最新であると考えてのことです)

レコードセットを開く際にレコードの抽出条件や並べ替え順を
明示的に指定しない限り、そのような結果が返されることは
一切保証されません。
 
引用:
Set rst = CurrentDb.OpenRecordset(“案件一覧”, dbOpenTable)

Dim strSQL As String
strSQL = "SELECT TOP 1 * FROM [案件一覧] ORDER BY [ID] DESC"
Set rst = CurrentDb.OpenRecordset(strSQL, dbOpenDynaset)
 
----------------------------------------------------------------
 
[案件一覧]の全てのレコードを[ID]の降順に並べ替え、
その最初の 1 件のレコードのみを参照したい場合は
とりあえず上記のような形になさればよろしいでしょう。

投稿日時: 23/02/07 12:36:06
投稿者: aokiiiii

Suzu様
 
コメントいただきまして、ありがとうございます。
ご記載いただいたように、SeekメソッドでIDを利用して管理することにしました。
 
連結に変えたくない、というのはVBAを修正する時間と手間をあまりかけられないため、必要最低限で…という思惑がありました。
 
非表示のコントロールを置くことやRecordsetCloneなど、技術的なアドバイスもありがとうございました。
まだ現状勉強不足ですので、今後理解を深めていきたいと思います。
ありがとうございました。

投稿日時: 23/02/07 12:41:47
投稿者: aokiiiii

sk様
 
コメントいただきまして、ありがとうございました。
レコードセットを開く際の制御等、まったく考慮しておりませんでした。
今後さらに勉強したいと思います。
 
連結のフォームとしなかったのは、ネットのにわか知識ですが、複数ユーザで使用を想定しているツールということもあり、非連結のほうが適していそう、と考えて作成を始めたものです。
そしていまや、VBAの書き換え等の手間を考えると、非連結の仕組みはいじりたくないというのが本音でした。
 
手数の少ない修正として、MoveLastはやめ、Seekメソッドを挿入しIDから更新対象のレコードを選択する方法で改修し、目的は達成できました。
 
今後とも何卒よろしくお願いいたします。