Function tryExecute(sqlList As Collection) As String
'## 複数のSQLを実行するFunctionプロシージャ(SQLリストをすべて実行してメッセージを受け取る関数)
'エラーが起きたら「ErrorHandler」へジャンプ
On Error GoTo ErrorHandler
Dim daoWs As DAO.Workspace
Set daoWs = DBEngine(0) 'トランザクションをサポートするオブジェクトを作成
Dim daoDb As DAO.Database
Set daoDb = CurrentDb '接続
daoWs.BeginTrans 'トランザクション開始
Dim strSQL As Variant
For Each strSQL In sqlList 'SQL文リストをループ
daoDb.Execute strSQL '実行
Next strSQL
daoWs.CommitTrans '確定
'成功の場合は空の文字列が入る
tryExecute = ""
'接続解除へジャンプ
GoTo Finally
'エラー処理
ErrorHandler:
tryExecute = "Error #: " & Err.Number & vbNewLine & vbNewLine & Err.Description 'エラーの場合はエラーメッセージが入る
'接続解除
Finally:
If Not daoDb Is Nothing Then
daoDb.Close
Set daoDb = Nothing
End If
If Not daoWs Is Nothing Then 'トランザクション用のオブジェクトを破棄
daoWs.Close
Set daoWs = Nothing
End If
End Function
Private Sub Form_Unload(Cancel As Integer)
If Me.埋め込み1.Form.Recordset.RecordCount = 0 Or Me.埋め込み1.Form!SumF2.Value <> Me.埋め込み1.Form!SumF4.Value Then
Cancel = True
Me.埋め込み1.SetFocus
End If
End Sub
Private Sub 埋め込み1_Exit(Cancel As Integer)
Me.埋め込み1.Form.Requery 'レコード保存
If Me.埋め込み1.Form.Recordset.RecordCount = 0 Then
Cancel = True
MsgBox "明細データを1件以上入力してください"
ElseIf Me.埋め込み1.Form!SumF2.Value <> Me.埋め込み1.Form!SumF4.Value Then
Cancel = True
MsgBox "F2とF4の合計が合っていません!"
End If
End Sub
Private Sub Form_Unload(Cancel As Integer)
If Me.埋め込み1.Form!SumF2.Value <> Me.埋め込み1.Form!SumF4.Value Then
Cancel = True
Me.埋め込み1.Form!SumF2.SetFocus
End If
End Sub
Private Sub 埋め込み1_Exit(Cancel As Integer)
Me.埋め込み1.Form.Requery 'レコード保存
If Me.埋め込み1.Form!SumF2.Value <> Me.埋め込み1.Form!SumF4.Value Then
Cancel = True
MsgBox "F2とF4の合計が合っていません!"
End If
End Sub
ありがとうございます。対象レポートソースの集計クエリの基もクエリ(A)にしてまして、その(A)をソースにしたレポートも同じ状態でした(以前作成)。その(A)を使いウィザードで簡易なレポート作成すると問題なく重複データ非表示は出来ています。不思議です。何かの設定でしょうか?
上記のコードで、詳細リンクがNullの場合、""(空文字列)に変換しています。
下記の次のコードで、
IsNullでNullかどうかをチェックしていますが、その前でNullは""に変換されてますので、このSQLは必ず実行されます。
つまり、""に更新されてしまう。これが下記の原因かと思います。
対策としては、前者のコードは削除して、後者のコードを下記に修正すればどうでしょうか。
上記以外の該当部分も同様に修正してください。
あと、コスト、ですかね。
案件や状況によりけり、としか言えないのが難しいところですね。
質問内容が「Accessについてどのような意見を持っているか」なので、日頃Accessを選択する場合の理由になることを書いてみました。
やはり小~中の企業でシステム周りにあまりお金をかけたくない、というところは多くそういった場合に提案されることはまだまだ続くと思います。
SEから見ればコスト度外視で開発が楽な環境にしてくれとなるでしょう。質問にある指摘はそれだけとは言いませんがその面が大きく出ているように思いますね
企業から見れば、企業の実態に見合ったシステムの要件と、コスト(導入コスト・ランニングコスト)、時間(開発時間や運用に関する時間(これは≒システム要件))が問題です。開発・メンテナンスのしやすさなんてものは評価に値しません
それらは全てひっくるめて結局、できるのか?いつまでに?いくらで?で判断されることです
会社の大小によって、これらの評価の閾値はかわるでしょうが、これらが評価項目であることに変わりはないでしょう
ACCESSは貧弱なのでシステムの要件という大前提のもとNGとなる場合もあります。「要求を十分に満たす」となればコストパフォーマンスは高いと思います
実際、大掛かりなシステムでもフロントエンド(の一部はACCESS)という場合もあります
繰り返しますが、ACCESSは特定の条件に於いて「十分である」という評価をつけることはあります。これは「よい」ではありませんし、なんなら、大規模化を望めないという観点から「よくない」とするのが一般的な評価ではないか?というのがhirotonの考えです
まぁ、「一般的」などという特殊な環境なんてそうそうないとも思ってますが
ACCESSとVBAは切っても切れない関係ですが、同一のものではありません。VBAだけなら覚えなくてもいいんじゃないかなぁとも思います。ACCESSを使うなら覚えないわけにはいかないですが
時代は「クラウド」で「ノーコード」で「RPA」だ、なんで、いままで「office」で「VBA」でなんて言っていたのは今や特別必要というわけでもないのでしょう
ACCESSのような「手軽さ」も特別感のあるものではなくなってきました。ACCESSがいらないのであれば、必然VBAの必要性も無くなります
hirotonのまわりはまだまだサブスクリプションに拒否感を受ける人も多いようで、「スタンドアロン」で「買い切り」で、が決め手になる場合もありますが、システム選定の幅はかなり広がっていると思います。「同等の知識はあるが、ACCESSやVBAは知らない」という人がいてもおかしくない時代じゃないでしょうか
余談
VBAの兄弟分でもあるVBScriptがとうとう非推奨になってしまいました
https://learn.microsoft.com/en-us/windows/whats-new/deprecated-features-resources#vbscript
VBA,VBScriptの手軽さ、便利さはWindowsを使うにあたって有用なものだったんですが、そういう付加価値もなくなってくるとやはり、VBAにも消極的な姿勢にならざるを得ないかなぁと感じています
会社の規模感と開発に携わる人数の問題なんですかね。
"#"で囲っているのが余計だからでしょう。
一度、連結フォームで作成したものを書籍を参考にVBAでチャレンジしています。
2つのハイパーリンク型のフィールド以外は、難なく更新できています。
複数のSQL実行のためのプロシージャ
一部を略しましたが、更新文です。
重複データ非表示はよく使いますが、いままでそのような現象になったことはありません。
同じテーブルから新規にウィザードでレポートを作成しても現象は再現しますか。
個人的には状況によると思います。
例えば30~50人程度の会社の基幹DBで、1~2人の限定された開発人数で構築する場合、コストや開発情報の多さなどを考えるとそれほど悪くないと感じてます。
SQL Serverなどを使うと環境を用意するだけで簡単に200万円以上かかりますし。
またWindows環境の会社でADを主体としたファイル管理を多なっている場合はかなり便利です。
2016のあたりから今と同じように「もう終わる」みたいなことを囁かれていますが、2024年のいまでもまったく普通に使えます。
10年~20年とか基幹システムを使うとどこかでアップグレードしたくなるので、その際にシステムを変える等でもいいかと。
つまりとっかかりのシステム構築を行うと考えた場合はかなり優れたシステムだと言えると思います。
「よくない」でしょうね
ただまぁ、質問にある指摘は「金で解決できる問題」であるとも思いますが
度々ありがとうございました。イベントの説明も大変参考になりました。個々のレコード移動時イベントにコード記述して対応してみます。お世話になりました。
3で提示したコードの条件にレコード件数が0もつけ加えるといいでしょう。
これでサブフォームのレコード件数が0のときはフォームを閉じれなくなります。
ただし、これだけではメインレコード移動は規制できません。
レコード移動時イベントでは、レコード移動した後に発生するしキャンセルできないので。
いろいろ考えてみましたが、難しそうですね。
レコード移動時イベントで、サブのレコード件数が0のメインのレコードがないかチェックして、あればそこにレコード移動するという感じでするとか、ぐらいかな。
ちょっと面倒そうですね。
重ね重ねすみません、記述位置をミスしてました。埋め込み1_Exit***のコードをメインに記述してました。失礼しました。
これで移動も規制できました。
このフォームでメインにだけ入力してサブにはレコードが1件もない状態を回避したい場合、どうすると効果的でしょうか?(閉じたり、メインレコード移動時にメッセージを出したい)
ありがとうございます。メインにコード記述したらいけました。落ち着いて考えたら分かることなのに、すみませんでした。
イベントの説明もお手数かけました。フォーム閉じる時はこれでカバーできたのですが、メインに配置してますレコード移動ボタンに対してはどう対処したらいいでしょうか? 合計が合致してない場合、移動も出来なくなる様にしたいのです。
Private Sub Form_Unload(Cancel As Integer)
はメインフォームのモジュールに記述してますか。
サブフォームのモジュールに記述しているのなら、メインフォームの方へ移動させてください。
貴重なご意見をありがとうございました。
壊れた時のリカバリー・オブジェクト数との兼ね合いを見て感が陽と思います。
一般論ではなく前回の回答の”フォーカス喪失時”と”フォームの読み込み解除時”についてということで回答します。
その前にメイン/サブフォーム形式のフォームのフォーカス関係のイベントについて。
まずフォームを開いた直後は、メインフォームのタブオーダーが1番目のコントロールにフォーカスがあります。
メインフォームの入力を終えてサブフォームの入力に移るためにサブフォームのコントロールをクリックしたとします。
フォーカス関係イベントは下記のように発生します。
メインフォーム上のサブフォームコントロールのフォーカス取得時(Enter)イベント
↓
サブフォーム上のコントロールのフォーカス取得時(Enter)イベント
↓
サブフォーム上のコントロールのフォーカス取得後(GotFocus)イベント
サブフォームの入力を終了してメインフォームのコマンドボタンやテキストボックスをクリックしてメインフォームへフォーカスを移動したとき
サブフォーム上のコントロールのフォーカス喪失時(Exit)イベント
↓
サブフォーム上のコントロールのフォーカス喪失後(LostFocus)イベント
↓
メインフォーム上のサブフォームコントロールのフォーカス喪失時(Exit)イベント※
↓
クリックしたメインフォーム上のコントロールのフォーカス取得時(Enter)イベント
前回の回答では上記の※の時に、2つの合計をチェックして不一致の場合は、Cancel = Trueでイベントをキャンセルします。イベントがキャンセルされるとそれ以降のイベントは発生せずフォーカスはサブフォームから移動しません。
フォームの読み込み解除時イベントはフォームの右上のクローズボタンをクリックするなどフォームを閉じようとするアクションを起こすと発生します。サブフォームにフォーカスがある場合は、その前にメインフォームへフォーカスが移動することになります。イベントの発生順は下記のようになります。
サブフォーム上のコントロールのフォーカス喪失時(Exit)イベント
↓
サブフォーム上のコントロールのフォーカス喪失後(LostFocus)イベント
↓
メインフォーム上のサブフォームコントロールのフォーカス喪失時(Exit)イベント※
↓
メインフォームの読み込み解除時(Unload)イベント
この場合も※のところで合計チェックをして不一致ならイベントをキャンセルしますが、読み込み解除時イベントは発生してしまいます。ということは合計が不一致のまま閉じてレコード保存されてしまうことになります。
それを防ぐために、読み込み解除時でも合計をチェックして不一致ならイベントをキャンセル(Cancel = True)してフォーカスをサブフォームへ戻しておきます。これで合計が不一致の場合はフォームを閉じることができなくなります。
すみません、合計値が合致していない時は"F2とF4の合計が合っていません!"のメッセージが出て先に進めなくて狙い通りなのですが、合致している(正常の合計値)場合にフォーム閉じると ”メソッドまたはデータ メンバが見つかりません。” のコンパイルエラーとなり Private Sub Form_Unload(Cancel As Integer)のIf Me.埋め込み1(サブフォームコントロール名)の部分が示されます。メイン・サブに未入力で閉じても同じエラーとなります。
この回避はどうするといいでしょうか?
ありがとうございます。[OldValue]の事は全くしりませんでした。イベント使わずに計算が反映しますので、これは便利です。それと”フォーカス喪失時”と”フォームの読み込み解除時”のイベントの違いを教えて頂けますでしょうか(知識不足でフォームの流れがわかっていないのですみません)。
あと質問と異なるのですが、このフォームでメインにだけ入力してサブにはレコードが1件もない状態を回避したい場合、どうすると効果的でしょうか?(閉じたり、メインレコード移動時にメッセージを出したい)
Accessの仕様としては、F2、F4に金額を入力しただけではフッターの集計には反映されません。
レコード移動するとか、[Shift]+[Enter]キーを押す、レコードセレクタをクリック、・・・などなど
のレコード保存アクションを起こすと反映されます。
このレコード保存アクションを起こす前に、テキストボックスで金額を入力した直後に反映させたいなら、下記のリンク先の方法を参考にしてください。
フォームでの集計をレコード保存する前に反映させる - hatena chips
ただ、通常はそこまでしなくてもいいように思います。
サブフォームコントロールのフォーカス喪失時のイベントで合計値をチェックして合致していなかったら、イベントをキャンセルすればいいでしょう。
あとフォームの読み込み解除時でもチェックする必要があります。
サブフォームコントロール名(サブフォームを埋め込んでいるコントロールの名前)を「埋め込み1」、
サブフォームのフッターの集計テキストボックスの名前を SumF2, SumF4 と仮定した場合のサンプルコードです。
メインフォームのモジュールに記述します。
サブフォームコントロール名の確認法は下記を参考に。
サブフォームとサブフォームコントロールの違いとは? - hatena chips
hatenaさま
早速なるお知恵を授けていただき、ありがとうございます(にっこり)。
確かに!
「テキスト(CSV)形式やAccessのテーブルとしてエクスポートする」のはアリ、充分実用性がありますね。
またDB統合についても、現状ではファイルサイズが2GBを超えることは「まず、ありません」ので、
大丈夫そうです。
まずは状況を交通整理して、試してみようと思います。
(備忘録、も参考にさせていただきます♪)
今回のお知恵に感謝申し上げます(深々お辞儀)。
すみません説明不足でした。サブは下記のイメージです
F1 F2 F3 F4
摘要A ¥100 摘要B ¥50
摘要C ¥20 摘要D ¥70
このF2とF4の各合計値が合致する必要があります(サブフッターには各Sum値をテキストボックス)。金額入力ミスのチェックをしたいのです。
再更新ボタンもサブフッターに配置しており、単純に” Me.Requery” の記述だけです。
改善したいことはサブに金額入力したらすぐにサブフッターのテキストボックスに反映したいのと(再更新ボタン押さなくても)、合計値が合致していない状態でフォームを閉じたりメインに配置してます移動ボタン(新規レコード含む)で移動できない様に入力チェックが出来ないかなと思いまして。
Excel形式でエクスポートではなくテキスト(CSV)形式にする
または、
Accessのテーブルとしてエクスポートする
とかでどうでしょう。
サイズ問題に関しては、
毎日1時間ごとにバックアップをとるということですよね。
バックアップとしてどのくらい以前のデータまでさかのぼる必要があるのか不明ですが、
例えば、
本日分と前日分は毎時間分(16ファイル)
それ以前は、その日の最終分の1ファイルを残して削除
1か月以前のファイルは、月初めのファイルのみ残して削除
1年以上前のファイルはすべて削除
というように決めておけば(一例ですので実情にあわせて)
無制限にバックアップのサイズが増えることはないので
現在のストレージの価格を考えたらそれほど負担ではないと思いますが。
二つのファイルを合わせても400MBぐらいなら、統合したとしてたぶん問題ないと思います。
テーブル設計がどうなっているのか不明ですので断言はできませんが、
自分の経験でいくとそのぐらいでインデックス破損やDBのアクセス遅延はないように思います。
Accessのファイルサイズ制限の2GBに近くなったら分割を検討するのでいいかと。
MS Office Accessのサイズが2GBを超えてしまったときの対処法 | 俺的備忘録 〜なんかいろいろ〜
「その合計が合致する必要がある」とは、具体的に何と何が一致する必要があるのでしょうか。
サブフォームのフッターに表示させているF2の集計値とF4の集計値でしょうか。
「F2、F4入力後すぐに計算」とは、F2テキストボックスで入力した直後(レコード保存する前)に集計値に反映させたいということでしょうか。
とりあえず「再更新(Requery)ボタン」に設定してあるコードを提示して、こ処理でどの部分をどのように改善したいのかを説明してもらうと回答しやすいです。
まずは、どの程度の規模のシステムなのかによるでしょう。
レポート数が一桁から20ぐらいまでなら、どちらでもいいでしょう。
レポート数が多数になると、名前付きクエリにしておくと、クエリ数も増えて管理が煩雑になります。
クエリ名を工夫してレポートの関係が分かるようにするという管理法もあるにはありますが。
私の設計したシステムの場合、レポート数100以上なんてのもありますので、ほとんど埋め込みクエリにします。
ただし、複数のフォームやクエリで共通で使うクエリは名前付きクエリにすることもあります。
レポートのレコード ソースを設定する
名前付きクエリと埋め込みクエリの項目をチェックですね
どうでもいい経験談を加えると
「ACCESSが壊れた」とき、レコードソースプロパティが壊れてクエリがわからないなんてことには何度か遭遇してますね
名前付きクエリのSQLが壊れたのには遭遇したことはありません(偶々かもしれませんが)
「種別」テーブルと「商品リスト」テーブルがあってそれがコンボボックスの値集合ソースに設定されているということですか。
とりあえず一般的な設計法のサンプルです。
下記のようなテーブルを作成します。
T_種別
商品コンボボックス
名前 cmb商品
値集合ソース SELECT * FROM T_商品 WHERE 種別CD = [cmb種別];
連結列 1
列数 3
列幅 0cm;0cm
cmb商品のフォーカス取得時のイベントプロシージャを下記のように記述
すみません、追記させてください。
「\10.0.0.1\共有CSVフォルダ」が正常に表示されませんでした。
コードブロックとして再度記載します。
>> 8
じゃあ、各々のPCで取込・加工・登録が終わってから、各々でサーバ保管庫に投げておけばいいんじゃね?
返信遅れて申し訳ございません。
配列と、連想配列まわりを、ゴニョゴニョやってました。
エクセルのシートを使用しないのが、大きな目的です。
そして、配列と連想配列はすごいです。
キーは重複できないという特性を利用すると、
とんでもない速度で集計できるようになりました。
文字列処理も、連想配列とjoinを使うと負荷が減るようです。
集計と編集をして、カンマ区切りの状態にしてから、
可視で確認するために、最終状態を一気にエクセルシートに張り付けると、
瞬きする間に処理が終了していました。
EXCELは応答していません、と表示されている時間は嘘のようです。
データに間違えが無ければ、エクセルに張り付けずに、
そのまま指定の形式のファイルに出力する方法に変更します。
データがさらに大きくなると、配列に読み込むこと自体に限界が来るようですが、
自己使用の目的だけであれば、VBAは遅いという事は無いと思います。
これを、EXCELと呼べるか微妙ではありますが、とにかくハイパフォーマンスです。
それ以上踏み込むか、とどまるかは目的と趣味の問題ですね。
ちょっとどの程度まで理解しておられるか分かりませんので、余談になるかもしれません。
会社のサーバー(ファイルサーバーか共有フォルダ、のはず)に置き、ということなので、同じネットワーク上にあるPCからでしたら、共有フォルダのアドレスは変わらないはずです。
例えば「10.0.0.1」というIPアドレスにある「共有CSVフォルダ」という共有フォルダの場合、どのPCからアクセスしてもアドレスは「\10.0.0.1\共有CSVフォルダ」ですよね。
※探し方は参考リンクを書いて頂いてますのでそちらを参照してください
ですの以下のように設定すればいいのではないでしょうか?
DoCmd.TransferText acImportDelim, "my_imp", "注文取込", "\10.0.0.1\共有CSVフォルダ\中略\注文.csv", False, ""
または
folderName = "\10.0.0.1\共有CSVフォルダ"
ただしAccessのプログラムをネットワークフォルダなどに置き、同時に複数人が使用すると不具合が発生します。例えばプログラムを使って同時に取り込み作業を行った場合、データベースに同時に書き込みが発生してしまい、壊れやすくなります。
参考:https://sys-daddy.com/multi-user-setting-of-access/
そこで「データベース分割」などが必要になってきます。
(でも書き込みを見ると、ある程度できているようですね)
できました、ありがとうございます
メインデータ.accdbはサーバーに置いてあり、作業用.accdbは各クライアントPCにおいてあるということでしょうか。
複数ユーザーでデータを共有する場合は、データベースの分割は必須ですので、しっかり学習しておきましょう。WEB検索すれば解説ページは多数見つかります。
access データベースの分割 - Google 検索
はい、そうです。
アクセスの知識というよりサーバー上のファイルを共有する場合の前提知識ですね。
リンクテーブルにする場合もネットワークパス経由でリンクすることになります。
マスターテーブルと、取り込んだ注文.csvを加工して作成した注文データテーブルは、メインデータ.accdbに入ってり、テーブルのみのファイルになっています。他の作業用.accdbファイルではそのテーブルをリンクさせています。
どういうことでしょうか?初学者なものでデータベース分割、リンクテーブルはよく理解しておりません。
これをどうにか取得して、変数に入れるということですか?
これってそもそもデータベース分割とリンクテーブルをきちんとやっているの?