Microsoft Access 掲示板

[登録時]2グループ組合せの自動採番 /管理番号連番自動入力

6 コメント
views
4 フォロー

お世話になります。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~の連番)
施設名      :テキスト型
(レコード)
TB1

<テーブル2: TM_国名cd>
(フィールド)
国cd   :数値型 ⇒数値3桁
国名   :テキスト型
※ISO企画の国コード3桁を利用

<テーブル3: T種別cd>
(フィールド)
種別cd   :数値型 ⇒数値3桁
種別名称 :テキスト型
(レコード)
TB2

[クエリ]
<Q_海外施設_施設ID>
テーブル1をベースにテーブル2,3のcdを連携させ各項目名を表示
Q1

[フォームの構成]
<フォーム1:クエリ検索フォーム>
検索フォームで絞り込みレコードを選択
↓ボタンから「新規登録/修正」フォーム2を開く
「修正ボタン」  ⇒修正フォーム(選択した「施設ID」に紐付いた値が入ったフォーム2を開く)
「新規登録ボタン」⇒新規登録フォーム(値が空のフォーム2を開く)
F1

<フォーム2s:登録修正用フォーム>
・非連結のテキストボックス(Tx)とコンボボックス(cmb)で各項目を作成
・コンボボックス(cmb)で選択した値のcdが更新後処理で自動で入る設定
・修正モードの際は、フォーム1で選択した「施設ID」に紐付いた値が表示さる
Fs1
Fs2

【質問】[実現したいこと]
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
keepit
作成: 2021/01/29 (金) 12:17:39
最終更新: 2021/01/29 (金) 16:03:57
通報 ...
1
hiroton 2021/01/29 (金) 17:16:32 7ce18@f966d

ざっくり読んでみて

1.新規登録モードの際、ユーザーが[cmb施設_種別名称]選択した後に、
[Tx連番]の値が、「Tx施設_国cd」と「Tx施設_種別cd」の組合せを1つのグループとして、
1~の連番(値がある場合最大値に+1)が自動で入るようにしたい

施設_国cd   :数値型 ⇒数値3桁
施設_種別cd :数値型 ⇒数値2桁

strWhere = "施設_国cd='" & Me!Tx施設_国cd & "' AND 施設_種別cd='" & Me!Tx施設_種別cd & "'"
↓

strWhere = "施設_国cd=" & Me!Tx施設_国cd & " AND 施設_種別cd=" & Me!Tx施設_種別cd

条件(SQLのWHERE句)の書き方の問題で、フィールドの型とデータの型を合わせる必要があります

strWhere = "施設_国cd='" & Me!Tx施設_国cd & "' AND 施設_種別cd='" & Me!Tx施設_種別cd & "'"

2.(1.)で種別名称を選択した後、[Tx施設ID]に、
数値8桁(国cd;3桁 + 種別cd;2桁 + 連番;2桁)という形式で自動で施設IDの値が入るようにしたい

Me!Tx施設ID = Format(Me!Tx施設_国cd, "000") & Format(Me!Tx施設_種別cd, "00") & Format(new連番, "00")

Format 関数
format関数はよく使う関数なのでいろいろ(検索とかして)勉強するといいですね

3

hiroton様
早速の返答、教えて頂きありがとうございます。
サンプルのファイルでうまくいきました。
(フィールド名とTxbox名が少し違うだけの本番用では何故かまだできませんが・・)
フィールドの型が数値型かテキスト型かで書き方がちがうのですね。

Format 関数の参考サイトも教えて頂きありがとうございます。行き詰まったときに参考にさせていただきます。

2
hiroton 2021/01/29 (金) 17:46:06 修正 7ce18@f966d

3.(1.2.)が実現できた場合

いくつか方法がありますが、基本は

kaikae処理

If 新規登録処理 Then
    施設ID = ほにゃらら
End If

という作りにすることです。
このフラグは、クエリ検索フォームでボタンのどちらを押したかで切り替わるものなので、例えば(良いサンプルではありません

クエリ検索フォーム上に、「新規登録モード」チェックボックスを配置
新規登録ボタン

Me!新規登録モード = True
Docmd.OpenForm "クエリ検索フォーム"

詳細/修正ボタン

Me!新規登録モード = False
Docmd.OpenForm "クエリ検索フォーム"

kaikae処理

If Forms!クエリ検索フォーム!新規登録モード Then
    施設ID = ほにゃらら
End If

のように作ると期待する動作ができます。クエリ検索フォーム側で処理することなのでもっと具体的な質問であれば各ボタンを押したときのコードを提示するようにしてください(質問自体新しく立て直したほうがいいかもしれません)

もう一度言いますが、この作りは良いものではありません

・修正モードの際は、フォーム1で選択した「施設ID」に紐付いた値が表示さる

こういう処理ができているようなので、登録修正用フォーム側に「新規登録モード」チェックボックスを置いて設定を変えるような形にすればいいでしょう

4

hiroton様
ご丁寧に模範例まで教えて頂きありがとうございます。

チェックボックスを使ったことがないド素人なのですが、
チェックボックスON/OFF(True/false)で新規登録モードと切り替えみたいなことができるんですね。
読んだ参考書では、新規登録モード(Touroku)と修正モード(kakikae)、同じフォームで処理出来るような仕様になっていていて、ただし修正モード(kakikae)では主キーのような管理番号は書き換え対象から外してあったりしたので、今回のようなことで困っていました。

色々試してみて、また新たな質問挙げさせてもらうかもしれません。
いつも本当にありがとうございます。

5
hiroton 2021/02/01 (月) 13:11:35 b3a2d@f966d >> 4

プログラミングのテクニックというやつですね
「新規か修正」、2つの状態を判断できればいいので「ONかOFF」2つの状態を持てるチェックボックスで代用するという流れです。IF文との相性がいい(コードが簡素)になるのもポイントです

その代わり、新規登録モード = Falseのとき、何モードなの?というのはコードを読んでも分かりにくいという面はあります


テキストボックスで実装してもいいですし、3つの状態を判断しなければならないとかだとチェックボックスだと厳しいなんてこともあります

クエリ検索フォーム
[モード]テキストボックスを配置

新規登録用
Me!モード = "Touroku"
Docmd.OpenForm "登録修正用フォーム"

修正用
Me!モード = "kakikae"
Docmd.OpenForm "登録修正用フォーム"

閲覧用
Me!モード = "etsuran"
Docmd.OpenForm "登録修正用フォーム"

登録修正用フォーム

Select Case Forms!クエリ検索フォーム!モード
Case "Touroku"
    施設ID = ほにゃらら
Case "kakikae"
    '修正用処理
Case "etsuran"
    '閲覧用処理(書き換え自体を禁止するとか)
Case Else
    MsgBox "モード指定が不正です"
End Select

先の回答の通りこのコード自体はあまり良いものではないですが、考え方としてはこういう流れになります

テキスト(文字)を使うとコードだけを見ても何をやっているのが分かりやすいというメリットもあります(Case "etsuran"の中で施設ID = ほにゃららとかあったら「おかしくない?」ってなるとか)

6

3つの状態を判断する方法もあるんですね。
ご丁寧にサンプルコード本当にありがとうございます。
チェックボックスとともに勉強、テストしてみます。