Private Sub Report_Unload(Cancel As Integer)
Dim res As String
res = MsgBox("正常に印刷が完了しましたか?", vbQuestion + vbYesNo, "完了確認")
If res = vbNo Then
Cancel = True
Else
MsgBox "さようなら"
End If
End Sub
'ファイルパスとテーブル名は適宜書き換えること
Sub Test1()
Dim strDatabasePath As String
strDatabasePath = "C:\FolderName\FileName.accdb"
If Dir(strDatabasePath) = "" Then
MsgBox "Access データベースファイル'" & strDatabasePath & "'が見つかりません。", _
vbExclamation, _
"ファイル参照エラー"
Exit Sub
End If
Dim adoCn As ADODB.Connection
Dim strConnectString As String
Set adoCn = New ADODB.Connection
With adoCn
.CursorLocation = adUseClient
.CommandTimeout = 60
strConnectString = "Provider=Microsoft.ACE.OLEDB.12.0;Mode=Read;" & _
"Data Source=" & strDatabasePath
Debug.Print strConnectString
.ConnectionString = strConnectString
.Open
End With
Dim adoRs As ADODB.Recordset
Dim strSQL As String
Set adoRs = New ADODB.Recordset
With adoRs
Set .ActiveConnection = adoCn
.CursorLocation = adUseClient
.CursorType = adOpenStatic
.LockType = adLockReadOnly
strSQL = "SELECT t1.[sptx], t1.[sbj], t1.[pymt], t1.[fwd], t1.[dat]" & _
" FROM [テーブル名] t1" & _
" ORDER BY t1.[id];"
Debug.Print strSQL
.Source = strSQL
.Open
End With
Dim adoFld As ADODB.Field
Dim wbkDestination As Excel.Workbook
Dim wsDestination As Excel.Worksheet
Dim lngColumn As Long
Set wbkDestination = Workbooks.Add
Set wsDestination = wbkDestination.Worksheets(1)
wsDestination.Cells(1, 1).Resize(1, adoRs.Fields.Count).NumberFormat = "@"
For lngColumn = 1 To adoRs.Fields.Count
Set adoFld = adoRs.Fields(lngColumn - 1)
wsDestination.Cells(1, lngColumn).Value = adoFld.Name
Set adoFld = Nothing
Next
wsDestination.Cells(2, 1).CopyFromRecordset adoRs
wsDestination.UsedRange.EntireColumn.AutoFit
adoRs.Close
Set adoRs = Nothing
adoCn.Close
Set adoCn = Nothing
Set wsDestination = Nothing
Set wbkDestination = Nothing
End Sub
Dim dic As Object
Set dic = CreateObject("Scripting.Dictionary")
Dim fld As ADODB.Field, i As Long
For Each fld In adoRs.Fields
dic(fld.Name) = i
i = i + 1
Next fld
Debug.Print myArray(dic("フィールド名"), x)
Dim 検索フォルダ As Folder
Set 検索フォルダ = FSO.GetFolder("C:\Users\○○\Desktop\検索フォルダ")
Dim 該当フォルダ As Folder
Dim フォルダ候補 As Folder
For Each フォルダ候補 In 検索フォルダ.SubFolders
If フォルダ候補.Name Like "売上データ*" Then
Set 該当フォルダ = フォルダ候補
Exit For ElseIf
'フォルダ候補(子フォルダ)を親として同じことをする
End If
Next
If Not 該当フォルダ Is Nothing Then
MsgBox "該当フォルダのパス:" & 該当フォルダ.Path
End If
End Sub
とするだけですね
Sub フォルダ名が売上データ○○になっているフォルダを取得する()
Dim FSO As New FileSystemObject
Dim 検索フォルダ As Folder
Set 検索フォルダ = FSO.GetFolder("C:\Users\○○\Desktop\検索フォルダ")
Dim 該当フォルダ As Folder
Dim フォルダ候補 As Folder
For Each フォルダ候補 In 検索フォルダ.SubFolders
If フォルダ候補.Name Like "売上データ*" Then
Set 該当フォルダ = フォルダ候補
Exit For
ElseIf
Dim 孫フォルダ As Folder
For Each 孫フォルダ In フォルダ候補.SubFolders
If フォルダ候補.Name Like "売上データ*" Then
Set 該当フォルダ = 孫フォルダ
Exit For
End If
Next
If Not 該当フォルダ Is Nothing Then
Exit For
End If
End If
Next
If Not 該当フォルダ Is Nothing Then
MsgBox "該当フォルダのパス:" & 該当フォルダ.Path
End If
End Sub
INSERT INTO T3_1_手数料集計用 ( 保管個数, 区分, 単価, 入出庫・保管料, 移動日 )
SELECT [総入庫数]-[総出庫数] AS 保管個数, DLookUp("区分","T0_3_区分マスター","区分ID=3") AS 区分, DLookUp("単価","T0_3_区分マスター","区分ID=3") AS 単価, [保管個数]*[単価] AS 入出庫・保管料, Date() AS 移動日
FROM T0_3_区分マスター INNER JOIN Q3_1_総入出庫数集計用 ON T0_3_区分マスター.区分 = Q3_1_総入出庫数集計用.区分
GROUP BY DLookUp("区分","T0_3_区分マスター","区分ID=3"), DLookUp("単価","T0_3_区分マスター","区分ID=3"), Date();
SELECT T3_1_手数料集計用.区分, Format([移動日],"yyyy\年mm\月") AS 日, Sum(T3_1_手数料集計用.入庫数) AS 入庫数の合計, Sum(T3_1_手数料集計用.出庫数) AS 出庫数の合計
FROM T0_3_区分マスター INNER JOIN T3_1_手数料集計用 ON T0_3_区分マスター.区分 = T3_1_手数料集計用.区分
GROUP BY T3_1_手数料集計用.区分, Format([移動日],"yyyy\年mm\月"), T0_3_区分マスター.区分ID
HAVING (((Format([移動日],"yyyy\年mm\月"))<=[Forms]![F3_1_集計期間選択]![集計年月]))
ORDER BY Format([移動日],"yyyy\年mm\月"), T0_3_区分マスター.区分ID;
Q_保管個数↓
SELECT Sum(Q3_1_総入出庫数集計用.入庫数の合計) AS 総入庫数, Sum(Q3_1_総入出庫数集計用.出庫数の合計) AS 総出庫数, [総入庫数]-[総出庫数] AS 保管個数, Date() AS 移動日
FROM T0_3_区分マスター INNER JOIN Q3_1_総入出庫数集計用 ON T0_3_区分マスター.区分 = Q3_1_総入出庫数集計用.区分
GROUP BY Date();
Report_Closeイベントはキャンセルできません。
自動生成されたイベントプロシージャにCancel引数がないイベントはキャンセルできません。
読み込み解除時(Report_Unload)イベントならキャンセルできます。
ネットワークパス(UNCパス)を指定すればいいでしょう。
Windowsネットワークパスについて – 名古屋のパソコン入替・パソコン設定・キッティング作業業務
完全ガイド - Windows 10でネットワークドライブのパスを見つける方法 - MiniTool
一般的には下記のような書式になります。
現在は自身のPCのデスクトップ上のフォルダの中に注文.csvがあります。
このフォルダを会社のサーバーに移動させます。
Accessの入っている会社のPCならどれからでもこのコードが動くように、PCからそのサーバー上のフォルダまでのパスを取得したいです。
ちなみに、C:¥Users¥中略の部分を変数にするコードは下記のようになります。
ただし、質問のコードでエラーがでるならこのコードでもエラーはでます。
やっていることは同じことなので。
どのPCからでもということですが、これらのPCは同じローカルネットワーク内にあるということですか。
C:¥Users¥中略 というフォルダーはローカルネットワーク上の特定のPCのフォルダーということですか。
「どのPCからでもこのフォルダを扱えるよう」ということを上記の点も含めていもう少し詳しく説明してもらえますか。
自身のPC内のC:¥Users¥中略フォルダーでそこに注文.csvが存在するなら、そのコードではエラーにはならないと思いますが。
前の質問の時もそうでしたが、こちらの質問に対する応答がないですね。
結局、何がしたいのか、何が問題なのか不明のまま議論が深まらずに終了するということになってます。
配列をどうしたいのか、それが不明瞭のままです。これを明確にしてください。
レコードセットのデータをエクセルに出力するというのが目的でしょうか。
だとしたら、skさんの回答の CopyFromRecordset を使う方法で簡単に実現できます。
連想配列を使う必要もないです。
hatenaさん、すみませんでした。
連想配列の存在を知らなかったので、読み飛ばしていました。
分からないところが山もり状態ですが、
避けて通るとEXCELに応答していませんと表示されるのを、
数秒間眺めることになるので、なんとか理解します。
放置すると、動かなくなる日は近いはずなので。
ここをクリアしても、また限界が現れると思いますが、
配列周りの処理方法は、次の段階で役立つと思うので、取り組んでみます。
そもそもそのプロシージャはどのファイルのどのモジュールに記述されているのか( Access データベースファイル上の標準モジュール、Excelマクロ有効ブックの標準モジュールなど)。
取得したレコードセット(の各フィールドの名前と値)をどこに、どのような形で貼り付けようとしているのか。
以上の前提についてのご説明がない限り、何を問題視されているのか不明瞭なままです。
例えば「ある accdb ファイル上に存在するテーブルから[sptx]、[sbj]、[pymt]、[fwd]、[dat]の 5 つのフィールドを選択し、全てのレコードを[id]の昇順に並べ替えた結果を取得して、新規ブック上のワークシートに複写するプロシージャを Excel マクロ有効ブック上の標準モジュールに作成しようとしている」といった場合であれば、2次元配列に拘らずとも、Excel.Range オブジェクトの CopyFromRecordset メソッドを使用する、といった方法もあるでしょう。
そのコードを前の回答で提示したつもりですが。
どちらにしても、
2 次元配列をどのように利用しようとしているか。
レコードセットではだめなのか、その辺の説明がないと、
これ以上、議論のしようがないように思います。
怪しい民間療法みたいな街角勉強会に引っかかっているんじゃないかしら?accessのようなデータベースがまだ発明されていない時代に、流行っていた思想は廃れたはずですが。
まず、データと一緒に、フィールド名を格納することはできなかったようでした。
認識不足でした。
ACCESSのテーブルの、何番目のフィールドか調べたいわけではありません。
レコードセットは、フィールド名でデータを取り出せるので、
事前に、フィールドの並び順をカウントしておけば良いのですが、
よく単純な数え間違えが起こります。
何番目に、どのフィールドをおいて呼び出したのか、
確認するコードを加えれば済む話ではあります。
なのですが、フィールド名でデータを特定するのがベストなので、できればそうしたいということです。
と言っても、データを整理して一括で貼り付けないと、負荷はほとんど変わりません。
この処理段階の方が、何倍もミスを犯しやすいので、取るに足らないこだわりかもしれないです。
私はデザイン、レイアウトに力を入れてますよ。
ただし凝ったデザインにはしません。
シンプルでユーザーが使いやすいUIになるように意識してます。
例えば、下記とか。
入力必須項目のある入力フォームのUIを考察する - hatena chips
白背景にテキストボックスの羅列が使いにくいとは思いませんが、ラベルはあった方かいいでしょうね。
下記とか。
Accessフォームでおしゃれなデザインを作成 | 工場エンジニアのAccessスキル
ACCESS フォーム作成サンプル - たすけてACCESS
レコードセットは配列の上位互換だと思いますが、なぜ配列で処理する必要があるのでしょう?レコードセットならフィールド名でデータを取り出せます。どのような目的で配列にするのでしょうか。
やるとするなら、連想配列(Dictionary)にフィールド名と何列目かを格納して、参照することになるかな?
具体的にどのような目的から 2 次元配列を用いようとされているのでしょうか。
少なくとも、上記のコードをそのまま記述すればコンパイルエラーが発生します。
2 次元配列を使用する目的が不明ですので、今のところ評価のしようがありません。
ありがとうございます!頂いた情報をよく読み、チャレンジしてみます。
とりあえずで回答しますが、孫フォルダを対象にしたいなら
Sub フォルダ名が売上データ○○になっているフォルダを取得する()
Dim FSO As New FileSystemObject
Dim 検索フォルダ As Folder
Set 検索フォルダ = FSO.GetFolder("C:\Users\○○\Desktop\検索フォルダ")
Dim 該当フォルダ As Folder
Dim フォルダ候補 As Folder
For Each フォルダ候補 In 検索フォルダ.SubFolders
If フォルダ候補.Name Like "売上データ*" Then
Set 該当フォルダ = フォルダ候補
Exit For
ElseIf
'フォルダ候補(子フォルダ)を親として同じことをする
End If
Next
If Not 該当フォルダ Is Nothing Then
MsgBox "該当フォルダのパス:" & 該当フォルダ.Path
End If
End Sub
とするだけですね
それぞれの変数がどのように使われるのか理解して、必要に応じて必要な変数を用意してください
ただし、別階層のフォルダを対象とするということは、同名のフォルダがある可能性が否定できないので、処理の順番によっては望んだ結果にならない場合もあります。また、「見つかったものは全て」というのが望みの場合もあるでしょう。仕様を明確にしましょう
最初の"T_入出庫一覧"テーブルを正規化すると下記のようになります。
T_区分マスター
正規化についてはWEB検索すれば解説ページは多数見つかりますので、わかりやすそうな所をいろいろ見て理解を深めてください。
とりあえず下記を紹介しておきます。
正規化とは - もう一度学ぶMS-Access
正規化の実例 - もう一度学ぶMS-Access
一口に「正規化」といってもなかなか難しいですね・・・上手く理解できていないもので
正規化のコツ・正規化したテーブルの活用のコツ等はありますでしょうか?
とんちんかんな質問でしたら申し訳ございません。
hatenaさんありがとうございます。”テーブルで可能なことは、テーブルで行う” は確かにその通りですね。今回の件以外で、ついついクエリ時の関数で複雑な分岐をしがちなので大変参考になりました。
現状のテーブル設計がどうなっているか不明なので、回答が難しいです。
これについては、そもそも質問の最初の"T_入出庫一覧"テーブルの設計から間違っています。
テーブルの正規化ができていません。
前の質問の時も指摘しました。
レポートへの出力のレイアウトに合わせた設計にしたのでしょうが、データベースではこのようなデータの持ち方はしません。
今回のレポートの出力だけにしか使わないデータならいいのですが、今後、データベースの機能を活かした使い方に発展させていくことがあるのなら今のうちにテーブルの正規化から始めた方がいいでしょう。
正規化されていないテーブルはデータベースとしては使い物になりません。
正規化されていれば、そこから希望のレイアウトで出力することも可能です。
このデータは今回のレポート出力のみにしか使わないのでしょうか。
「在庫管理システム」ということなのでそうではないですよね。
普段、SQL ServerのDBを使っているのでAccessでのクエリの動きははそんなに詳しくないのですが、「[総入庫数] - [総出庫数] AS 保管個数」を計算する[総入庫数]と[総出庫数]の追加先が「T3_1_手数料集計用」に無いからエラーになるってことでしょうか。
そうだとすると計算にはINSERT先はまだ関連してないのに、ちょっと不便な仕様ですね・・・。
例えばSELECT部分を意味なくまとめてもだめでしょうか?
SELECT
SELECT
FROM
GROUP BY
) as T1
、のような感じです。
また、どうしてもだめであれば追加先のテーブルに総入庫数・総出庫数フィールドを追加すればいいのではないでしょうか。
パラメータを要求される理由は分かっていて、保管個数の演算に使っている総入庫数・総出庫数フィールドの追加先を設定していないためです。
しかし、追加先のテーブルには総入庫数・総出庫数を入れるフィールドはなく、しかし総入庫数・総出庫数がないと保管個数が出せないため困っています。
過去の書き込みを軽くみただけですが、「T0_3_区分マスター」「Q3_1_総入出庫数集計用」の2テーブルだけですべての項目が出力できるのかな?とは感じました。
とりあえずクエリを単純化して確認することをおすすめします。
「INSERT INTO」する前に「SELECT」だけで結果を見る、や文言の間違い、「GROUP BY」を使わない場合にほしい項目が揃っているか否か、などを順に確認するのが良いかなと。
パラメータを要求される場合、大抵は意図しないケアレスミスが原因であることが多いですね。
そもそものデータの作り方がまちがっているのでしょうか?
Q_保管個数を加工し、このようなクエリにしました。
あとはこのクエリでT_手数料集計用にレコードを追加できれば良いのですが、クエリ実行の際に総入庫数・総出庫数のパラメータを要求されてしまいます。T_手数料集計用に総入庫数・総出庫数のフィールドはありませんが、保管個数の演算用にこの2つのフィールドを消すわけにもいきません。どのようにすればよいでしょうか?
あ、質問主です。
T_手数料集計用というテーブル(フィールド No.:オートナンバー型 区分:短いテキスト 移動日:日付/時刻 入庫数:数値 出庫数:数値 保管個数:数値 単価:数値 入出庫・保管料:数値
に、入庫時・出庫時にレコードを入れ、
Q_総入出庫数集計用↓
Q_保管個数↓
を作成し、フォームで指定した期間までの総入庫数から総出庫数を引いた保管個数を求めることができました。
このQ_保管個数の保管個数にT_区分マスターの保管の手数料を掛ければ求めたい保管手数料を計算できると思うのですが、どのようにT_区分マスターの値を引っ張ってくればいいのか分かりません。
入力チェックはテーブルで設定しておくのが確実ですね。下記もご参考に。
テーブルでの入力チェック、入力規制 - hatena chips
ただ、これだけだとシステムの出すメッセージは不親切だし、未入力項目にフォーカス移動させるなど細かい制御ができないので、それがしたいときはVBAを使うことになります。その場合は下記などもご参考に。
複数項目の入力チェックを共通モジュール化する - hatena chips
hatenaさんありがとうございます。確かに「値入力」プロパティを「はい」がシンプルで一番いいですね。要は必須項目が未入力なら保存不可にしたらいいですね。こうしておけば入力順番もそんなに考えなくてもいいですね。出てくる現象に対してだけ対処しても根本が不完全なら意味ないですね。全体を見て作成しなくては上手くいきませんね。
まだまだ勉強が必要よ痛感しました。大変参考になりました。
前の回答でふれたように現状の仕様ではいろいろ不具合が出てくると思いますが、
とりあえずレコード移動したときに、常に[F1]にフォーカスを移動させておきたいのなら、
サブフォームのレコード移動時のイベントプロシージャを下記のように設定したらどうでしょう。
あるいは、F1フィールドが未入力の場合のみ移動させるなら、
お返事ありがとうございます。
これを使いたいのですが,今のところ,Microsoft 365サブスクライパーのみとなっているみたいです。
パソコンについていたOffice2021にAccess2021だけを追加しているので,
これ以上お金をかけないでなんとかできないかな?と悪あがきをしているのですが…。
前にもいったようにフォーカス系のイベント内でSetFocusで制御しようとすると、今回のような場合も含めて、いろいろ複雑になり制御しきれません。ユーザーも必ず先頭項目から順に入力してくれるとは限りませんし、すべての項目を入力してから必須項目のデータを削除したりとかもありえます。それらも考慮するとますます泥沼になります。
一番確実なのは、入力必須フィールドはテーブルデザインで「値入力」プロパティを「はい」に設定しておくことです。
そうすればそのフィールドが未入力状態ではレコード保存できなくできます。
ユーザーに入力順を強制するというユーザーインターフェイス(UI)が本当に必要でしょうか。
レコード保存する前に、必須項目は入力されているか、入力値に矛盾はないか等をチェックして、問題があるときはメッセージを表示してユーザーに修正を即するというUIのほうが使いやすいし、設計もはるかに楽です。
先ほど投稿したのですが、内容間違えてました。メインの項目だけ入力して(サブには未入力)新規レコードボタンで移動することは現状カバー出来てました。失礼しました。
やはりメイン・サブの入力後に新規レコードボタンで移動するとサブの直近に入力した項目にフォーカスが残ったままなので(F2、F3・・・)に留まったままなのでメイン入力後サブに移動すると記述しているメッセージが出るのをなんとかしたいということです。一回毎にフォームを閉じるとこうならないのですが。どう制御するといいか分からないので。
hatenaさんありがとうございます。 MsgBox ("先にF1を入力して下さい。")のコードはF1以降の項目のフォーカス取得後(GotFocus)イベントに記述しています。防ぎたいことは例えばメインの項目だけ入力して(サブには未入力)新規レコードボタンで移動することです(他の移動ボタンにもそうですが)。確かに今の方法では都度の対処だけの感じですね。
全体で考えるならどんなアイデアがあるでしょうか? 思いつかないもので。
このコードをどこのどのイベントに記述してますか。一部を抜粋するのではなく、
Sub から End Sub までをすべてコピペしてもらった方が話かはやいと思います。
どちらにしても入力必須項目をSetFocusで制御しようという仕様は無理があると思いますので、この仕様から考え直した方かいい気がします。
よくわからないけど、結局WebブラウザコントロールってIEベースなのでもうダメ(Acrobat
側がIEを切ってるのでどうしようもない)とかなんじゃないですかね
別なコントロールを検討するしかないんじゃないでしょうか?
最新のACCESSだと標準で新しいWebブラウザコントロールもあるようです
EdgeBrowserControl オブジェクト (Access)
見落としていました。(というか、表形式で提示されているデータしか見てませんでした)
データ構造をどうするか?はもっと前の段階の話ですね。hatenaさん指摘の通りでいいと思いますが、どのような手法を取るにせよ「手数料単価の変更履歴テーブル」は有ったほうがいいと思います。「手数料の改訂」は案件の発生とは別に発生すると思われるので
手数料テーブルを作っておく場合
結局は>> 3の冒頭で提示しているレポートのようなテーブルを事前に作っておくという話なので、データ生成の流れは同じです。レポートのオブジェクト・出力仕様を駆使してやるか、それらを全てVBA内で自前で用意するかだけの違いです
累計計算になる「保管料の情報」がキャッシュされるので、それが正しいと保証する仕組みや追加分だけの計算ですますための、どこまでのデータは確定情報なのか(追加で計算すべきデータはどれか)判断できる仕組みが必要になると思います
■「正しいと保証する仕組み」について
遡りで入出庫の情報が修正されると“それ以降の月の保管料のデータが全て”修正対象になる
とか
当月保管料が未確定の状態で保管料のデータを作るかどうか
作る→都度修正する仕組みが必要
作らない→月半ばで一時的なレポート表示が欲しいとかで困る
とか、既にデータがある/ないが様々な処理に影響します
(レポートで)出力のたびに累計計算をやり直す仕組みはこういうものは考えなくていいので出力(計算時間)とのトレードオフですね
上述でちょっと指摘していますが、「当月の情報は当月が終わるまで未確定(出力無し)でよい」ならば、ですね
「月末に1回」正確に行われるか?も悩ましいところです
上記の環境で,Accessのフォーム上に異なる3つのPDFファイルを表示する機能を,ActiveXのWebブラウザコントロールに変更して使っているのですが,何回か表示を繰り返すと,
Adobe AcrobatまたはReaderに問題があります
Acrbat または Reader を実行している場合,もういちどやり直してください(0:521)
というエラーが出たり,Accessが固まったりするので,困っています。あちこち調べたら,
・直前に,
XXX.Controls(Webブラウザコントロール名).Navigate "about:blank"
を入れる
・Adobe Readerの「環境設定」→「セキュリティ(拡張)」で「起動時に保護モードを有効にする」をオフにする
とあったので試したのですが,どちらも効果がありません。他に回避方法をご存じの方がありましたら,ご教授願えませんでしょうか?
T_入出庫一覧に入庫情報・出庫情報を書き込む際に、以下のクエリを流してレコードを追加するようにしました。
保管個数を計算するのは月末の1回だけになると思うので、保管個数計算用のフォームを作成してT_手数料にレコードを追加し、それを集計して目的のレポートにしようと考えています。
これで当時の手数料単価・手数料の計算結果が残るようには出来ました。
あとは、どのように保管個数を計算するかです。
まずはこれの対策が先決ですね。
hirotonさんの提案の方法の場合は、前者の方法で手数料単価はDLookup関数で参照するように手直しすればいけると思います。
ただ、結局VBAが必須になるので、後者の方法でもいいかもしれません。