Microsoft Access 掲示板

views
4 フォロー
6,278 件中 881 から 920 までを表示しています。
1

Report_Closeイベントはキャンセルできません。
自動生成されたイベントプロシージャにCancel引数がないイベントはキャンセルできません。

読み込み解除時(Report_Unload)イベントならキャンセルできます。

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
3

現在は自身のPCのデスクトップ上のフォルダの中に注文.csvがあります。
このフォルダを会社のサーバーに移動させます。
Accessの入っている会社のPCならどれからでもこのコードが動くように、PCからそのサーバー上のフォルダまでのパスを取得したいです。

2

ちなみに、C:¥Users¥中略の部分を変数にするコードは下記のようになります。
ただし、質問のコードでエラーがでるならこのコードでもエラーはでます。
やっていることは同じことなので。

Private Sub btn_注文データ取り込み_Click()
    Dim folderName As String
    Dim oldname as String
    Dim newname as String
    folderName = "C:¥Users¥中略"
    DoCmd.TransferText acImportDelim, "my_imp", "注文取込", folderName & "¥注文.csv", False, ""
    DoCmd.OpenQuery "Q_注文取込→注文データ"
    DoCmd.OpenQuery "Q_注文取込削除"
    
    Kill folderName & "¥前回注文.csv"
    oldname = folderName & "¥注文.csv"
    newname = folderName & "¥前回注文.csv"
    Name oldname As newname
    
    MsgBox "取り込みが完了しました。", vbInformation + vbOKOnly, "取込完了"

End Sub
1

どのPCからでもということですが、これらのPCは同じローカルネットワーク内にあるということですか。
C:¥Users¥中略 というフォルダーはローカルネットワーク上の特定のPCのフォルダーということですか。

「どのPCからでもこのフォルダを扱えるよう」ということを上記の点も含めていもう少し詳しく説明してもらえますか。

自身のPC内のC:¥Users¥中略フォルダーでそこに注文.csvが存在するなら、そのコードではエラーにはならないと思いますが。

8

前の質問の時もそうでしたが、こちらの質問に対する応答がないですね。
結局、何がしたいのか、何が問題なのか不明のまま議論が深まらずに終了するということになってます。

配列をどうしたいのか、それが不明瞭のままです。これを明確にしてください。

避けて通るとEXCELに応答していませんと表示されるのを、

レコードセットのデータをエクセルに出力するというのが目的でしょうか。
だとしたら、skさんの回答の CopyFromRecordset を使う方法で簡単に実現できます。
連想配列を使う必要もないです。

7
タークン 2024/01/19 (金) 16:13:24 7a0a1@2705a

hatenaさん、すみませんでした。
連想配列の存在を知らなかったので、読み飛ばしていました。
分からないところが山もり状態ですが、
避けて通るとEXCELに応答していませんと表示されるのを、
数秒間眺めることになるので、なんとか理解します。
放置すると、動かなくなる日は近いはずなので。
ここをクリアしても、また限界が現れると思いますが、
配列周りの処理方法は、次の段階で役立つと思うので、取り組んでみます。

6

データと一緒に、フィールド名を格納することはできなかった

データを整理して一括で貼り付けないと

  • そもそもそのプロシージャはどのファイルのどのモジュールに記述されているのか( Access データベースファイル上の標準モジュール、Excelマクロ有効ブックの標準モジュールなど)。

  • 取得したレコードセット(の各フィールドの名前と値)をどこに、どのような形で貼り付けようとしているのか。

以上の前提についてのご説明がない限り、何を問題視されているのか不明瞭なままです。

例えば「ある accdb ファイル上に存在するテーブルから[sptx]、[sbj]、[pymt]、[fwd]、[dat]の 5 つのフィールドを選択し、全てのレコードを[id]の昇順に並べ替えた結果を取得して、新規ブック上のワークシートに複写するプロシージャを Excel マクロ有効ブック上の標準モジュールに作成しようとしている」といった場合であれば、2次元配列に拘らずとも、Excel.Range オブジェクトの CopyFromRecordset メソッドを使用する、といった方法もあるでしょう。

'ファイルパスとテーブル名は適宜書き換えること
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
5
hatena 2024/01/19 (金) 15:08:03 修正

何番目に、どのフィールドをおいて呼び出したのか、
確認するコードを加えれば済む話ではあります。

そのコードを前の回答で提示したつもりですが。

どちらにしても、
2 次元配列をどのように利用しようとしているか。
レコードセットではだめなのか、その辺の説明がないと、
これ以上、議論のしようがないように思います。

4
りんご 2024/01/19 (金) 15:06:04 07313@0e907 >> 3

怪しい民間療法みたいな街角勉強会に引っかかっているんじゃないかしら?accessのようなデータベースがまだ発明されていない時代に、流行っていた思想は廃れたはずですが。

3
タークン 2024/01/19 (金) 14:38:38 7a0a1@2705a

まず、データと一緒に、フィールド名を格納することはできなかったようでした。
認識不足でした。

ACCESSのテーブルの、何番目のフィールドか調べたいわけではありません。
レコードセットは、フィールド名でデータを取り出せるので、
事前に、フィールドの並び順をカウントしておけば良いのですが、
よく単純な数え間違えが起こります。
何番目に、どのフィールドをおいて呼び出したのか、
確認するコードを加えれば済む話ではあります。
なのですが、フィールド名でデータを特定するのがベストなので、できればそうしたいということです。

と言っても、データを整理して一括で貼り付けないと、負荷はほとんど変わりません。
この処理段階の方が、何倍もミスを犯しやすいので、取るに足らないこだわりかもしれないです。

1

私はデザイン、レイアウトに力を入れてますよ。
ただし凝ったデザインにはしません。
シンプルでユーザーが使いやすいUIになるように意識してます。
例えば、下記とか。
入力必須項目のある入力フォームのUIを考察する - hatena chips

果ては白背景にテキストボックスの羅列、ラベルの見出しすらないものまであって辟易です(笑)

白背景にテキストボックスの羅列が使いにくいとは思いませんが、ラベルはあった方かいいでしょうね。

何かレイアウトのテンプレートを公開していらっしゃるサイト等、心あたりがありましたら教えて頂きたいです!

下記とか。

Accessフォームでおしゃれなデザインを作成 | 工場エンジニアのAccessスキル

ACCESS フォーム作成サンプル - たすけてACCESS

2

レコードセットは配列の上位互換だと思いますが、なぜ配列で処理する必要があるのでしょう?レコードセットならフィールド名でデータを取り出せます。どのような目的で配列にするのでしょうか。

やるとするなら、連想配列(Dictionary)にフィールド名と何列目かを格納して、参照することになるかな?

  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)
1

sptx、sbj、pymt、fwd、datという5つのフィールド名のデータを2次配列に格納します。

myArray = adoRs.GetRows

具体的にどのような目的から 2 次元配列を用いようとされているのでしょうか。

"n1-" & i = myArray(0, x)

少なくとも、上記のコードをそのまま記述すればコンパイルエラーが発生します。

実際の場合は、フィールド数が多い場合が多いので、数字で指定するのは非効率的です。
フィールド名で指定してデータを取り出すのが、現実的な方法だと思います。

2 次元配列を使用する目的が不明ですので、今のところ評価のしようがありません。

2
nanana 2024/01/18 (木) 16:47:57 e48ae@9a838

ありがとうございます!頂いた情報をよく読み、チャレンジしてみます。

1
hiroton 2024/01/18 (木) 16:02:23 99b6e@f966d

とりあえずで回答しますが、孫フォルダを対象にしたいなら


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


とするだけですね

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

それぞれの変数がどのように使われるのか理解して、必要に応じて必要な変数を用意してください

ただし、別階層のフォルダを対象とするということは、同名のフォルダがある可能性が否定できないので、処理の順番によっては望んだ結果にならない場合もあります。また、「見つかったものは全て」というのが望みの場合もあるでしょう。仕様を明確にしましょう

20

最初の"T_入出庫一覧"テーブルを正規化すると下記のようになります。

T_区分マスター

区分CD区分
1入庫
2出庫
3保管
 
T_商品マスター
商品CD商品名
1AAA
2BBB
3CCC
4DDD
 
T_T_入出庫履歴
入出庫履歴ID区分CD移動日商品CD金額
112023/11/3012000
212023/11/3022000
312023/11/3032000
412023/11/3042000
522023/12/2154
622023/12/2254
722023/12/2354
822023/12/2454
922023/12/25181
1022023/12/25281
1122023/12/25381
1222023/12/25481
1322023/12/101108
1422023/12/102108
1522023/12/103108
1622023/12/104108
1722023/12/111135
1822023/12/112135
1922023/12/113135
2022023/12/114135

正規化についてはWEB検索すれば解説ページは多数見つかりますので、わかりやすそうな所をいろいろ見て理解を深めてください。
とりあえず下記を紹介しておきます。

正規化とは - もう一度学ぶMS-Access

正規化の実例 - もう一度学ぶMS-Access

19
My Car Bomber 2024/01/17 (水) 12:51:36 23e8e@44ebd

一口に「正規化」といってもなかなか難しいですね・・・上手く理解できていないもので

正規化のコツ・正規化したテーブルの活用のコツ等はありますでしょうか?
とんちんかんな質問でしたら申し訳ございません。

8
ひで 2024/01/17 (水) 12:20:21 ddfe5@00814

hatenaさんありがとうございます。”テーブルで可能なことは、テーブルで行う” は確かにその通りですね。今回の件以外で、ついついクエリ時の関数で複雑な分岐をしがちなので大変参考になりました。

18

現状のテーブル設計がどうなっているか不明なので、回答が難しいです。

そもそものデータの作り方がまちがっているのでしょうか?

これについては、そもそも質問の最初の"T_入出庫一覧"テーブルの設計から間違っています。
テーブルの正規化ができていません。
前の質問の時も指摘しました。

レポートへの出力のレイアウトに合わせた設計にしたのでしょうが、データベースではこのようなデータの持ち方はしません。
今回のレポートの出力だけにしか使わないデータならいいのですが、今後、データベースの機能を活かした使い方に発展させていくことがあるのなら今のうちにテーブルの正規化から始めた方がいいでしょう。

正規化されていないテーブルはデータベースとしては使い物になりません。
正規化されていれば、そこから希望のレイアウトで出力することも可能です。

このデータは今回のレポート出力のみにしか使わないのでしょうか。
「在庫管理システム」ということなのでそうではないですよね。

17
すずやん 2024/01/16 (火) 17:30:37 >> 15

普段、SQL ServerのDBを使っているのでAccessでのクエリの動きははそんなに詳しくないのですが、「[総入庫数] - [総出庫数] AS 保管個数」を計算する[総入庫数]と[総出庫数]の追加先が「T3_1_手数料集計用」に無いからエラーになるってことでしょうか。
そうだとすると計算にはINSERT先はまだ関連してないのに、ちょっと不便な仕様ですね・・・。

例えばSELECT部分を意味なくまとめてもだめでしょうか?

SELECT

  • (
    SELECT
    FROM
    GROUP BY
    ) as T1

、のような感じです。
また、どうしてもだめであれば追加先のテーブルに総入庫数・総出庫数フィールドを追加すればいいのではないでしょうか。

16
My Car Bomber 2024/01/16 (火) 16:28:04 23e8e@44ebd >> 15

パラメータを要求される理由は分かっていて、保管個数の演算に使っている総入庫数・総出庫数フィールドの追加先を設定していないためです。
しかし、追加先のテーブルには総入庫数・総出庫数を入れるフィールドはなく、しかし総入庫数・総出庫数がないと保管個数が出せないため困っています。

15
すずやん 2024/01/16 (火) 10:25:17

過去の書き込みを軽くみただけですが、「T0_3_区分マスター」「Q3_1_総入出庫数集計用」の2テーブルだけですべての項目が出力できるのかな?とは感じました。

とりあえずクエリを単純化して確認することをおすすめします。
「INSERT INTO」する前に「SELECT」だけで結果を見る、や文言の間違い、「GROUP BY」を使わない場合にほしい項目が揃っているか否か、などを順に確認するのが良いかなと。

パラメータを要求される場合、大抵は意図しないケアレスミスが原因であることが多いですね。

14
My Car Bomber 2024/01/15 (月) 17:00:16 23e8e@44ebd >> 13

そもそものデータの作り方がまちがっているのでしょうか?

13
My Car Bomber 2024/01/15 (月) 16:12:41 23e8e@44ebd
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();

Q_保管個数を加工し、このようなクエリにしました。
あとはこのクエリでT_手数料集計用にレコードを追加できれば良いのですが、クエリ実行の際に総入庫数・総出庫数のパラメータを要求されてしまいます。T_手数料集計用に総入庫数・総出庫数のフィールドはありませんが、保管個数の演算用にこの2つのフィールドを消すわけにもいきません。どのようにすればよいでしょうか?

11
名前なし 2024/01/15 (月) 13:01:17 23e8e@44ebd

T_手数料集計用というテーブル(フィールド No.:オートナンバー型 区分:短いテキスト 移動日:日付/時刻 入庫数:数値 出庫数:数値 保管個数:数値 単価:数値 入出庫・保管料:数値
に、入庫時・出庫時にレコードを入れ、

Q_総入出庫数集計用↓

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();

を作成し、フォームで指定した期間までの総入庫数から総出庫数を引いた保管個数を求めることができました。
このQ_保管個数の保管個数にT_区分マスターの保管の手数料を掛ければ求めたい保管手数料を計算できると思うのですが、どのようにT_区分マスターの値を引っ張ってくればいいのか分かりません。

7

入力チェックはテーブルで設定しておくのが確実ですね。下記もご参考に。

テーブルでの入力チェック、入力規制 - hatena chips

ただ、これだけだとシステムの出すメッセージは不親切だし、未入力項目にフォーカス移動させるなど細かい制御ができないので、それがしたいときはVBAを使うことになります。その場合は下記などもご参考に。

複数項目の入力チェックを共通モジュール化する - hatena chips

6
ひで 2024/01/15 (月) 08:24:08 ddfe5@00814

hatenaさんありがとうございます。確かに「値入力」プロパティを「はい」がシンプルで一番いいですね。要は必須項目が未入力なら保存不可にしたらいいですね。こうしておけば入力順番もそんなに考えなくてもいいですね。出てくる現象に対してだけ対処しても根本が不完全なら意味ないですね。全体を見て作成しなくては上手くいきませんね。
まだまだ勉強が必要よ痛感しました。大変参考になりました。

5

前の回答でふれたように現状の仕様ではいろいろ不具合が出てくると思いますが、
とりあえずレコード移動したときに、常に[F1]にフォーカスを移動させておきたいのなら、
サブフォームのレコード移動時のイベントプロシージャを下記のように設定したらどうでしょう。

Private Sub Form_Current()
    Me.F1.SetFocus
End Sub

あるいは、F1フィールドが未入力の場合のみ移動させるなら、

Private Sub Form_Current()
     If IsNull(Me.F1.Value) Then Me.F1.SetFocus
End Sub
5
すぬぅ 2024/01/12 (金) 18:27:35 3c8aa@6f7d6

お返事ありがとうございます。

これを使いたいのですが,今のところ,Microsoft 365サブスクライパーのみとなっているみたいです。
パソコンについていたOffice2021にAccess2021だけを追加しているので,
これ以上お金をかけないでなんとかできないかな?と悪あがきをしているのですが…。

4

前にもいったようにフォーカス系のイベント内でSetFocusで制御しようとすると、今回のような場合も含めて、いろいろ複雑になり制御しきれません。ユーザーも必ず先頭項目から順に入力してくれるとは限りませんし、すべての項目を入力してから必須項目のデータを削除したりとかもありえます。それらも考慮するとますます泥沼になります。

一番確実なのは、入力必須フィールドはテーブルデザインで「値入力」プロパティを「はい」に設定しておくことです。
そうすればそのフィールドが未入力状態ではレコード保存できなくできます。

ユーザーに入力順を強制するというユーザーインターフェイス(UI)が本当に必要でしょうか。
レコード保存する前に、必須項目は入力されているか、入力値に矛盾はないか等をチェックして、問題があるときはメッセージを表示してユーザーに修正を即するというUIのほうが使いやすいし、設計もはるかに楽です。

3
ひで 2024/01/12 (金) 12:40:12 ddfe5@3f4b9

先ほど投稿したのですが、内容間違えてました。メインの項目だけ入力して(サブには未入力)新規レコードボタンで移動することは現状カバー出来てました。失礼しました。
やはりメイン・サブの入力後に新規レコードボタンで移動するとサブの直近に入力した項目にフォーカスが残ったままなので(F2、F3・・・)に留まったままなのでメイン入力後サブに移動すると記述しているメッセージが出るのをなんとかしたいということです。一回毎にフォームを閉じるとこうならないのですが。どう制御するといいか分からないので。

2
ひで 2024/01/12 (金) 11:40:47 ddfe5@3f4b9

hatenaさんありがとうございます。 MsgBox ("先にF1を入力して下さい。")のコードはF1以降の項目のフォーカス取得後(GotFocus)イベントに記述しています。防ぎたいことは例えばメインの項目だけ入力して(サブには未入力)新規レコードボタンで移動することです(他の移動ボタンにもそうですが)。確かに今の方法では都度の対処だけの感じですね。
全体で考えるならどんなアイデアがあるでしょうか? 思いつかないもので。

1

サブには必須項目を先に入力しないと他の項目には移れない様に下記のコード記述してます。

このコードをどこのどのイベントに記述してますか。一部を抜粋するのではなく、
Sub から End Sub までをすべてコピペしてもらった方が話かはやいと思います。

どちらにしても入力必須項目をSetFocusで制御しようという仕様は無理があると思いますので、この仕様から考え直した方かいい気がします。

4
hiroton 2024/01/12 (金) 10:40:07 1d724@f966d

よくわからないけど、結局WebブラウザコントロールってIEベースなのでもうダメ(Acrobat
側がIEを切ってるのでどうしようもない)とかなんじゃないですかね

別なコントロールを検討するしかないんじゃないでしょうか?
最新のACCESSだと標準で新しいWebブラウザコントロールもあるようです

EdgeBrowserControl オブジェクト (Access)

10
hiroton 2024/01/12 (金) 09:40:45 1d724@f966d

・手数料単価が変更になる場合、変更になった月以前の計算結果が変わらないようにしなければなりません。

見落としていました。(というか、表形式で提示されているデータしか見てませんでした)

データ構造をどうするか?はもっと前の段階の話ですね。hatenaさん指摘の通りでいいと思いますが、どのような手法を取るにせよ「手数料単価の変更履歴テーブル」は有ったほうがいいと思います。「手数料の改訂」は案件の発生とは別に発生すると思われるので


手数料テーブルを作っておく場合

結局は>> 3の冒頭で提示しているレポートのようなテーブルを事前に作っておくという話なので、データ生成の流れは同じです。レポートのオブジェクト・出力仕様を駆使してやるか、それらを全てVBA内で自前で用意するかだけの違いです

累計計算になる「保管料の情報」がキャッシュされるので、それが正しいと保証する仕組みや追加分だけの計算ですますための、どこまでのデータは確定情報なのか(追加で計算すべきデータはどれか)判断できる仕組みが必要になると思います


■「正しいと保証する仕組み」について
遡りで入出庫の情報が修正されると“それ以降の月の保管料のデータが全て”修正対象になる

とか

当月保管料が未確定の状態で保管料のデータを作るかどうか
作る→都度修正する仕組みが必要
作らない→月半ばで一時的なレポート表示が欲しいとかで困る

とか、既にデータがある/ないが様々な処理に影響します


(レポートで)出力のたびに累計計算をやり直す仕組みはこういうものは考えなくていいので出力(計算時間)とのトレードオフですね


保管個数を計算するのは月末の1回だけになると思う

上述でちょっと指摘していますが、「当月の情報は当月が終わるまで未確定(出力無し)でよい」ならば、ですね
「月末に1回」正確に行われるか?も悩ましいところです

3
すぬぅ 2024/01/11 (木) 17:19:21 3c8aa@6f7d6

上記の環境で,Accessのフォーム上に異なる3つのPDFファイルを表示する機能を,ActiveXのWebブラウザコントロールに変更して使っているのですが,何回か表示を繰り返すと,
 Adobe AcrobatまたはReaderに問題があります
 Acrbat または Reader を実行している場合,もういちどやり直してください(0:521)
というエラーが出たり,Accessが固まったりするので,困っています。あちこち調べたら,
・直前に,
    XXX.Controls(Webブラウザコントロール名).Navigate "about:blank"
 を入れる
・Adobe Readerの「環境設定」→「セキュリティ(拡張)」で「起動時に保護モードを有効にする」をオフにする
とあったので試したのですが,どちらも効果がありません。他に回避方法をご存じの方がありましたら,ご教授願えませんでしょうか?

9
My Car Bomber 2024/01/11 (木) 15:37:29 修正 7fdfc@44ebd

T_入出庫一覧に入庫情報・出庫情報を書き込む際に、以下のクエリを流してレコードを追加するようにしました。

INSERT INTO T_手数料 ( 区分, 移動日, 出庫数, 単価, 入出庫・保管料 )
SELECT T_在庫移動(出庫)tmp.区分, T_在庫移動(出庫)tmp.移動日, T_在庫移動(出庫)tmp.合計 AS 出庫数, T_区分マスター.単価, [合計]*[単価] AS 入出庫・保管料
FROM T_区分マスター INNER JOIN T_在庫移動(出庫)tmp ON T_区分マスター.区分 = T_在庫移動(出庫)tmp.区分;
INSERT INTO T_手数料 ( 区分, 移動日, 入庫数, 単価, 入出庫・保管料 )
SELECT T_入庫情報tmp.区分, T_入庫情報tmp.移動日, T_入庫情報tmp.合計 AS 入庫数, T_区分マスター.単価, [合計]*[単価] AS 入出庫・保管料
FROM T_区分マスター INNER JOIN T_入庫情報tmp ON T_区分マスター.区分 = T_入庫情報tmp.区分;

保管個数を計算するのは月末の1回だけになると思うので、保管個数計算用のフォームを作成してT_手数料にレコードを追加し、それを集計して目的のレポートにしようと考えています。

これで当時の手数料単価・手数料の計算結果が残るようには出来ました。

あとは、どのように保管個数を計算するかです。

8
hatena 2024/01/11 (木) 14:24:38 修正

・手数料単価が変更になる場合、変更になった月以前の計算結果が変わらないようにしなければなりません。

まずはこれの対策が先決ですね。

  • 手数料単価の変更履歴テーブルを作成して、そこから対応する年月の単価を参照する設計にする。
  • いっそのことレポートの出力形式とおなじになるテーブルを作成しておいて、VBAで出力する。

hirotonさんの提案の方法の場合は、前者の方法で手数料単価はDLookup関数で参照するように手直しすればいけると思います。
ただ、結局VBAが必須になるので、後者の方法でもいいかもしれません。