MS Access 2010查询多次拉出相同的记录,sql挑战

时间:2012-10-28 11:46:17

标签: sql ms-access

我目前正在开发一个使用ms Access 2010跟踪公司库存的程序。我很难获得用于显示库存的查询,以显示我想要的信息。问题似乎是查询多次拉出相同的记录,使预留和已售产品的总和膨胀。

背景: 我的公司库存钢筋。我们提议将条形切成碎片。从库存方面来说,我们想要跟踪每个酒吧的长度,从进入仓库的那一刻起,到仓库中的时间(可能会被切成小块),直到整个酒吧出售并消失。

数据库: 提出问题的查询是咨询3个表格;

  • 巴斯托克(以下字段)
    • BatchNumber(收到的所有酒吧,相同的生产热量)
    • BarNo(个别酒吧)
    • Orginial Length(在库存中收到的条的长度

(BatchNumber和BarNo合并,是主键)

  • 销售

    • ID(主键)
    • BatchNumber
    • 巴诺
    • 已售出数量
  • 预订(卖方可以保留一些材料,当客户表示有兴趣,但需要时间来决定)

    • ID(主键)
    • BatchNumber
    • 巴诺
    • 保留数量

我想将这三个表中的信息拉到一个列表中,显示: -Barstock.orginial length收到 - Sales.Quantity已售出售出 - 收到 - 按库存出售 - reservation.Quantity保留为预留 - 现货 - 保留为可用。

问题是我吮吸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 个答案:

答案 0 :(得分:9)

!!!检查一些假设

从您的数据库架构看来:

  • 可以为给定Sales的多个BatchNumber/BarNo记录(例如,我可以想象多个客户可能已经购买了相同栏的子部分)。
  • 可以为给定Reservation的多个BatchNumber/BarNo记录(例如,同一个栏的多个部分可能会被保留&#39;)< / LI>

要检查这些表中是否确实有多条记录,请尝试以下操作:

SELECT CountOfDuplicates
FROM   (SELECT COUNT(*) AS CountOfDuplicates
        FROM   Sales
        GROUP  BY BatchNumber & "," & BarNo)
WHERE  CountOfDuplicates > 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 

销售原始库存

现在,我们应该能够将前两个查询合并为一个。我没有尝试优化,只是为了使数据协同工作:

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():如果给定的Sales对没有ReservationBatchNumber/BarNo数据, SumAvQtySoldReserved的值将为Null,并且无论库存中的实际数量是多少,都会将OnStockAvailable呈现为空是我们期望的结果。

在Access中使用查询设计器,您必须单独创建3个查询,然后将它们组合起来 请注意,查询设计并不是非常擅长处理多个LEFTRIGHT联接,因此我不认为您可以一次性编写所有内容。< / p>

一些评论

我相信你应该阅读@Remou在评论中给你的信息 对我来说,这个数据库有一些不幸的设计选择:获取基本库存数据应该像保存库存记录的列上的简单SUM()一样简单。

通常,跟踪库​​存的一种简单方法是跟踪每个股票交易:

  • 收货库存记录有+数量
  • 外发库存记录有 - 数量
  • 记录还应跟踪部件/项目/栏参考(或ID),交易的日期和时间,以及 - 如果您想管理多个仓库 - 涉及哪个仓库ID。

因此,如果您需要了解所有商品的库存情况,您需要做的就是:

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

在您的情况下,虽然BatchNumber/BarNo是您的自然关键,但将它们保存在单独的Bar表格中会有一些优势:

  • 您可以使用Bar.ID在您需要的任何地方取回Bar.BatchNumberBar.BarNo
  • 您可以在BarIDBarStockSales表中使用Reservation作为外键。它使连接变得更容易,而不必混淆复合键的复杂性。

Access允许的东西并不是很好的做法,例如表名和字段中的空格,最终会降低可读性(至少因为你需要将它们保持在[]之间),少了与表示这些字段的VBA变量名一致,并且与不接受除表和字段名称的字母数字字符之外的任何其他数据库不兼容(如果您希望稍后调整大小或将数据库与其他应用程序连接)。

此外,通过坚持单一命名约定来帮助自己,并保持一致:

  • 不要不一致地混合大写和小写:要么使用CamelCase,要么使用小写或UPPER大小写,但始终遵守该规则。
  • 以单数形式命名表格 - 或复数形式 - 但保持一致。我更喜欢使用单数,例如表Part而不是Parts,但它只是一个约定(有其自身的原因)。
  • 拼写正确:Received而非Recieved。在调试为什么某些查询或VBA代码无法正常工作时,单独这个错误可能会花费你,只是因为有人犯了错字。
  • 每个表应/必须有ID列。通常,这将是一个自动增量,保证表中每条记录的唯一性。如果你保持这种惯例,那么外键变得容易猜测和阅读,你永远不必担心一些业务需求改变你可能突然发现自己有两个相同BatchNumbers的事实,由于某种原因你可以&# 39;现在不知道。

有很多关于数据库设计的争论,但有一些规则&#39;每个人都同意,所以我的建议应该是努力:

  • 简单性:确保每个表记录一种数据,并且不包含其他表中的冗余数据(规范化)。
  • 一致性:命名约定很重要。无论您选择什么,都要在整个项目中坚持下去。
  • 清晰度:确保您在3年内和其他人可以轻松阅读表名和字段,并了解它们的内容,而无需阅读300页规范。它并不总是那么清楚,但它是值得努力的。