Access (VBA)

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

 
(Windows 10全般 : Access 2016)
コントロールソースを別テーブルに動的設定したい
投稿日時: 22/12/13 19:13:36
投稿者: おーさん0729

数年Accessを使用してますが、初心者です。
 
フォームの中にあるテキストボックスのコントロールソースを1フィールドだけ、
別テーブルのものに変更したいです。
 
Aテーブル、Bテーブルとあり、
CフォームのレコードソースはAテーブルとしています。
そのCフォームのD、E、F...フィールドの中で、DフィールドだけBテーブルのデータをソースにしたいです。
 
よろしくお願いします。

回答
投稿日時: 22/12/13 21:11:50
投稿者: hatena
投稿者のウェブサイトに移動

AテーブルとBテーブルをリンクするフィールドが必要です
 
クエリで、そのリンクフィールドを結合して、それぞれのテーブルから必要なフィールドを表示させることができます。

投稿日時: 22/12/14 19:08:36
投稿者: おーさん0729

hatena さんの引用:
AテーブルとBテーブルをリンクするフィールドが必要です
 
クエリで、そのリンクフィールドを結合して、それぞれのテーブルから必要なフィールドを表示させることができます。

 
ほかのフィールドで結合させています。
 
    Dim db As Database 'テーブル
    Dim rsa As Recordset 'テーブルのレコード
Set db = CurrentDb
Set rsa = Pcurrentform.Recordset
 
naiyou = Me.ActiveControl.Name
 
Me(naiyou).ControlSource = "Aテーブル.フィールド"
 
としているのですが、できません。
 
よろしくお願いします。

回答
投稿日時: 22/12/15 12:59:50
投稿者: hatena
投稿者のウェブサイトに移動

引用:
ほかのフィールドで結合させています。

 
具体的にどのようなフィールドですか。
AテーブルとBテーブルにあるフィールドなら、クエリにAテーブルとBテーブルを追加して、フィールドを結合したて、表示したいフィールドをクエリに追加して、そのクエリをフォームのレコードソースとすればいいでしょう。
 

投稿日時: 22/12/15 19:11:32
投稿者: おーさん0729

hatena さんの引用:
引用:
ほかのフィールドで結合させています。

 
具体的にどのようなフィールドですか。
AテーブルとBテーブルにあるフィールドなら、クエリにAテーブルとBテーブルを追加して、フィールドを結合したて、表示したいフィールドをクエリに追加して、そのクエリをフォームのレコードソースとすればいいでしょう

 
オートナンバー型と長整数型にしています。
 
複数人でレコードを更新できるようにしたいのが最終目的です。
そのために、AテーブルとBテーブルをリンクさせて、
フォームにはAテーブルのソースを表示させ、
入力時(フォーカス取得時?)にフィールドのソースをBテーブルに切り替えて、
その入力内容をAテーブルに更新しつつ、フィールドのソースをAテーブルに戻す
ということをすれば、複数人の使用に耐えることができるのでは?と考えています。
 (見た目的にはAテーブルと変わらないように)
 
基本的には帳票フォームでの使用(新規作成・既存レコード編集)ですので、入力用の新フォーム作成はなしとなります。
 
よろしくお願いします。

回答
投稿日時: 22/12/16 10:55:31
投稿者: Suzu

引用:
複数人でレコードを更新できるようにしたいのが最終目的です。

 
を実現する為に
 
引用:
そのために、AテーブルとBテーブルをリンクさせて、
フォームにはAテーブルのソースを表示させ、
入力時(フォーカス取得時?)にフィールドのソースをBテーブルに切り替えて、
その入力内容をAテーブルに更新しつつ、フィールドのソースをAテーブルに戻す
ということをすれば、複数人の使用に耐えることができるのでは?と考えています。
 (見た目的にはAテーブルと変わらないように)

を お考えの様ですが、
 
それが、実装できたとして、
 
Aテーブルの あるフィールドのデータを編集しようとして
使用者1 が コントロールをクリック そのデータを編集した時、
 Bテーブルのレコードが更新され、それを Aテーブルにも更新しようとすると
 Aテーブル の 当該レコード に対し、レコードロックが必要です。
 
この時 使用者2 がAテーブルの 同じレコードの 別のフィールドのデータ(仮にこのソースは Cテーブル)
を編集した時 Cテーブルに対し 更新が行われ、
同時に Aテーブルの レコードにも編集を行おうとしますが
これは、既に 使用者1 がレコードロックを行っていますから、更新できません。
 
更新タイミングの時だけ、編集ロックが掛かるのだから、その可能性は低い とお考えかもしれませんが、
可能性は 低くとも ゼロではないです。
 
 
システム(仕組み)を 検討する際には、可能性が低くとも考慮は必要です。
 
希望通りに動かないのは、エラーが発生しているからなのか?
エラーの原因は?
エラーを発生させない為にはどうあるべきか?
もし、エラーが発生したら どうするのか?
 
使用者には、システムの中の処理の流れは判り得ません。
使用者は更新したつもりになっているけど、
 実際は更新されていない
 別の使用者の更新が優先される
使用者が気づけないまま、希望の処理とは違う処理が行われてしまえば
誰も 気付けず、間違ったデータになってしまいます。
 (エラーの時には、編集自体を無かったことにする事が多いです)
 
なので、仕組みを検討する場合には、可能性が低い事も考慮する必要があります。

回答
投稿日時: 22/12/16 11:46:51
投稿者: Suzu

使用者が、同じレコード/同じフィールド を 編集しないなら
 
T_Main    (Server)
Fld1    Fld2    Fld3    Fld4
1    A    B    C
があったとして、
 
※1 使用者1 が データを見る際に、見るレコードを 使用者1 のローカルテーブルにコピーします。
T_Main    (使用者1)
Fld1    Fld2    Fld3    Fld4
1    A    B    C
--------------------------------------
 
※2 このテーブル に対し、使用者1 が 更新をします。 同時に更新内容をローカルの T_Sub に 保存
T_Main    (使用者1) 【更新後】
Fld1    Fld2    Fld3    Fld4
1    A    J    C
 
T_Sub    (使用者1)
Fld1    Fld    oldValue    NewValue
1    Fld3    B    J
--------------------------------------
 
※3 T_Sub を元に、サーバーに編集内容を更新
   できるなら、更新クエリ
      UPDATE T_Main SET FLD2 = "J" WHERE (FLD1=1 AND FLD3 = "B";
      を発行し、エラーならその旨表示
    更新クエリなのは、T_Main(Server) のロック時間を短くする為と、
    エラー時に、ロックしたままの状態をを保持しない為
     (レコードセット更新では Edit から Undo 間 ロックしつづける)
 
T_Main    (Server)【使用者1編集反映】
Fld1    Fld2    Fld3    Fld4
1    A    J    C
--------------------------------------
 
 
※4 使用者2 が 使用者1 とほぼ同時にレコードを取得
T_Main    (使用者2)
Fld1    Fld2    Fld3    Fld4
1    A    B    C
--------------------------------------
 
※5 使用者2 がレコード更新
T_Main    (使用者2)【更新後】
Fld1    Fld2    Fld3    Fld4
1    A    B    K
 
T_Sub    (使用者1)
Fld1    Fld    oldValue    NewValue
1    Fld4    C    K
--------------------------------------
 
 
※6 使用者2 の変更内容を サーバーに反映
T_Main    (Server)【使用者2編集反映】
Fld1    Fld2    Fld3    Fld4
1    A    J    K
------------------------------------
 
で、可能でしょうが、
 
同じフィールドに対し 操作ミスを含め 更新が行われる可能性があるなら ダメです。
 
システムの 仕組みとして、
 使用者1 は Fld2 のみ 編集可能コントロールとする 様な 仕組みとするなら 良いでしょう。
 
 
ただ。。。
単票フォームなら、連結フォームとせず、非連結フォームとしてしまった方が楽でしょう。
 
更新可能が Fld2 のみ として
読み込み時
 Me![txt1] = rsa![Fld1]
 Me![txt2] = rsa![Fld2]
 Me![txt3] = rsa![Fld3]
 Me![txt4] = rsa![Fld4]
 
更新ボタンクリック時
  db.Excute "UPDATE T_Main SET FLD2 =""" & Me![Fld2] & """ WHERE FLD1=" & Me![Fld2], dbFailOnError
を投げれば良い。
 
レコード新規入力/レコード削除 は 別の仕組みが必要ですね。

投稿日時: 22/12/16 19:34:38
投稿者: おーさん0729

Suzu様
分かりやすい解説ありがとうございます。
 

Suzu さんの引用:

Aテーブルの あるフィールドのデータを編集しようとして
使用者1 が コントロールをクリック そのデータを編集した時、
 Bテーブルのレコードが更新され、それを Aテーブルにも更新しようとすると
 Aテーブル の 当該レコード に対し、レコードロックが必要です。
 
この時 使用者2 がAテーブルの 同じレコードの 別のフィールドのデータ(仮にこのソースは Cテーブル)
を編集した時 Cテーブルに対し 更新が行われ、
同時に Aテーブルの レコードにも編集を行おうとしますが
これは、既に 使用者1 がレコードロックを行っていますから、更新できません。

 
「データの競合」については、後で更新する使用者2のデータで問題ないです。
 (使用者1が使用者2の変更に気づいていなくても大丈夫です)
また、後述されている※1〜6で言うと、
 Fld3の変更として、B→J→KでもB→K→Jでも後で更新されるデータが格納されていれば問題ありません。
 
Suzu さんの引用:

使用者が、同じレコード/同じフィールド を 編集しないなら
T_Main    (Server)
Fld1    Fld2    Fld3    Fld4
1    A    B    C
があったとして、
 
※1 使用者1 が データを見る際に、見るレコードを 使用者1 のローカルテーブルにコピーします。
T_Main    (使用者1)
Fld1    Fld2    Fld3    Fld4
1    A    B    C
--------------------------------------
 
※2 このテーブル に対し、使用者1 が 更新をします。 同時に更新内容をローカルの T_Sub に 保存
T_Main    (使用者1) 【更新後】
Fld1    Fld2    Fld3    Fld4
1    A    J    C
 
T_Sub    (使用者1)
Fld1    Fld    oldValue    NewValue
1    Fld3    B    J
--------------------------------------
 
※3 T_Sub を元に、サーバーに編集内容を更新
   できるなら、更新クエリ
      UPDATE T_Main SET FLD2 = "J" WHERE (FLD1=1 AND FLD3 = "B";
      を発行し、エラーならその旨表示
    更新クエリなのは、T_Main(Server) のロック時間を短くする為と、
    エラー時に、ロックしたままの状態をを保持しない為
     (レコードセット更新では Edit から Undo 間 ロックしつづける)
 
T_Main    (Server)【使用者1編集反映】
Fld1    Fld2    Fld3    Fld4
1    A    J    C
--------------------------------------

 
やりたいことがこの※1〜3だと思います。
※1は「サーバーメインテーブル」から「使用者1ローカルメインテーブル」にカレントレコードをコピー。
※2はフォーム上では「使用者1ローカルメインテーブル」をソースにして、使用。更新時は「使用者1ローカルテーブル」が変更され、同時に「使用者1ローカルサブテーブル」に保存。
※3は「使用者1ローカルサブテーブル」をもとに「サーバーメインテーブル」を更新する
といった理解であってますか?
 
データの印刷やレポートの使用もありますが、こちらは「サーバーメインテーブル」をソースに設定すれば、最新の情報でアウトプットできるのではないかと思っています。
 
ご確認お願いします。[/quote]

回答
投稿日時: 22/12/19 09:01:06
投稿者: Suzu

引用:
やりたいことがこの※1〜3だと思います。
※1は「サーバーメインテーブル」から「使用者1ローカルメインテーブル」にカレントレコードをコピー。
※2はフォーム上では「使用者1ローカルメインテーブル」をソースにして、使用。更新時は「使用者1ローカルテーブル」が変更され、同時に「使用者1ローカルサブテーブル」に保存。
※3は「使用者1ローカルサブテーブル」をもとに「サーバーメインテーブル」を更新する
といった理解であってますか?

 
意図としては、そういう事です。
ただ、1〜3 と 4〜6 が別々の流れではありません。
1〜6 が全体として 一つの流れです。
 
それは、1レコードに対し複数人の同時編集を考慮して と言う事です。
 
それが、
引用:
「データの競合」については、後で更新する使用者2のデータで問題ないです。
 (使用者1が使用者2の変更に気づいていなくても大丈夫です)
また、後述されている※1〜6で言うと、
 Fld3の変更として、B→J→KでもB→K→Jでも後で更新されるデータが格納されていれば問題ありません。

 
Fld3 への 変更は、使用者2 のみが行っており
最終的に
---------------------------------------
Fld1 Fld2 Fld3 Fld4
1 A J K
---------------------------------------
こうなっています。
 
もう一度確認ください。
 
 
使用者2 のみの変更 つまり※5 の
---------------------------------------
Fld1 Fld2 Fld3 Fld4
1 A B K
---------------------------------------
が反映されれば良い と言う事であれば、T_Sub は必要ないです。
 
その場合は、※1〜※2 終了後
T_Main(使用者1)と同じレコードを T_Main(Server)から削除
T_Main(使用者1)のレコードを INSERT INTOステートメント で T_Main(Server)へ追加
でも良いです。
 
この処理のタイミングや仕組みを誤ると、
 
本来、使用者1より使用者2が後に更新。
  → 使用者1の変更を Serverに反映後、使用者2の変更がServer に反映
 
最終データ
---------------------------------------
Fld1 Fld2 Fld3 Fld4
1 A B K
---------------------------------------
となるはずが、
 
 
使用者1 より 使用者2 が後に更新
  → 使用者1 の変更が Serverに反映されず、使用者2の変更がServerに反映された後に
    使用者1 の変更が Server 反映されてしまい、使用者2の変更が 反映されない
---------------------------------------
Fld1 Fld2 Fld3 Fld4
1 A J C
---------------------------------------
となります。
 
そのタイミングや仕様に関しては考慮し調整ください。

投稿日時: 22/12/20 00:00:33
投稿者: おーさん0729

Suzu様、ありがとうございます。
 

引用:

Fld3 への 変更は、使用者2 のみが行っており
最終的に
---------------------------------------
Fld1 Fld2 Fld3 Fld4
1 A J K
---------------------------------------
こうなっています。
もう一度確認ください。

Fld3,4が別々に更新されているので合っています!
このようにしたいです。
 
引用:

使用者2 のみの変更 つまり※5 の
---------------------------------------
Fld1 Fld2 Fld3 Fld4
1 A B K
---------------------------------------
が反映されれば良い と言う事であれば、T_Sub は必要ないです。

「使用者2が反映される」ではなく、「後から更新したフィールドが反映される」にしたいので、
上記同様だと思います。
 
 
使用者の使うフォームのソースをローカルメインテーブルにして、更新時にローカルサブテーブルも更新。
そのあとに、サブテーブルをもとにサーバーテーブルに反映する。
また、レポートのソースはサーバーテーブルにする。
で合っていると思うのですが、
ローカルメインテーブルへのコピーするタイミングがフォームを開いた時だけのような気がします。
かといって、更新頻度を増やすと、使い勝手が...
と悩んでいます。
良いタイミングってありますかね?

回答
投稿日時: 22/12/20 08:30:53
投稿者: Suzu

引用:
「使用者2が反映される」ではなく、「後から更新したフィールドが反映される」にしたいので、
上記同様だと思います。

同様では無いと思っています。
使用者1 の Fld2 B→J が反映されていません。それで良いかは質問者さんが判断ください。
 
 
引用:
ローカルメインテーブルへのコピーするタイミングがフォームを開いた時だけのような気がします。
かといって、更新頻度を増やすと、使い勝手が...
と悩んでいます。
良いタイミングってありますかね?

それは、使い方やタイミングも判りませんので、質問者さんでお決めください。

投稿日時: 22/12/20 19:32:08
投稿者: おーさん0729

Suzu さんの引用:
引用:
「使用者2が反映される」ではなく、「後から更新したフィールドが反映される」にしたいので、
上記同様だと思います。

同様では無いと思っています。
使用者1 の Fld2 B→J が反映されていません。それで良いかは質問者さんが判断ください。
 
 
引用:
ローカルメインテーブルへのコピーするタイミングがフォームを開いた時だけのような気がします。
かといって、更新頻度を増やすと、使い勝手が...
と悩んでいます。
良いタイミングってありますかね?

それは、使い方やタイミングも判りませんので、質問者さんでお決めください。

 
Suzu様、ありがとうございます。
 
参考になんとかそれなりの形になりました。
更新タイミング等の課題はありますが、考えていきます。