'請求月数の分だけ、サブフォームにレコードを追加する
Dim i As Long, s As Long
With Me.T_月額マスタのサブフォーム1.Form.Recordset
'「ごとに請求」のコンボボックスで、以下の値が選択されている場合
If Me.入金月頻度 = "2ヶ月" Then
s = 2
ElseIf Me.入金月頻度 = "半年" Then
s = 6
ElseIf Me.入金月頻度 = "1年" Then
s = 12
End If
For i = 0 To 月数 Step s
.AddNew
![契約番号] = Me.txt契約番号
![月額] = Me.月額
![入金月] = DateAdd("m", i, 開始年月)
![税率] = Me.税率
![税の処理] = Me.税の処理
.Update
Next
End With
'請求月数の分だけ、サブフォームにレコードを追加する
Dim i As Long
With Me.T_月額マスタのサブフォーム1.Form.Recordset
For i = 0 To 月数
.AddNew
Me.T_月額マスタのサブフォーム1.Form![契約番号サブ] = Me.txt契約番号
Me.T_月額マスタのサブフォーム1.Form![月額サブ] = Me.月額
Me.T_月額マスタのサブフォーム1.Form![入金月サブ] = DateAdd("m", i, 開始年月)
Me.T_月額マスタのサブフォーム1.Form![税率サブ] = Me.税率
Me.T_月額マスタのサブフォーム1.Form![税の処理サブ] = Me.税の処理
'「ごとに請求」のコンボボックスで、以下の値が選択されている場合
If Me.入金月頻度 = "2ヶ月" Then
i = i + 1
ElseIf Me.入金月頻度 = "半年" Then
i = i + 5
ElseIf Me.入金月頻度 = "1年" Then
i = i + 11
End If
Next
End With
Option Compare Database
Option Explicit
Dim dicIndex As Object
Private Sub Report_Open(Cancel As Integer)
Set dicIndex = CreateObject("Scripting.Dictionary")
End Sub
Private Sub 詳細_Format(Cancel As Integer, FormatCount As Integer)
Dim indexString As String
indexString = Left(Me!薬品名 & String(12, "・"), 12) & Format(Me.Page, "@@@")
With dicIndex
If .Exists(Me!薬品名のフリガナ.Value) Then
.Item(Me!薬品名のフリガナ.Value) = indexString
Else
.Add Me!薬品名のフリガナ.Value, indexString
End If
End With
End Sub
Private Sub レポートフッター_Format(Cancel As Integer, FormatCount As Integer)
Static isExecuted As Boolean
Dim arr
Dim s
Const colCount = 3 '1ページの段数
Const rowCount = 30 '1ページの行数
Dim CNT As Long
Dim colName As String
If Not isExecuted Then
'並び替え用配列の準備
arr = dicIndex.Keys
'並び替え用配列を出力順に並び替え
Call ArrayListSort(arr)
'出力順にデータを取り出して段組みに振り分ける
CNT = 0
For Each s In arr
colName = "txt目次" & CNT \ rowCount Mod colCount
Me(colName) = Me(colName) & dicIndex.Item(s) & vbCrLf
CNT = CNT + 1
Next
isExecuted = True
End If
End Sub
Option Compare Database
Option Explicit
Dim indexText As String
Dim keepIndexString As String
Private Sub 詳細_Format(Cancel As Integer, FormatCount As Integer)
Static preItemName As String
'仮データの確定処理
If preItemName <> Me!薬品名 Then
indexText = indexText & keepIndexString
preItemName = Me!薬品名
End If
'仮データを作成
keepIndexString = Left(Me!薬品名 & String(12, "・"), 12) & Format(Me.Page, "@@@") & vbCrLf
End Sub
Private Sub レポートフッター_Format(Cancel As Integer, FormatCount As Integer)
Static isExecuted As Boolean
Dim arr
Dim s
Const colCount = 3 '1ページの段数
Const rowCount = 30 '1ページの行数
Dim CNT As Long
Dim colName As String
If Not isExecuted Then
'最後の明細の仮データの確定処理
indexText = indexText & keepIndexString
'並び替えのために配列にする
arr = Split(indexText, vbCrLf)
'配列を並び替え
Call ArrayListSort(arr)
'段組みに振り分ける
CNT = 0
For Each s In arr
colName = "txt目次" & CNT \ rowCount Mod colCount
Me(colName) = Me(colName) & s & vbCrLf
CNT = CNT + 1
Next
isExecuted = True
End If
End Sub
'ArrayListSort関数は省略
Private Sub 詳細_Format(Cancel As Integer, FormatCount As Integer)
If FormatCount = 1 Then
data = data & Left(Me!薬品名 & String(12, "・"), 12) & Format(Me.Page, "@@@") & vbCrLf
End If
End Sub
Private Sub レポートフッター_Format(Cancel As Integer, FormatCount As Integer)
Static isExecuted As Boolean
Dim arr
Dim s
Const colCount = 3 '1ページの段数
Const rowCount = 30 '1ページの行数
Dim CNT As Long
Dim colName As String
If Not isExecuted Then
'並び替えのために配列にする
arr = Split(Data, vbCrLf)
'配列を並び替え
Call ArrayListSort(arr)
'段組みに振り分ける
CNT = 0
For Each s In arr
colName = "txt目次" & CNT \ rowCount Mod colCount
Me(colName) = Me(colName) & s & vbCrLf
CNT = CNT + 1
Next
isExecuted = True
End If
End Sub
Private Sub ボタン_Click()
With Me.RecordsetClone
.MoveFirst
Do until .EOF
.Edit
!Chk1 = False
!Chk2 = False
!Chk3 = False
!Chk4 = False
.Update
.MoveNext
Loop
End With
End Sub
もしかして、AddDataのコードが、上記の他にありませんか?
例えば、
【うどん屋プロシージャの呼び出し】
Call うどん屋("きつねうどん", "400円")
【うどん屋プロシージャの記述】
……
エラーメッセージの通りだと思います

新しく追加したプロシージャは
Report_Open
なので開く時プロパティに[イベント プロシージャ]
を設定してくださいArrayListSort関数も省略しているので適当な場所に入れておいてください(汎用的に使える関数なので標準モジュールに入れてしまってもいいと思います)
[イベント プロシージャ]
は各イベントのプロパティのプルダウンから常に選べるようになっているプロパティですが、これを指定すると、それぞれで専用のプロシージャを呼び出しなさいという指定になります(レポートの開く時ならReport_Open
とか)[イベント プロシージャ]
を選んで[...]をクリックすると、対応するプロシージャが自動で生成されますが、コードをコピペしても[イベント プロシージャ]
は自動で設定はされないので、この部分は自分でやる必要があります。今の問題点は「
詳細_Format
で正確なページ数が取得できない」なので「取得後の目次データの取り扱いをどうするか」は問題の解決にならないです一応いろいろ眺めていたら解決案は出てきました(公開する段階にないですが)
これ自体は>> 7で出来てます。いろいろ議論の余地もあるかと思いますが、現時点で索引表示のためにワークテーブルを使う必要性は感じないです
以下、フォームのイメージです。
①開始時間を入力する。店舗を選ぶ。
・出荷時間のリストボックス
店舗A,30
店舗B,90
店舗C,…
・開始時間のテキストボックス:9:00
・終了時間のテキストボックス:
…,店舗名,開始時間,終了時間
1,
②終了時間を計算する。
・出荷時間のリストボックス
店舗A,30
店舗B,90
店舗C,…
・開始時間のテキストボックス:9:00
・終了時間のテキストボックス:9:30
…,店舗名,開始時間,終了時間
1,
③店舗名、開始時間、終了時間を計算。
・出荷時間のリストボックス
店舗A,30
店舗B,90
店舗C,……
・開始時間のテキストボックス:9:00
・終了時間のテキストボックス:9:30
…,店舗名,開始時間,終了時間
1,店舗A,9:00,9:30
④開始時間のテキストボックスに終了時間を入力
・出荷時間のリストボックス
店舗A,30
店舗B,90
店舗C,……
・開始時間のテキストボックス:9:30
・終了時間のテキストボックス:9:30
…,店舗名,開始時間,終了時間
1,店舗A,9:00,9:30
2,
終了時間は、開始時間に出荷時間を加える計算を考えてみました。
開始時間=9:00、終了時間=
開始時間=9:00、終了時間=9:30
開始時間=9:30、終了時間=9:30
開始時間=9:30、終了時間=11:00
まずは、先程のフォームの連結クエリをもとに、出荷時間のクエリを作ります。
店舗名,チーム名,出荷時間
店舗A,チーム9時 ,30
店舗B,チーム9時 ,30
店舗B,チーム10時,60
店舗C,チーム11時,……
店舗の終了時間を計算するときは、店舗名でグループ化、出荷時間の合計を集計しましょう。
りんごさんへ
たくさんのアドバイスありがとうございます。
難しそうですが、明日以降に試してみたいと思います。
このスレッドの流れを細かく読んではいませんので、外しているかも知れませんが、
ちょっと思ったことを書いてみます。
レポートの最後に索引を追加したいということですよね。
ということだと、かなり難易度が高いと思います。
一つのレポートで索引も出力するというのはあきらめて、
まずは、索引なしの医薬品集レポートを出力する。
その後、索引を出力する。
というようにレポートを2つに分けたらどうでしょう。
索引用のテーブルを作成しておいて、それから索引レポートを作成しておきます。
医薬品集レポートを出力するときに、フォーマット時イベントで索引用テーブルに索引用データを出力していく。
こうすれば、並べ替えも、段組みもレポートの機能で簡単にできます。
処理の流れは下記のようなイメージです。
フォームにコマンドボタンを2つ配置。
「医薬品集レポート印刷」
「医薬品集索引印刷」
「医薬品集レポート印刷」ボタンのクリック
索引テーブル の全データを削除 → 医薬品集レポートの印刷
医薬品集レポートの詳細(またはグループヘッダー)のフォーマット時イベントで索引データを索引テーブルに追加。
上記印刷後、「医薬品集索引印刷」をクリックで索引レポートを印刷。
まず、Forループ内でカウンター変数を変更するのはご法度です。Step を使いましょう。
データ追加は、サブフォームのレコードセットに対してAddNewで追加するようにします。
Withでサブフォームのレコードセットを参照するようしてますのて、
Me.T_月額マスタのサブフォーム1.Form
は不要です。![契約番号サブ] 等の[]内はコントロール名ではなく、フィールド名にしてください。
テーブルのフィールド名が「契約番号サブ」ならいいですが、「契約番号」なら、
![契約番号]
です。
あと、最後に .Update が必要です。
リンクフィールドの設定は問題ないと思います。
リンク親フィールド/子フィールドが設定されている箇所が分かりましたので、念のため追記いたします。

hirotonさん、本当に有難うござます。自分がやろうとしていたことが、素人には絶対無理だったと痛感しました。ご指導頂いた資料で今後じっくり勉強することにして・・・ とりあえず、このままコピペしてみました。添付しましたファイルの様なコメントが出ました。完全なコピペはダメだったでしょうか?
⑦リストボックスから、とりあえず泥臭く選んで登録する
未完了テーブルのリストボックス
1,店舗A,500
2,店舗B,1000
3,店舗A,0
持ち時間テーブルのリストボックス
1,チーム9時 ,60
2,チーム10時,60
3,チーム11時,60
4,チーム9時 ,30
…,店舗名,チーム名,未完了,持ち時間,最大出荷数,出荷数,出荷時間,未完了残り,持ち時間残り
1,店舗A,チーム9時 ,500 ,60,最大出荷数,500,30,0,30
2,店舗B,チーム9時 ,1000,30,
⑤店舗A,未完了残り0を登録
未完了テーブルのリストボックス
1,店舗A,500
2,店舗B,1000
3,店舗A,0
⑥チーム9時,持ち時間残り30を登録。
持ち時間テーブルのリストボックス
1,チーム9時 ,60
2,チーム10時,60
3,チーム11時,60
4.チーム9時 ,30
出荷時間のログ
…,店舗名,チーム名,未完了,持ち時間,最大出荷数,出荷数,出荷時間,未完了残り,持ち時間残り
1,店舗A,チーム9時 ,500 ,60,最大出荷数,500,30,0,30
未完了テーブルのリストボックス
1,店舗A,500
2,店舗B,1000
持ち時間テーブルのリストボックス
1,チーム9時 ,60
2,チーム10時,60
3,チーム11時,60
④リストボックスから、店舗A、チーム9時、未完了500、持ち時間60を選んで登録。
以下、フォームの連結クエリのイメージです。
…,店舗名,チーム名,未完了,持ち時間,最大出荷数,出荷数,出荷時間,未完了残り,持ち時間残り
1,店舗A,チーム9時 ,500 ,60,以降、計算で導出。
未完了のログと持ち時間のログを考えてみました。持ち時間は、9:00~10:00ならば、60とします。
以下、フォームのイメージです。
① 出荷日を選ぶ。
② 店舗名を選んで登録。
未完了テーブルのリストボックス
1,店舗A,500
2,店舗B,1000
③ チームを選んで登録。
持ち時間テーブルのリストボックス
1,チーム9時 ,60
2,チーム10時,60
3,チーム11時,60
情報が足りずに申し訳ありません…
サブフォームのリンク

親フィールド:「T_契約マスタ」の「契約番号」
子フィールド:「T_月額マスタ」の「契約番号」
(リレーションシップで結ばれている関係をリンクフィールドと解釈しているのですか、相違ありませんでしょうか…?)
サブフォーム上で手入力した場合は問題なく入力できました。
以上、どうぞよろしくお願いいたします。
というわけで、ちゃんと使いやすいデータにして対応する例
Dictionary オブジェクトを使って目次データを整理するようにします
Dictionary オブジェクトを使うには事前準備が必要なのでレポートの開く時イベントに処理を追加しています。
Dictionary オブジェクトの仕様上「薬品名のフリガナ」に重複データがあると最後の「薬品名」のみ目次に反映されます
五十音での並び替えについて
とりあえず無理やり的な方法で(修正箇所だけ)
例えば
のようなデータがあった場合、
のようにひとかたまりの文字列のデータにして並び替えた後、分割用の文字から後ろを抜き出せば「かな順」で並び替えができるというものです
「<split>」は誤動作しないよう「かな」に含まれない文字列なら何でも構いません
内容が複雑化してきて、簡素化した記述が足かせになって余計な苦労をしてるような気がしてきました。データのボリュームが増えてきているのでコード内でもしっかりデータを管理できるような仕組みを導入したほうがよさそうです
適当なデータを作って試してみたら確かにうまくいかないですね
レポートのイベントの発生メカニズムの研究(hatena chipsさん)
ページ跨ぎが発生した場合に目次データが重複しないよう
と制御を入れたんですが、
FormatCount = 1
だけだとうまく目的のデータにならないようです。画像を見てわかる通り、目次データの取得は「実際の描画があったら目次データを作成する(ページ番号を取得する)」とする必要がありそうです。hirotonはうまい方法を知りません目次データを取得している詳細_Formatイベントは描画前の処理なので、このタイミングで「描画があったかどうか?」は知りようがありません。やるとすれば、印刷しようとしている余白に印刷できる高さがあるかどうかを計算するという方法になると思います。現在の印刷位置情報や、印刷領域の残り高さが必要になるのでかなり大変です
条件を限定すれば、いくらか簡単な方法でチェックすることもできそうです
・同一ページ印刷プロパティ「はい」
・単独で1ページを超えるような出力がない(上図の例なら詳細は最大でも9行(1ページで収まる)場合)
であれば、「
FormatCount = 2
があれば、それが描画ページ」とすることができます。ただ、FormatCount = 1
のときはFormatCount = 2
があるかどうかわからないので、「仮データを置いて、次の明細に移動したら仮データの確定処理をする」様にします下記の情報を提示してもらえますか。
「ごとに請求」ボタンのクリック時イベントのVBAコード。
サブフォームコントロールの「リンク親フィールド」「リンク子フィールド」の設定。
サブフォームで手入力で入力したときは問題なく入力できるかどうか。
hirotonさん、早くも質問です。小出し小出しで申し訳ない内容です。

索引を印刷したところ、本文の薬品ページと索引で示すページが異なっている一部薬品があります。ページが変わるタイミングの薬品で、レポートで薬品を剤型→薬効分類とグループ化しているのですが、薬効分類がページが切り替わる時、例えば、1ページ目に薬効分類が入っていると薬品が2ページ目なのに索引には1ページと表記される といった状態です。2点目は、以前
ご指摘の通り、薬品にはカタカナ、漢字、数字が混在しています。印刷をしてみると、やはり五十音順にならんでいた方が見やすいかなと思い、ご指導を頂けないでしょうか?
今更ですが、レポートと薬品集テーブルのスクリーンショットを添付しました。宜しくお願い致します。
hatena様、新たな情報ありがとうございます。
実現方法も様々あるようで、場面によって適した方法が使えるように励みたいと思います。
改めましてありがとうございました。
>hatena様
前回は色々とご教授いただきありがとうございました。
hatena様のお力添えのおかげで、途中まで順調に進むことができました。
しかし、どうしても一点つまづいてしまった部分があり、
ご助言をいただきたく、またご相談させていただきました。
hatena様のご助言通り、メインフォームの「基本情報」はT_契約マスターと連結させました。
教えていただいたVBAのコードは、「ごとに請求」ボタンに埋め込んでおります。
また、月額、税率、税の処理などのコントロールは、非連結で作成しております。
今回困っている箇所ですが、ボタンを押すと問題なくレコードがサブフォームに追加されるのですが、
サブフォームを触ろうとするとサブフォームがクリアされてしまいます。
(サブフォーム以外の場所をクリックしてもクリアされてしまいます)
サブフォームはT_月額マスタに連結しているのですが、T_月額マスタにはきちんと保存されておりました。
また、「ごとに請求」ボタンを2回連続で押すと、今度はサブフォームはクリアされず、
サブフォームに追加されている1回目のレコードの下に2回目のレコードが追加されます。
2回目以上だと、不思議なことにサブフォームを触ってもクリアされず編集可能です。
稀にですが、月額が異なっていたり、ひと月だけ税率の違う月が存在するため、
ユーザーがサブフォームのレコードを自由に編集できるようにしておきたいです。
ボタンを押した後、データをそのままサブフォームに保持しておける手段がありましたら
どうか教えていただけませんでしょうか?
直接テーブルとつながってるサブフォームなので、もしかしたらただレコードを表示するための
ユーザーは触れないサブフォームにした方が理想的なのかもしれません…
もし、データベース構造的にふさわしくない等のご意見がありましたら、
お手数をお掛けしますが、併せて教えていただけますと大変ありがたいです。
よろしくお願いいたします🙇♂️
解決済みですが、下記のような方法もあります。ご参考までに。
式1: "," & Nz([ID検索],[社員ID]) & ","
Like "*," & [社員ID] & ",*"
>hiroton様
ある程度で式を分解して確認する、肝に銘じておきます。
>ゲッキョク駐車場様
Nz関数を使って、以下のようにすることで無事解決することができました。
Eval(BuildCriteria("'" & [テーブル1]![社員ID] & "'",10,"*" & Replace(Nz([ID検索]),",","* Or *") & "*"))
どういった関数があるのか、あったとしてそれをどう見つけ当てるかが大事ですね。
色々と経験値を溜めて行ければと思います。
hiroton様、ゲッキョク駐車場様、貴重な情報ありがとうございました!
hirotonさんのが圧倒的に強いので、出しゃばりたくはないのですが、
Null出ちゃう時にとりあえず使うイメージのある「Nz」を使ってみては。
Nzの使い方とかは調べるとたくさん出てきます。
ゲッキョク駐車場様、ありがとうございます!
テキストボックスに何も入力されなかった(NULLの)場合は対象をそのまま表示させればいいということですね。
思いつきもせず目からウロコです!
ただ、、、ご教授いただいた方法でも同じエラーダイアログが表示されてしまいました。
どこか根本的な見落としでもあるのでしょうか・・・。
Replace 関数
Replace([ID検索],",","* Or *")
の部分で[ID検索]
が未入力(Null)ならエラーが発生します。複雑な計算式でエラーが出た場合は、式を分解して内容を確かめる等、原因の究明をしましょう
例えば、抽出用のフィールドを作らず、単に
Replace([ID検索],",","* Or *")
だけのフィールドを作成しますこれだけのクエリでも質問のようなテストを実行すれば同じエラーが表示されるはずです
IIf(IsNull([ID検索]),[テーブル1]![社員名],Eval(BuildCriteria("'" & [テーブル1]![社員ID] & "'",10,"" & Replace([ID検索],","," Or ") & "")))
でどうでしょうか。
条件式ちゃんと見てないのであってるか微妙ですが。
hirotonさん、感動です! やりたかったことが出来てます!! 改めて、いくら自分で本を読んだりネットで調べてもダメだったと痛感しました。教えて頂いたコードを読み解いて勉強してみます。解決できない時はまたご指導ください。取り急ぎご報告まで。
りんごさんへ
アドバイスありがとうございます。

私はド素人ですのでどんなアドバイスでも助かります。
一応、こんな感じで作ってみました。
りんごさんのイメージと違ったらすいません。
現在時刻: Time()
残り時間: (([未完了]/([生産性]10))60)/1440
終了時間: [現在時刻]+[残り時間]
問題点1
残り時間を出すときの人数を今回は10人固定にしてます。
時間で変動できるような式にしたいです。
1時間後の出荷なら1時間後の人数で計算、
2時間後の出荷なら2時間後の人数で計算できるようにしたいです。
具体的な例として、9時~10時が5人で10時~11時が10人とします。
9時スタートで店舗Aの出荷が9時30分に終わるとします。
店舗Bの出荷は9時30分~10時は人数5人で計算して、10時から11時までは10人で計算したいです。
生産性は店舗ごとに変わります。
この計算を例えば9時の時点で最後の店舗までできるようにしたいです。
問題点2
1つまえのレコードの終了時間に残り時間をプラスして終了時間をだしたいです。
今週は実際にアクセスで試せるのが金曜日以降になります。
質問等ありましたら答えることはできます。
ええと、私も素人なので、大きなことは言えないのですが、次のような方針はどうですか?
現在時刻の項目を追加して、日時/日付関数を設定。(更新するたびに、自動入力)
残り時間の項目を追加して、計算式(未完了の値÷生産性の値)を設定する。
終了時間の項目は、計算式(現在時刻の項目+残り時間)を設定、導き出す。
的外れでしたら、ごめんなさい。
りんごさんへ
日本語が分かりにくくてすいません。
現在の時刻から終了時刻を表現できればと思っております。
8時00分スタートで1時間で終わる予定ならば終了時刻は9時00分になります。
進捗状況はリアルタイムで更新していきます。
基本的に予定と同じになることはありません。
あくまでも予想の終了時刻の計算をしたいと思っております。
店舗によって生産性が変わったり、時間によって人数が変わります。
やり方などはおまかせします。
ここでするような質問でなかったら流してください。
終了時刻を導き出すために、現在時刻を関数で表現するには、どうすればいいかという質問ですか?
回答ありがとうございます!返信遅くなり申し訳ありません。
ユニオンクエリにそのようなデメリットがあるとは知りませんでした。
レポートで日計と累計を作成できるのですね。調べてやってみます。
躓いたらまた質問すると思いますが、またよろしくお願いします。
3ヶ月越しで申し訳ありません。うまくいきました!
(念のためお伝えするとご記載いただいた内容につきまして、strFilterとstFilterが混ざっているようです)
大変たすかりました。教えていただき、ありがとうございました。
hatena様
コードのご提示ありがとうございます。
無事解決いたしました。
それと、詳細セクションも複数ページにまたがることがあったりしますか?
ページ跨ぎが発生すると
詳細_Format
もその都度発生するので、data
に薬品名が重複して登録されます。こちらもページ跨ぎの場合はdata
にデータを追加しない様、制御処理を追加しておいたほうがいいかもしれません「txt目次0~3」なら「0,1,2,3」の4段じゃないですか?
印刷時拡張を使って複数ページになるなら目次データの生成処理を初回の1回だけ処理するようにすればいいですね
それと、印刷時拡張かつ段組みとすると、30行ずつ3段目まで振り分けたらまた1段目に戻す必要がありますね
レポートフッター_Format
を次のように変更します別案としてフォームのレコードセットを直接更新する方法も提示しておきます。
Yes/No型フィールドの名前は、chk1, chk2, chk3, chk4 と仮定したコードですので実際のものに変更して使用してください。
hiroton さん、何度も有難うございます。
また、複数ページにまたがる事をお伝えしていませんでした。
薬剤数450-500、3段組みの設定を考えており数ページに及びます。
変更点をご指導頂けますでしょうか?