6

現在、ms Access 2010を使用して、会社の在庫を追跡するプログラムに取り組んでいます。在庫を表示するためのクエリを取得して、必要な情報を表示するのに苦労しています。問題は、クエリが同じレコードを複数回プルし、予約された製品と販売された製品の合計を膨らませることにあるようです。

背景:私の会社は棒鋼を在庫しています。バーを細かく切ることを提案します。在庫の面から、各バーが倉庫に入った瞬間から、倉庫にいる時間(小さな断片に切り分けられる可能性がある)まで、バー全体が販売されてなくなるまでの長さを追跡したいと思います。 。

データベース:問題を与えるクエリは、3つのテーブルを調べています。

  • バーストック(以下のフィールド付き)
    • BatchNumber(すべてのバーが受信され、同じ生産熱に影響します)
    • BarNo(個別のバー)
    • 元の長さ(ストックで受け取ったときのバーの長さ)

(BatchNumberとBarNoを組み合わせたものが主キーです)

  • 売上高

    • ID(主キー)
    • バッチ番号
    • BarNo
    • 販売数量
  • 予約(顧客が興味を示したが、決定するのに時間が必要な場合、売り手はいくつかの資料を予約します)

    • ID(主キー)
    • バッチ番号
    • BarNo
    • 予約数量

3つのテーブルから情報を1つのリストにまとめて、次の情報を表示したいと思います。利用可能として予約済み。

問題は、私がSQLを吸うことです。私は自分の能力を最大限に発揮するために結合と内部結合を調べましたが、私の努力は無駄でした。私は通常、必要なSqlステートメントを生成するためにデザインビューに依存しています。デザインビューで、私は次のSQLを思いついた:

SELECT 
  BarStock.BatchNo
  , BarStock.BarNo
  , First(BarStock.OrgLength) AS Recieved
  , Sum(Sales.QtySold) AS SumAvQtySold
  , [Recieved]-[SumAvQtySold] AS [On Stock]
  , Sum(Reservation.QtyReserved) AS Reserved
  , ([On Stock]-[Reserved])*[Skjemaer]![Inventory]![unitvalg] AS Available
FROM 
  (BarStock 
    INNER JOIN Reservation ON (BarStock.BarNo = Reservation.BarNo) AND (BarStock.BatchNo = Reservation.BatchNo)
  ) 
    INNER JOIN Sales ON (BarStock.BarNo = Sales.BarNo) AND (BarStock.BatchNo = Sales.BatchNo)
GROUP BY 
  BarStock.BatchNo
  , BarStock.BarNo

クエリが同じレコードを複数回プルしていることはわかっています。--GROUP BY用語を削除すると、まったく同じレコードがいくつか取得されます。-ただし、対応するテーブルには、これらのレコードのインスタンスが1つだけあります。

きちんと説明できたと思いますので、詳しく教えてください。

私の問題を見てくれてありがとう!

4

1 に答える 1

10

!!! いくつかの仮定を確認する

データベーススキーマから、次のようになります。

  • 特定のレコードが複数存在する可能性があります(たとえば、複数の顧客が同じバーのサブセクションを購入した可能性があると想像できます)。SalesBatchNumber/BarNo
  • 特定のレコードが複数存在する可能性があります(たとえば、同じバーの複数のセクションを「予約」することができます)。ReservationBatchNumber/BarNo

これらのテーブルに実際に複数のレコードがあるかどうかを確認するには、次のようにしてみてください。

SELECT CountOfDuplicates
FROM   (SELECT COUNT(*) AS CountOfDuplicates
        FROM   Sales
        GROUP  BY BatchNumber & "," & BarNo)
WHERE  CountOfDuplicates > 1 

クエリがいくつかのレコードを返す場合は、重複があり、クエリが誤った値を返しているのはおそらくそのためです。

ゼロから始める

さて、クエリを機能させる秘訣は、表示したい主なデータを実際に考えて、そこから始めることです。

  • 基本的に、在庫内のすべてのバーのリストが必要です。これらのバーの一部は販売されているか、予約されている可能性がありますが、そうでない場合は、在庫がある数量を表示する必要があります。あなたの現在のクエリはあなたにそれを決して示しません。
  • 在庫のあるバーごとに、販売数量と予約数量をリストし、それらを組み合わせて、残りの在庫数を調べます。

ですから、あなたの中心的なデータは在庫のあるバーのリストであることは明らかです。

すべてをすぐに1つの大きなクエリにまとめようとするのではなく、これらの目標ごとに単純なクエリを作成し、それぞれの場合に適切なデータを取得することをお勧めします。

ただのバー

あなたが説明したことから、個々のバーはBarStockテーブルに記録されます。
コメントで述べたように、私が理解していることから、配信されるすべてのバーには、BarStock重複のない単一のレコードがテーブルにあります。したがって、在庫を測定する必要がある主なリストは次のBarStock表です。

SELECT BatchNumber, 
       BarNo, 
       OrgLength
FROM   BarStock

ただの販売

BatchNumber/BarNo繰り返しになりますが、これは非常に簡単なはずです。各ペアで販売された全長を確認する必要があります。

SELECT BatchNumber, 
       BarNo, 
       Sum(QtySold) AS SumAvQtySold
FROM   Sales
GROUP BY BatchNumber, BarNo

予約だけ

販売と同じ:

SELECT BatchNumber,
       BarNo,
       SUM(QtyReserved) AS Reserved
FROM   Reservation
GROUP  BY BatchNumber, BarNo 

販売に対する元の在庫

これで、最初の2つのクエリを1つにまとめることができるはずです。データを連携させるためだけに、最適化しようとはしていません。

SELECT BarStock.BatchNumber,
       BarStock.BarNo,
       BarStock.OrgLength,
       S.SumAvQtySold,
       (BarStock.OrgLength - Nz(S.SumAvQtySold)) AS OnStock
FROM   BarStock
LEFT JOIN (SELECT BatchNumber,
                  BarNo,
                  Sum(QtySold) AS SumAvQtySold
           FROM   Sales
           GROUP  BY BatchNumber, BarNo) AS S
  ON (BarStock.BatchNumber = S.BatchNumber) AND (BarStock.BarNo = S.BarNo) 

LEFT JOINまだ販売されていないバーの在庫があるかもしれないので、私たちはそうします。
私たちがやった場合INNER JOIN、私たちは最終報告書でこれらを見逃していると思い、そもそもこれらのバーは決してそこになかったと信じるようになりました。

すべて一緒に

LEFT JOINこれで、クエリ全体を予約済みのバーに対して別のクエリでラップして、最終結果を得ることができます。

SELECT BS.BatchNumber,
       BS.BarNo,
       BS.OrgLength,
       BS.SumAvQtySold,
       BS.OnStock,
       R.Reserved,
       (OnStock - Nz(Reserved)) AS Available
FROM   (SELECT BarStock.BatchNumber,
               BarStock.BarNo,
               BarStock.OrgLength,
               S.SumAvQtySold,
               (BarStock.OrgLength - Nz(S.SumAvQtySold)) AS OnStock
        FROM   BarStock
        LEFT JOIN (SELECT BatchNumber,
                          BarNo,
                          SUM(QtySold) AS SumAvQtySold
                   FROM   Sales
                   GROUP  BY BatchNumber,
                             BarNo) AS S
          ON (BarStock.BatchNumber = S.BatchNumber) AND (BarStock.BarNo = S.BarNo)) AS BS
LEFT JOIN (SELECT BatchNumber,
                  BarNo,
                  SUM(QtyReserved) AS Reserved
           FROM   Reservation
           GROUP  BY BatchNumber,
                     BarNo) AS R
  ON (BS.BatchNumber = R.BatchNumber) AND (BS.BarNo = R.BarNo) 

Nz()結合の右側にあるforアイテムの使用に注意してください。特定のペアのデータがない場合、Salesまたはの値は、実際の在庫数に関係なく、レンダリングされ、 nullになります。私たちが期待する結果ではないでしょう。ReservationBatchNumber/BarNoSumAvQtySoldReservedNullOnStockAvailable

Accessでクエリデザイナを使用すると、3つのクエリを個別に作成してから、それらを組み合わせる必要があります。
ただし、Query Designedは複数LEFTRIGHT結合を処理するのがあまり得意ではないため、一度にすべてを記述できなかったと思います。

いくつかのコメント

@Remouが彼のコメントであなたに与えた情報を読むべきだと私は信じています。私にとって、このデータベースにはいくつかの不幸な設計上の選択があります。基本的な在庫データの取得は、在庫レコードを保持する列で
の単純なものと同じくらい簡単である必要があります。SUM()

通常、在庫を追跡する簡単な方法は、各株式取引を追跡することです。

  • 入荷在庫レコードには+数量があります
  • 出庫在庫レコードには-数量があります
  • レコードには、部品/アイテム/バーの参照(またはID)、トランザクションの日時、および(複数の倉庫を管理する場合は)どの倉庫IDが関係しているかも追跡する必要があります。

したがって、すべてのアイテムの手元にある完全な在庫を知る必要がある場合、必要なのは次のようなものだけです。

SELECT BarID,
       Sum(Quantity)
FROM   StockTransaction
GROUP BY BarID

あなたの場合、それBatchNumber/BarNoはあなたの自然キーですが、それらを別のBarテーブルに保持することにはいくつかの利点があります。

  • あなたはそれBar.IDを取り戻すためにBar.BatchNumberそしてBar.BarNoあなたがそれを必要とするところならどこでも使うことができます。
  • 、およびテーブルBarIDで外部キーとして使用できます。複合キーの複雑さを台無しにすることなく、結合が簡単になります。BarStockSalesReservation

テーブル名やフィールドのスペースなど、Accessで許可されているものがあります。これにより、読みにくくなり(少なくとも間に保持する必要があるため[])、これらを表すVBA変数名との整合性が低下します。フィールドであり、テーブル名とフィールド名に英数字以外のものを受け入れない他のデータベースとは互換性がありません(後でサイズを大きくするか、データベースを他のアプリとインターフェースする必要があります)。

また、単一の命名規則に固執することで自分自身を助け、一貫性を保ちます。

  • 大文字と小文字を一貫して混在させないでください。すべてにキャメルケースを使用するか、小文字または大文字を使用しますが、常にその規則に従ってください。
  • テーブルに単数形(または複数形)で名前を付けますが、一貫性を保ちます。Part私は、の代わりにテーブルのような単数を使用することを好みますPartsが、それは単なる慣例です(それは独自の理由があります)。
  • 正しくつづります:そうでReceivedはありませんRecieved。誰かがタイプミスをしたという理由だけで、一部のクエリまたはVBAコードが機能しない理由をデバッグするときに、その間違いだけでコストがかかる可能性があります。
  • ID各テーブルには列が必要です。通常、これはテーブル内の各レコードの一意性を保証する自動インクリメントになります。その慣習を守れば、外部キーは推測しやすくなり、読みやすくなります。ビジネス要件によって、2つの同一のものが突然見つかる可能性があるという事実を心配する必要はありBatchNumbersません。何らかの理由で、今は理解できません。

データベース設計については多くの議論がありますが、誰もが同意する特定の「ルール」があるので、私の推奨事項は次のことを目指して努力することです。

  • シンプルさ:各テーブルが1種類のデータを記録し、他のテーブルからの冗長データが含まれていないことを確認します(正規化)。
  • 一貫性:命名規則は重要です。何を選択しても、プロジェクト全体を通してそれに固執します。
  • 明確さ:3歳以上の人や他の人が、300ページの仕様を読まなくても、テーブルの名前とフィールドを簡単に読んで、それらが何であるかを理解できるようにしてください。常に明確にすることは可能ではありませんが、それは努力すべきことです。
于 2012-10-29T15:11:42.923 に答える