お世話になります。AccsessVBA勉強中の者です。
テーブル内の2つのフィールドの組合せで1グループとして、
連番フィールドにグループごとに連番 1~を自動挿入する、入力フォームを作成したいと思っています。
・別のスレッドで質問で教えていただいたAfterUpdateでのコードや
https://zawazawa.jp/ms-access/topic/468
・別のスレッドで「複数選択後、項目毎の自動採番について」
を参考にしましたが、うまくいかず、
お知恵をお借りできたら幸いです。
画像があり長文ですみませんが、よろしくお願いします。
※説明文が長すぎたかと思い、
サンプルのaccessファイルを下記にアップロードしました。
素人が作ったシステム、VBAコードで恐縮ですが、よろしくおねがいします。
【質問accessサンプル】
https://30.gigafile.nu/0212-c409331159b65ea6e9a47e39a0aaeee2d
[テーブルの構成]
<テーブル1: TG_海外施設_施設ID>
(フィールド)
施設ID :数値型(主キー) ⇒数値8桁(国cd;3桁 + 種別cd;2桁 + 連番;2桁)
施設_国cd :数値型 ⇒数値3桁
施設_種別cd :数値型 ⇒数値2桁
連番 :数値型 ⇒数値3桁(国cd+種別cdの組合せで1グループ、1~の連番)
施設名 :テキスト型
(レコード)
<テーブル2: TM_国名cd>
(フィールド)
国cd :数値型 ⇒数値3桁
国名 :テキスト型
※ISO企画の国コード3桁を利用
<テーブル3: T種別cd>
(フィールド)
種別cd :数値型 ⇒数値3桁
種別名称 :テキスト型
(レコード)
[クエリ]
<Q_海外施設_施設ID>
テーブル1をベースにテーブル2,3のcdを連携させ各項目名を表示
[フォームの構成]
<フォーム1:クエリ検索フォーム>
検索フォームで絞り込みレコードを選択
↓ボタンから「新規登録/修正」フォーム2を開く
「修正ボタン」 ⇒修正フォーム(選択した「施設ID」に紐付いた値が入ったフォーム2を開く)
「新規登録ボタン」⇒新規登録フォーム(値が空のフォーム2を開く)
<フォーム2s:登録修正用フォーム>
・非連結のテキストボックス(Tx)とコンボボックス(cmb)で各項目を作成
・コンボボックス(cmb)で選択した値のcdが更新後処理で自動で入る設定
・修正モードの際は、フォーム1で選択した「施設ID」に紐付いた値が表示さる
【質問】[実現したいこと]
1.新規登録モードの際、ユーザーが[cmb施設_種別名称]選択した後に、
[Tx連番]の値が、「Tx施設_国cd」と「Tx施設_種別cd」の組合せを1つのグループとして、
1~の連番(値がある場合最大値に+1)が自動で入るようにしたい
2.(1.)で種別名称を選択した後、[Tx施設ID]に、
数値8桁(国cd;3桁 + 種別cd;2桁 + 連番;2桁)という形式で自動で施設IDの値が入るようにしたい
3.(1.2.)が実現できた場合
[新規登録モード]では、自動で新たな連番と「施設ID」が採番されるので良いと思うのですが、
[修正モード]では国cd、種別cdを変更してしまった場合は、
主キーの施設ID8桁も自動で変わってしまいます。
[施設ID]8桁は他のテーブルとリンクしてしまっているため、
kaikae処理のUpdateの対象から、施設IDは除外したのですが、
何か良い運用方法はありますでしょうか?
案として、修正モードの際は、
国cd、種別cdは変更しないように運用してもらうよう、
「ユーザーに念を押して伝える」くらいしか思いつきませんでした。
4.[施設IDデータの持ち方としての相談]
※エクセルで整理管理していたものをアクセスへ移行したようなデータなので、
施設ID8桁(国cd;3桁 + 種別cd;2桁 + 連番;2桁)
このような組合せをAccessの主キーとして管理するのは、
後々問題ありそうでしょうか?
・すでにこのルールの[施設ID]で他のテーブルにデータを持っているので、
あまり変えたくはないのですが、
なんの関連性のない「連番ID」のような数値フィールドを新たに設けた方が後々良いのかどうかなど、
お気軽にご意見頂けたら大変ありがたいです。
[失敗したサンプルコード]
別スレッドで教えていただいたAfterUpdate()の
2つのコードを試してみましたが、
エラーとなってしまいました。
//◆★★年度選択後の_管理番号_連番自動採番_失敗1
Dim new連番 As Long
new連番 = Nz(DMax("連番", "TG_海外施設_施設ID", "施設_国cd='" & Me!Tx施設_国cd & "' AND 施設_種別cd='" & Me!Tx施設_種別cd & "'"), 0) + 1
'//↑エラーデバッグではこの行が指定される
Me!Tx連番 = new連番
Me!Tx施設ID = Me!Tx施設_国cd & Me!Tx施設_種別cd & Format(new連番, "000")
'//◆★★年度選択後の_管理番号_連番自動採番_失敗2
Dim new連番 As Long
Dim strWhere As String '//発行番号のグループの条件
strWhere = "施設_国cd='" & Me!Tx施設_国cd & "' AND 施設_種別cd='" & Me!Tx施設_種別cd & "'"
new連番 = Nz(DMax("連番", "TG_海外施設_施設ID", strWhere), 0) + 1
'//↑エラーデバッグではこの行が指定される
Me!Tx連番 = new連番
Me!Tx施設ID = Me!Tx施設_国cd & Me!Tx施設_種別cd & Format(new連番, "000")
[サンプルコード:フォーム2s:登録修正用フォーム ]
◆マークが付いている部分が、今回質問前に試してみた部分です。
Option Compare Database
Option Explicit
'===============================================================================
' ★★★1.保存ボタンを押した際の処理
'===============================================================================
Private Sub btnSave_Click()
If Nz(Me.Tx施設ID) = "" Then
MsgBox "訪問施設IDが入力されていません"
Exit Sub
Else
End If
'OpenArgsに何も入っていないときは終了します
If IsNull(Me.OpenArgs) Then
Call Touroku
Else
Call Kakikae
End If
'完了メッセージを表示しフォームを閉じます
MsgBox "保存しました。" _
, vbOKOnly + vbInformation _
, "保存"
DoCmd.Close acForm, Me.Name
End Sub
'===============================================================================
' ★★★2.[新規登録モード]レコードの新規登録_Touroku
'===============================================================================
Private Sub Touroku()
Dim oRS As DAO.Recordset
'テーブルを開きます
Set oRS = CurrentDb.OpenRecordset("TG_海外施設_施設ID", dbOpenDynaset)
'テーブルに新しいレコードを挿入します
oRS.AddNew
'フィールドを書き換えます
With Me
oRS("施設ID").Value = .Tx施設ID.Value
oRS("施設_国cd").Value = .Tx施設_国cd.Value
oRS("施設_種別cd").Value = .Tx施設_種別cd.Value
oRS("連番").Value = .Tx連番.Value
oRS("施設名").Value = .Tx施設名.Value
End With
'テーブルに保存します
oRS.Update
'レコードセットを閉じて終了します
oRS.Close
Set oRS = Nothing
End Sub
'===============================================================================
' ★★[新規登録時]国名_種別名_選択後のcdデータ反映
'===============================================================================
'//cmb施設_国名選択後_Tx施設_国cdの値を挿入
Private Sub cmb施設_国名_AfterUpdate()
Me.Tx施設_国cd.Value = Me.cmb施設_国名.Column(0)
End Sub
'===============================================================================
' ◆★★[新規登録時]cmb施設_種別名称_選択更新後の処理
'===============================================================================
'//cmb施設_種別名称_種別名選択後_Tx施設_種別cdの値を挿入
Private Sub cmb施設_種別名称_AfterUpdate()
Me.Tx施設_種別cd.Value = Me.cmb施設_種別名称.Column(0)
'//◆年度選択後の_管理番号_連番自動採番_失敗1
'Dim new連番 As Long
'new連番 = Nz(DMax("連番", "TG_海外施設_施設ID", "施設_国cd='" & Me!Tx施設_国cd & "' AND 施設_種別cd='" & Me!Tx施設_種別cd & "'"), 0) + 1
''//↑エラーデバッグではこの行が指定される
'Me!Tx連番 = new連番
'Me!Tx施設ID = Me!Tx施設_国cd & Me!Tx施設_種別cd & Format(new連番, "000")
End Sub
'===============================================================================
' ★★★3.検索フォームから選択した施設ID_テーブルからデータの値取り込みDAO
'===============================================================================
Private Sub Form_Open(Cancel As Integer)
Dim oRS As DAO.Recordset
'OpenArgsに何も入っていないときは終了します(登録モードのため)
If IsNull(Me.OpenArgs) Then
Exit Sub
End If
'テーブルを開きます
Set oRS = CurrentDb.OpenRecordset("TG_海外施設_施設ID", dbOpenDynaset)
'表示するデータを検索します
oRS.FindFirst "施設ID=" & Me.OpenArgs
'データが見つかったときは
If oRS.NoMatch = False Then
'フォームのテキストボックスなどを使ってデータを表示します
With Me
.Tx施設ID.Value = oRS("施設ID").Value
.Tx施設_国cd.Value = oRS("施設_国cd").Value
.cmb施設_国名.Value = oRS("施設_国cd").Value
.Tx施設_種別cd.Value = oRS("施設_種別cd").Value
.cmb施設_種別名称.Value = oRS("施設_種別cd").Value
.Tx連番.Value = oRS("連番").Value
.Tx施設名.Value = oRS("施設名").Value
End With
End If
'レコードセットを閉じて終了します
oRS.Close
Set oRS = Nothing
End Sub
'===============================================================================
' ★★★4.[修正モード]選択したデータのレコード書き換え処理_Kakikae
'===============================================================================
Private Sub Kakikae()
Dim oRS As DAO.Recordset
'テーブルを開きます
Set oRS = CurrentDb.OpenRecordset("TG_海外施設_施設ID", dbOpenDynaset)
'書き換え対象のデータを検索します
oRS.FindFirst "施設ID=" & Me.OpenArgs
'データが見つかったときはレコードの書き換え処理を行います
If oRS.NoMatch = False Then
'レコードを書き換え可能にします
oRS.Edit
'フィールドを書き換えます
With Me
'oRS("施設ID").Value = .Tx施設ID.Value '//Tx施設IDは書き換えから除外
oRS("施設_国cd").Value = .Tx施設_国cd.Value
oRS("施設_種別cd").Value = .Tx施設_種別cd.Value
oRS("連番").Value = .Tx連番.Value
oRS("施設名").Value = .Tx施設名.Value
End With
'テーブルに保存します
oRS.Update
End If
'レコードセットを閉じて終了します
oRS.Close
Set oRS = Nothing
End Sub
'===============================================================================
' ★★★5.閉じるボタンアクション
'===============================================================================
Private Sub btn_閉じる_Click()
DoCmd.Close
End Sub
ざっくり読んでみて
条件(SQLのWHERE句)の書き方の問題で、フィールドの型とデータの型を合わせる必要があります
strWhere = "施設_国cd='" & Me!Tx施設_国cd & "' AND 施設_種別cd='" & Me!Tx施設_種別cd & "'"
Format 関数
format関数はよく使う関数なのでいろいろ(検索とかして)勉強するといいですね
hiroton様
早速の返答、教えて頂きありがとうございます。
サンプルのファイルでうまくいきました。
(フィールド名とTxbox名が少し違うだけの本番用では何故かまだできませんが・・)
フィールドの型が数値型かテキスト型かで書き方がちがうのですね。
Format 関数の参考サイトも教えて頂きありがとうございます。行き詰まったときに参考にさせていただきます。
いくつか方法がありますが、基本は
という作りにすることです。
このフラグは、クエリ検索フォームでボタンのどちらを押したかで切り替わるものなので、例えば(良いサンプルではありません)
クエリ検索フォーム上に、「新規登録モード」チェックボックスを配置
新規登録ボタン
詳細/修正ボタン
kaikae処理
のように作ると期待する動作ができます。クエリ検索フォーム側で処理することなのでもっと具体的な質問であれば各ボタンを押したときのコードを提示するようにしてください(質問自体新しく立て直したほうがいいかもしれません)
もう一度言いますが、この作りは良いものではありません
こういう処理ができているようなので、登録修正用フォーム側に「新規登録モード」チェックボックスを置いて設定を変えるような形にすればいいでしょう
hiroton様
ご丁寧に模範例まで教えて頂きありがとうございます。
チェックボックスを使ったことがないド素人なのですが、
チェックボックスON/OFF(True/false)で新規登録モードと切り替えみたいなことができるんですね。
読んだ参考書では、新規登録モード(Touroku)と修正モード(kakikae)、同じフォームで処理出来るような仕様になっていていて、ただし修正モード(kakikae)では主キーのような管理番号は書き換え対象から外してあったりしたので、今回のようなことで困っていました。
色々試してみて、また新たな質問挙げさせてもらうかもしれません。
いつも本当にありがとうございます。
プログラミングのテクニックというやつですね
「新規か修正」、2つの状態を判断できればいいので「ONかOFF」2つの状態を持てるチェックボックスで代用するという流れです。IF文との相性がいい(コードが簡素)になるのもポイントです
その代わり、
新規登録モード = False
のとき、何モードなの?というのはコードを読んでも分かりにくいという面はありますテキストボックスで実装してもいいですし、3つの状態を判断しなければならないとかだとチェックボックスだと厳しいなんてこともあります
クエリ検索フォーム
[モード]テキストボックスを配置
登録修正用フォーム
先の回答の通りこのコード自体はあまり良いものではないですが、考え方としてはこういう流れになります
テキスト(文字)を使うとコードだけを見ても何をやっているのが分かりやすいというメリットもあります(
Case "etsuran"
の中で施設ID = ほにゃらら
とかあったら「おかしくない?」ってなるとか)3つの状態を判断する方法もあるんですね。
ご丁寧にサンプルコード本当にありがとうございます。
チェックボックスとともに勉強、テストしてみます。