Public Function 入力漏れ() As Boolean
Dim myCtrl As Control
For Each myCtrl In Screen.ActiveForm.Controls
If myCtrl.Name Like "txt*" Then
If IsNull(myCtrl.Value) Then
MsgBox "入力必須項目に入力漏れがあります"
' Cancel = True
入力漏れ = True
Exit Function
End If
End If
Next
入力漏れ = False
End Function
If .RecordCount = 0 Then
For i = 0 To monthNum Step s
'全部新規登録
Next
Else
For i = 0 To monthNum Step s
.FindFirst "入金月 = " & "#" & DateAdd("m", i, startDate) & "#"
'(省略)
Next
End If
Dim rs As Recordset
Set rs = Me.月額サブフォーム.Form.RecordsetClone
With rs
For i = 0 To monthNum Step s '請求頻度ごとに
'既に同じ入金月のレコードが登録されているかチェック
.FindFirst "入金月 = " & "#" & DateAdd("m", i, startDate) & "#"
If .NoMatch Then
.AddNew
![契約番号] = Me.契約番号
![月額] = Me.月額
![入金月] = DateAdd("m", i, startDate)
![税率] = Me.税率
![税の処理] = Me.税の処理
.Update '★ここでデバッグが出る
'同じ入金月のレコードが登録されていない場合
Else
.Edit
![月額] = Me.月額
![税率] = Me.税率
![税の処理] = Me.税の処理
.Update
End If
Next
.Close
End With
どうもありがとうございます。
アドバイスをいただきまして、私の説明が足りなかったと感じた部分もあり、また、今後の対応の方向性が少し見えたこともありましたので、コメントさせていただきます。
1点目ですが、少し補足させていただくと、デザインビューでレコレードソースにはクエリを物理的に設定はしています。
データ取得後、なんでレコレードソースを
再設定してるかというと、メインフォームのヘッダにザブフォームのレコードを抽出するためのテキストボックス、コンボボックス等が十数個あり、それぞれの更新後処理から、レコードソースのwhere条件を生成してレコレードソースを設定するfunctionプロシージャを呼び出しています。
このヘッダの抽出条件を設定するコントロールのいくつかにはデフォルト値が設定しているため、データ読み込み後、この条件でデータを更新したいため、前述のfunctionプロシージャを呼び出してもいて、この時のエラーになっています。
データ取得後なら更新と、ユーザーが抽出条件を与えての更新で処理を分けてみるとかも検討してみたいです。
そして、このクエリ自体も少し重いものなので、2点目でアドバイスいただきましたように、待機処理をいれてみようと思います。
奇しくも、この投稿をしてから十数回この処理を繰り返し行っていますが、エラーは1回も出ていません。
この処理の影響もありそうですが、
まずは、VBAでレコードソースを変更するのは避けて、フォームのデザインビューでレコードソースプロパティにクエリ名を設定しておいて、VBAでは再クエリするだけにした方が安定しそうです。
あと、外部データをテーブルに取得した後に少し、待機してから再クエリするといいかもしれません。
VBAで指定した秒数だけ処理を止める方法【Sleep関数(API)】|CATIAマクロの作成方法 | LiCLOG
ありがとうございます。()などがエラーの原因の可能性があると言う事ですね。
全部修正できるか見直してみます。
フィールド名やコントロール名、その他名前に記号や特殊文字を使わない
コンピューターが文字をどのように扱うか、さらにACCESSならどうか、VBAならどうか、という深い問題があります。それでもどうしても記号や特殊文字を使わなければいけないのならこれらの仕組みを勉強してください
例外的に安全であろう記号はVBA自身も使っている「
_
」1文字くらいですありがとうございました。
Fcuntionを勉強していますが、イマイチ理解できていません。
このように条件判定するんですね。
参考になりました。
ありがとうございました。
ご助力感謝いたします。
本日、いただきましたコードを入れる前に下記のことを確認し一応の問題解決になりました。。
メインフォームには二つのサブフォームがあり、レコードソースにはクエリの内容は違うものの、
同じテーブルを元にしているクエリがセットされています。
そして、片方だけrequeryしておりましたが、両方することで、
更新が行われるようになりました。
また、クリック等では更新されるとありましたが、そのマクロの実行は両方のサブフォームをrequeryしておりました。
上記の通り、二つのサブフォームについて伝えていなかったこと、
そして、クリック等での更新については結果的に勘違いであったことお詫び申し上げます。
ただ、腑に落ちないのは、サブフォームが複数ある場合は両方しなければならない仕様なのでしょうか。
当然その場合は、処理に時間がかかるのでいかがなものかなと思います。
ご尽力いただきました、りんご様、本当にありがとうございました。
Function プロシージャは戻り値が取れるのでその結果で条件分岐すればいいでしょう
プロシージャはExitステートメントで中断することができます
>> 2
色々試してみましたが、力不足でした、
当面、タイマー時イベントから期待通りに動くイベントを呼び出すのは、どうでしょうか?
どなたかフォローをお願いします。
早速のご返信ありがとうございます。
ご指摘の内容を行いました。
メッセージボックス表示されました。
申し訳ありません。久々のアクセスでウッカリしておりましたが、少しずつ思い出してきました。
NOとNOsの方が違ったようです。自己解決しました。失礼いたしました。
おぉ、おめでとうございます。皆様お疲れ様でした。ビール飲もうっ、とっとっと、自宅でだょノ
出来ました!
Q従業員抽出 のクエリに[従業員コード]を追加してみたところ、
「あ」のボタンを押した後、コンボボックスにあ行の従業員が表示され、
その中の従業員を選択すると、フォームに出てくるようになりました。
hirotonさん りんごさん
何度もじっくりとお付き合いいただき、またご指導下さり、本当にありがとうございましたm(__)m
数値型 ≠ 文字型
とりあえず、コンボボックスの表示問題は解決出来たという事でよろしいですか?この質問スレを解決済みにして新しい質問を立てましょう。下記の準備をやっておいて下さい。
やりたい事の為には、従業員コードが出てくる「従業員テーブル、従業員抽出クエリ、ほにゃららフォームのコンボボックス(値集合ソース:従業員抽出クエリ)」が必要だと思います。
Q従業員抽出が従業員抽出クエリに相当するならば、従業員コードのフィールドを追加、本番前のお試しクエリに相当するならば、新しいコンボボックス(値集合ソース:従業員抽出クエリ)を作って下さい。コンボボックスの連結列が従業員コードの列になるようにしておきましょう。
「あ」のボタンを押した後、従業員コンボボックスには、従業員の苗字が1回ずつ(同一名が繰り返されることなく)表示されました。
そして、名字を選択すると「型が一致しません」となります。
マクロ名
基本情報1 : 従業員コンボボックス : AfterUpdate : 埋め込みマクロ
アクション名
オブジェクトからレコードの検索
引数
-1, , 先頭のレコード, ="[従業員コード] = "& Str(Nz([Screen].[ActiveControl], 0))
エラー番号
2950
となっています。
内容テーブルのフィールド次第だと思います。情報不足です。
日付IDが出てくるのでしょうか?各テーブルの主キーはどうしているのでしょうか?
サブレポートを使ったことがないので勉強してやってみます
またわからなかったら新規で質問させてもらうかもしれません
よろしくおねがいします
コンボボックスの列数を2、列幅を例えば、1cm;1cm、連結列を1にしてどうなったか報告して下さい。
コンボボックスが空白だということなので改めて設定を確認していきます
コンボボックスには値集合ソースに「Q従業員抽出」が指定してあります。なのでコンボボックスにはクエリに内容が表示されているはずです
Q従業員抽出の抽出条件を削除して保存した後フォームを開きなおすとコンボボックスにはクエリと同じ内容が表示されますか?
これが確認出来たらQ従業員抽出の抽出条件を
Like "[ア-オ]*"
にして保存しなおした後、フォームを開きなおします。コンボボックスにはクエリと同じ内容が表示されますか?このような方法でクエリの内容をコンボボックスに表示することができることが確認できますが正しく動いていますか?
反応が遅く申し訳ありません。
クエリを削除して再度作り直すとこうなりました。
SELECT 基本情報.苗字
FROM 基本情報
WHERE (((基本情報.苗字カナ) Like [Forms]![基本情報1]![抽出用カナ]));
最初と違うのはわかりますが、それがどのように違うのかはわかりません。
クエリを実行してみて、パラメータ試しに[アーオ]*と入れてみたところ、結果はあ行の方の名字がきちんと1回ずつ表示されました!
ただ、現時点では「あ」のボタンを押した後のコンボボックスは空白です。
>> 11
試行錯誤するのであれば、主キーを消さずに出来る範囲で頑張る方がいいと思いますよ。絵に描いた餅になりそうで心配です。
テーブル同士に線を引く時は、データベースツールタブのリレーションシップがオススメです。参照整合性を設定できるので、リンク切れ、怪しいリンクを未然に防いでくれるでしょう。
もしかしたら、変動支払条件みたいなものがあるのかなぁ。
やった事がないので、ワークテーブル、フラグテーブルがセオリーなのかわかりません。何かあればどなたか回答をお願いします。
>りんごさん
hirotonさんが書いてくださったコードを使用したことで、無事解決いたしました!
>りんごさん
テーブル構造をうまく伝えられず申し訳ありません…
以下の画像で伝わりますでしょうか…?
月額マスタには単独主キーが存在しません。
(参考書でテーブルには必ず主キーを設定すべしと書いてあったため、
最初は月額IDフィールドを作成していたのですが、
編集したり、消したりという処理が多く、連番を管理する技術がなかったため
フィールド自体を消してしまいました…)
業務内容は、数年単位のリース契約が主です。契約期間が終わるまで、特定の月に請求するという感じです。
本テーブルという分かりづらい言葉を使ってしまい、申し訳ありません…
新規登録や編集に使うワークテーブルに対し、
データを蓄積するテーブルという意味で「本テーブル」と書きました。
例えば、編集する場合の流れだと
① 帳票形式の検索フォームで、ユーザーが編集したいレコードを選択する
② 選択したレコードの契約番号をフラグテーブルに追加し、同じ契約番号のレコードの編集を防ぐ
③ データを蓄積しているテーブル(本テーブル)から、選択したレコードの契約番号を検索する
④ 検索したレコードを空のワークテーブルに移す
⑤ ワークテーブルがレコードソースの編集フォームを開く
⑥ ユーザーが編集する
・フォーム上の登録ボタンを押した場合
⑦ 編集したレコードの契約番号を本テーブルから検索し、そのレコードを削除する
⑧ ワークテーブルから本テーブルにレコードを移す
⑨ ワークテーブルからレコードを全削除する
⑩ フラグテーブルから編集したレコードを消す
・フォーム上のキャンセルボタンを押した場合/ユーザーが画面を閉じた場合
⑦ ワークテーブルからレコードを全削除する
⑧ フラグテーブルから編集したレコードを消す
>hirotonさん
参考資料をありがとうございます!とても分かりやすかったです!
そもそもRecordsetChoneとRecordset.Cloneの2種類があることをはじめて知りました!
千件単位のデータを処理すると、処理時間にはっきりと差が出るのですね…
これからはこの差を念頭に置いて、どの処理を使用すべきかを考えたいと思いました。
確かにForループを2つに分けた方がごちゃごちゃせず見やすいです!
そして、「実行頻度の高さから処理方法を考える」という視点を持っていなかったので、肝に銘じました…
だいたいひとつくらいしか処理するアイデアが浮かばないので
もっとこうできないかな?と発想を広げられるよう頑張ります!
質問文中のコードが解決済みコードに書き換えられているようですが、なお不具合ありという事でしょうか?
>> 4
まず、テーブルがわからなかったのですが、こんな感じですか?
契約マスタ_ワークテーブル:契約番号,契約名,請求先,顧客ID,…
単独主キー 請求先と顧客の関係性は何かありますか?
月額マスタ_ワークテーブル:月額ID,契約番号,入金月,税抜価格,…
単独主キー
次に、業務がわからなかったのですが、使った分だけお支払い、上限ありのサービスをイメージすれば良いですか?
最後に、本テーブルって何でしょうか?毎回、ワークテーブルのレコード全削除、本テーブルのレコードを全コピー、登録ボタンを押すと、全置換されたりするのでしょうか。
サブレポート方式でいけば比較的簡単にできると思います。
サブレポートコントロールの「印刷時拡張」プロパティを「はい」にしておけば件数に応じて高さが拡張します。
ACCESSのレポートの設計からは逸脱しているのでむずかしいですかね?
速度関係はよくわかりませんが
これをTrueで抽出するとかどうですかね?
余談
カンマ区切りにしてみたら
] & ",","," & [
この辺でめっちゃ混乱しそうでした高速化を考えるなら
フォームの Recordset, RecorsetClone, RecordSet.Clone の違いとは?(hatena chipsさん)
データの操作・更新とともにフォームの表示も一緒にやるかどうかでかなり速度が変わります
If .RecordCount = 0 Then
を使うなら「ループ自体を2パターンにする」ですね新規契約(
.RecordCount = 0
)の割合が高ければ効果的ですが、正直あまり使う形じゃないかなぁと。もう少し条件を変えて「startDate
以上の[入金月]が無ければ」でレコード数チェック(Dcount
)するなら実行頻度もあがるかも?もう一つは、チェックするデータがなくなったら残り全てを登録するという手法もありますが、「チェックしなくていいデータ」(チェックの終えたデータ)をどう表現するかということになるのでちょっと難易度が上がります
まぁ、今回の件だとデータ数はかなり少ないでしょうからチェック手法での差はほとんど出ないと思います。まずは冒頭の「フォームの更新が同時に起こる操作」に注目してみてください
クエリデザインで下記のように設定してください。
これで、パラメータに 1A,3C,5B とカンマ区切りで入力すると該当のタグで抽出できます。
ただし、件数が多いと重くなるので(インデックスが効かないので)、その場合は、
条件入力用のテーブルを作成して、そのテーブルと結合させるクエリにした方がいいでしょう。
条件入力用テーブルをレコードソースとするフォームを作成して、ユーザーにはそこで条件を入力させて、コマンドボタンでクエリを開くようにすればいいでしょう。
>hirotonさん
で、できました…!!希望通りの処理ができました!!
先週からずっーと悩んでいていたのでとてもすっきりしました…!!
本当にありがとうございます…!!思わず目頭が熱くなりました…!!
恐らく初歩的な内容であるにも関わらず、なぜレコードセットをcloseで閉じる必要があるかを
丁寧にご説明いただきありがとうございます。
テーブルを開きっぱなしと言われると、恐ろしさが重々理解できました…
また、コードの訂正に関してもありがとうございます…!
処理が早くなるかなと思って入れたIf .RecordCount = 0 Thenでしたが、
今試してみたら全く変わらない上に可読性も落ちていましたね…ご指摘ありがとうございます!
RecordsetCloneはこのような場合に使えるのですね!
存在自体は薄々知っていましたが、どう使いこなすべきかよくわからないプロパティでしたので
今回の件で大変勉強になりました。
見返してみると、recordsetの中でもう一度recordsetを開いていたことが複雑化する原因のようでした。
これからはシンプルな作りを心がけます!この度は助けていただき本当にありがとうございました…!
心からの感謝を申し上げます…!
>> 2
問題なのはOpenに対するCloseがないのほうです。このくらいの規模であれば
For
の外で宣言して終わったらrs.Close
しますが、超巨大なFor
文とか、一概にループの外でというわけではありません今のコードだと、開いたテーブルが開きっぱなしのまま放っておかれるので何かしらの不具合の原因になってもおかしくありません。今回のエラーの原因かどうかはわかりませんが、同じテーブルを複数開いてそのうちどれかで編集をしようとしているので原因にもなりそうです
あとは、全体の処理として
If .RecordCount = 0 Then
のところがループの中なのに最高でも1回しか実行されない作りなのが気になりますねこのくらいの処理なら
FindFirst
で全数チェックかけても大した問題じゃないのでいっそIf .RecordCount = 0 Then
の制御処理は無くてもいいと思います(実際今のコードはほぼFindFirst
で全数チェックになっています)その他変更点として
これはフォームのレコードセットをVBA上で扱う場合、テーブルを直接開く以外の便利な記述方法の内の一つです。より意味の明確なコードにしてるだけで「やりたいこと」自体は同じです
>りんごさん
ご回答いただきありがとうございます!
現在は年度別のExcelシートで管理している売上表を、
データベースで一貫して閲覧できるようにしたいというのがはじまりです。
ワークテーブルの設計が不味いということでしょうか…?汲み取れず申し訳ありません…
実はクラウドサービスや外注も検討したのですが、契約数も数百件規模ですし予算上厳しく…
また、入社してはじめて取り掛かった業務のひとつですので、できれば完成させたいという気持ちがあります…
開発中の契約管理システムがよくわからないのですが、月次売上サマリみたいなものが職場で求められているのでしょうか?個人的には、テーブル設計が気になります。
趣味で開発するのは、いいと思いますが。仕事で使うのであれば、外注やパッケージを検討するといいと思います。
>hirotonさん
ご指摘いただきありがとうございます!
「T_月額マスタ_編集_仮」は「月額マスタ_ワークテーブル」の書き間違いです。大変失礼いたしました…
無知でお恥ずかしい限りなのですが、このような場合、Forループ外で
recordsetを指定するのが通常なのでしょうか?
エラーが発生しない場合、希望通りの動きができていたので特に気にしておりませんでした…
CurrentDb.OpenRecordsetをForループ外に置いて試してみます!
回答ではありませんが
フォーム:契約マスタ_ワークテーブル
サブフォーム:月額マスタ_ワークテーブル
コード中に出てくる「T_月額マスタ_編集_仮」は全く無関係の別なテーブルですか?
またこのテーブルは閉じられる(
rs.Close
される)ことなくFor
ループの中で何度もCurrentDb.OpenRecordset
されるようですが大丈夫ですか?素早いお返事に感謝いたします!
試したところ理想通りの結果になりました。
勉強になります、ありがとうございました!
SELECT句で、英語・日本語どちらの表記を優先して表示させるかを明示しましょう。
問題点を指摘する前に、
そのクエリを一度削除してもう一度作り直すとどうなりますか?