在庫管理システムの一連の質問でお世話になっております。
最終的にこのような一覧表のレポートを作成したいです。
毎月末に、入庫・出庫の数量を合算して入庫・出庫・保管料の請求額を表示したいです。
No | 区分 | 移動日 | 入庫数 | 出庫数 | 保管個数 | 手数料単価 | 手数料 |
---|---|---|---|---|---|---|---|
1 | 入庫 | 2023年11月 | 8000 | 10.0 | 80000 | ||
2 | 保管 | 2023年11月 | 8000 | 30.5 | 244000 | ||
3 | 出庫 | 2023年12月 | 1512 | 10.0 | 15120 | ||
4 | 保管 | 2023年12月 | 6488 | 30.5 | 197884 |
このような入出庫一覧表のレポートを作成しました。
レコードソース:レポートと同じフィールドを持つ"T_入出庫一覧"テーブル
No | 区分 | 移動日 | 商品1 | 商品2 | 商品3 | 商品4 | 合計 |
---|---|---|---|---|---|---|---|
1 | 入庫 | 2023/11/30 | 2000 | 2000 | 2000 | 2000 | 8000 |
2 | 出庫 | 2023/12/02 | 54 | 54 | 54 | 54 | 216 |
3 | 出庫 | 2023/12/25 | 81 | 81 | 81 | 81 | 324 |
4 | 出庫 | 2023/12/10 | 108 | 108 | 108 | 108 | 432 |
5 | 出庫 | 2023/12/11 | 135 | 135 | 135 | 135 | 540 |
"T_区分マスター"
区分ID | 区分 | 手数料単価 |
---|---|---|
1 | 入庫 | 10.0 |
2 | 出庫 | 10.0 |
3 | 保管 | 30.5 |
・手数料単価が変更になる場合、変更になった月以前の計算結果が変わらないようにしなければなりません。
とりあえず確認
「入庫」「出庫」が同一月に発生することはありますか?その場合どのような表示になりますか?
「入庫」「出庫」が発生せず、「保管」だけが発生する月はありますか?
両方あり得ます。
入庫・出庫が同一月に発生する場合、1行目入庫、2行目出庫、3行目保管になるようにしたいと考えています。
適当に「2024年3月に400個出庫」のデータを加えたサンプル
hirotonは「簡単な手法」が思い浮かばなかったので覚悟してください
複雑な要件なので問題を分解します
1.「保管」の累計個数をどう計算するか
2.「No」の連番をどう取得するか
3.「存在しない月のデータ」をどう補完するか
回答としては一緒くたにやっていますが、どの問題を解決するためのものなのか考えながら見てください
レポートのレコードソースのクエリ
上記クエリによるレポート出力用の基礎データ例
レポートのモジュール
レポートのデザイン
1.「保管」の累計個数をどう計算するか
入庫を足して在庫を減らして、それを積み立てれば累計(残在庫)です。ACCESSレポートではテンプレート的な用法があるのでそのまま使います
詳細セクションに「累計」テキストボックスを配置します
詳細セクションでデータを表示する必要はないので枠線だけ表示されるように調整しています。(非表示+枠線は別なコントロールでとかでもいいです)
「移動月」でグループ化して、フッターを配置し、「保管」行として使います
「保管」専用の行なので「区分」はラベルコントロールでそのまま「保管」を表示、その他必要なテキストボックスを配置します
2.「No」の連番をどう取得するか
「保管」データの累計計算のためにセクションを跨いでしまったのでVBAで計算・設定します
非連結のテキストボックスに、データが出力されるたび
+1
してデータを設定するだけです。「データが出力されるたび」がどんな時かきちんと把握しておく必要があります今回は適当に上から「No_補完」「No_入出庫」「No_保管」という名前にしました
出力のタイトルは「移動日」ですが、元データに「移動日」フィールドがあるので、データ段階では「移動月」の名前になっています。レポートに配置するラベルで「移動日」と表示すればいいと思います
この「移動月」でグループ化してヘッダー・フッターを設置します。デフォルトでは「グループヘッダー0」「グループフッター0」のような名前になっていますが、解説用にそれぞれ「移動月ヘッダー」「移動月フッター」と名前を変えています。
移動月ヘッダーの使い方は次での解説がメインですが、「No」表記が必要なのでここでの解説に「No_補完」が紛れ込んでいます
連番を付けるだけ、でいいのであればよくある手法があるんですが、その他の要求と組み合わせるとどうするといいのか悩みどころですね
3.「存在しない月のデータ」をどう補完するか
「新しいデータを読み込んだ時、古いデータとの比較で月が離れていたら、データを挿入する」方法を取ります
「データ」はレポートのクエリを基に詳細セクションで読み込まれるので、「『移動月』でグループ化し、グループヘッダーを設置すると、『新しいデータと古いデータの間』」になります
このグループヘッダーを出力しなかったり、出力したり、たくさん出力するようにすれば、存在しないデータの補完ができます
移動月ヘッダーで表示する「区分」も「保管」のみなので、区分はラベルコントロールです
その他のテキストボックスはそれぞれ
です。存在しない月データの補完用のセクションなので全部「補完」とつけてるだけです
新しいレコードに移って捨てられてしまうデータをVBAで保存しておいて必要に応じて(非連結の)テキストボックスに設定、セクションの出力(繰り返し出力)をするとかそんな流れになっています
その他
移動日/移動月については軽く触れていますが、そのほか、後の処理の(楽をしたい)都合で日付データとして各月の1日に統一したデータで扱っています
レポートの表示はテキストボックスの書式の設定(
YYYY年MM月
)で対応しています「抽出の最小日以前から保管個数がある場合」は考慮していません
その他、細かいところは適当なので(代替の背景色が有効のせいで微妙に表示がおかしいとか)そういう調整は必要です
こういう案件の場合、ワークテーブルを用意してゴリゴリしてからそれをレポートにとかってなるんですかねぇ
Noの連番取るのにVBA使わないとダメなの何か方法あるんじゃない?って思わなくもないけど、保管用のデータ作るとこと考えるとそっちがめちゃくちゃ遠回りになりそうだしなぁとか
「とりあえずやってみたらそれっぽくできたので公開してるだけ」なのでこういう手法どうなの?とかあればください
まずはこれの対策が先決ですね。
hirotonさんの提案の方法の場合は、前者の方法で手数料単価はDLookup関数で参照するように手直しすればいけると思います。
ただ、結局VBAが必須になるので、後者の方法でもいいかもしれません。
T_入出庫一覧に入庫情報・出庫情報を書き込む際に、以下のクエリを流してレコードを追加するようにしました。
保管個数を計算するのは月末の1回だけになると思うので、保管個数計算用のフォームを作成してT_手数料にレコードを追加し、それを集計して目的のレポートにしようと考えています。
これで当時の手数料単価・手数料の計算結果が残るようには出来ました。
あとは、どのように保管個数を計算するかです。
見落としていました。(というか、表形式で提示されているデータしか見てませんでした)
データ構造をどうするか?はもっと前の段階の話ですね。hatenaさん指摘の通りでいいと思いますが、どのような手法を取るにせよ「手数料単価の変更履歴テーブル」は有ったほうがいいと思います。「手数料の改訂」は案件の発生とは別に発生すると思われるので
手数料テーブルを作っておく場合
結局は>> 3の冒頭で提示しているレポートのようなテーブルを事前に作っておくという話なので、データ生成の流れは同じです。レポートのオブジェクト・出力仕様を駆使してやるか、それらを全てVBA内で自前で用意するかだけの違いです
累計計算になる「保管料の情報」がキャッシュされるので、それが正しいと保証する仕組みや追加分だけの計算ですますための、どこまでのデータは確定情報なのか(追加で計算すべきデータはどれか)判断できる仕組みが必要になると思います
■「正しいと保証する仕組み」について
遡りで入出庫の情報が修正されると“それ以降の月の保管料のデータが全て”修正対象になる
とか
当月保管料が未確定の状態で保管料のデータを作るかどうか
作る→都度修正する仕組みが必要
作らない→月半ばで一時的なレポート表示が欲しいとかで困る
とか、既にデータがある/ないが様々な処理に影響します
(レポートで)出力のたびに累計計算をやり直す仕組みはこういうものは考えなくていいので出力(計算時間)とのトレードオフですね
上述でちょっと指摘していますが、「当月の情報は当月が終わるまで未確定(出力無し)でよい」ならば、ですね
「月末に1回」正確に行われるか?も悩ましいところです
T_手数料集計用というテーブル(フィールド No.:オートナンバー型 区分:短いテキスト 移動日:日付/時刻 入庫数:数値 出庫数:数値 保管個数:数値 単価:数値 入出庫・保管料:数値
に、入庫時・出庫時にレコードを入れ、
Q_総入出庫数集計用↓
Q_保管個数↓
を作成し、フォームで指定した期間までの総入庫数から総出庫数を引いた保管個数を求めることができました。
このQ_保管個数の保管個数にT_区分マスターの保管の手数料を掛ければ求めたい保管手数料を計算できると思うのですが、どのようにT_区分マスターの値を引っ張ってくればいいのか分かりません。
あ、質問主です。
Q_保管個数を加工し、このようなクエリにしました。
あとはこのクエリでT_手数料集計用にレコードを追加できれば良いのですが、クエリ実行の際に総入庫数・総出庫数のパラメータを要求されてしまいます。T_手数料集計用に総入庫数・総出庫数のフィールドはありませんが、保管個数の演算用にこの2つのフィールドを消すわけにもいきません。どのようにすればよいでしょうか?
そもそものデータの作り方がまちがっているのでしょうか?
過去の書き込みを軽くみただけですが、「T0_3_区分マスター」「Q3_1_総入出庫数集計用」の2テーブルだけですべての項目が出力できるのかな?とは感じました。
とりあえずクエリを単純化して確認することをおすすめします。
「INSERT INTO」する前に「SELECT」だけで結果を見る、や文言の間違い、「GROUP BY」を使わない場合にほしい項目が揃っているか否か、などを順に確認するのが良いかなと。
パラメータを要求される場合、大抵は意図しないケアレスミスが原因であることが多いですね。
パラメータを要求される理由は分かっていて、保管個数の演算に使っている総入庫数・総出庫数フィールドの追加先を設定していないためです。
しかし、追加先のテーブルには総入庫数・総出庫数を入れるフィールドはなく、しかし総入庫数・総出庫数がないと保管個数が出せないため困っています。
普段、SQL ServerのDBを使っているのでAccessでのクエリの動きははそんなに詳しくないのですが、「[総入庫数] - [総出庫数] AS 保管個数」を計算する[総入庫数]と[総出庫数]の追加先が「T3_1_手数料集計用」に無いからエラーになるってことでしょうか。
そうだとすると計算にはINSERT先はまだ関連してないのに、ちょっと不便な仕様ですね・・・。
例えばSELECT部分を意味なくまとめてもだめでしょうか?
SELECT
SELECT
FROM
GROUP BY
) as T1
、のような感じです。
また、どうしてもだめであれば追加先のテーブルに総入庫数・総出庫数フィールドを追加すればいいのではないでしょうか。
現状のテーブル設計がどうなっているか不明なので、回答が難しいです。
これについては、そもそも質問の最初の"T_入出庫一覧"テーブルの設計から間違っています。
テーブルの正規化ができていません。
前の質問の時も指摘しました。
レポートへの出力のレイアウトに合わせた設計にしたのでしょうが、データベースではこのようなデータの持ち方はしません。
今回のレポートの出力だけにしか使わないデータならいいのですが、今後、データベースの機能を活かした使い方に発展させていくことがあるのなら今のうちにテーブルの正規化から始めた方がいいでしょう。
正規化されていないテーブルはデータベースとしては使い物になりません。
正規化されていれば、そこから希望のレイアウトで出力することも可能です。
このデータは今回のレポート出力のみにしか使わないのでしょうか。
「在庫管理システム」ということなのでそうではないですよね。
一口に「正規化」といってもなかなか難しいですね・・・上手く理解できていないもので
正規化のコツ・正規化したテーブルの活用のコツ等はありますでしょうか?
とんちんかんな質問でしたら申し訳ございません。
最初の"T_入出庫一覧"テーブルを正規化すると下記のようになります。
T_区分マスター
正規化についてはWEB検索すれば解説ページは多数見つかりますので、わかりやすそうな所をいろいろ見て理解を深めてください。
とりあえず下記を紹介しておきます。
正規化とは - もう一度学ぶMS-Access
正規化の実例 - もう一度学ぶMS-Access