MS Access 2010 查询多次提取相同的记录,sql 挑战
Posted
技术标签:
【中文标题】MS Access 2010 查询多次提取相同的记录,sql 挑战【英文标题】:MS Access 2010 query pulls same records multiple times, sql challenge 【发布时间】:2012-10-28 11:46:16 【问题描述】:我目前正在开发一个使用 ms Access 2010 跟踪我公司库存的程序。我很难获得旨在显示库存的查询以显示我想要的信息。问题似乎是查询多次提取相同的记录,从而夸大了保留和已售产品的总和。
背景: 我公司库存钢筋。我们提供将酒吧切成小块。从库存方面,我们想要跟踪每根棒材的长度,从它进入仓库的那一刻起,到它在仓库中的时间(它可能会被切成小块),直到整个棒材被售出并消失.
数据库: 查询给出问题,正在查询3个表;
棒料(具有以下字段) BatchNumber(收到的所有棒材,属于同一生产热区) BarNo(单个栏) 原始长度(在库存收到时棒材的长度(BatchNumber 和 BarNo 结合,为主键)
销售
ID(主键) 批号 酒吧号 售出数量预订(卖家可以预订一些材料,当客户表示有兴趣但需要时间来决定时)
ID(主键) 批号 酒吧号 保留数量我想将三个表中的信息提取到一个列表中,该列表显示: -Barstock.orginial 长度如收到 - Sales.Quantity sold As Sold - 已收到 - 按库存出售 - reservation.Quantity Reserved As Reserved - 有货 - 保留可用。
问题是我不擅长 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 术语时,我得到了几条完全相同的记录。 - 但是,在相应的表中只有这些记录的一个实例。
我希望我能够正确解释自己,请问我是否需要详细说明。
感谢您花时间查看我的问题!
【问题讨论】:
根据三个表创建一个不分组的查询,然后删除一个表并运行该查询。重复直到找到导致重复的表。然后编辑查询以避免重复或在此处发布示例数据以寻求帮助。 顺便说一句,我想问题出在销售表上。 您好 Remou,感谢您的回答,是的,您是对的 - 当我删除 sales 表时,预订记录的重复就停止了。你能告诉我你是如何做出预测的吗? Barstock 在连接字段上有一个唯一索引,所以不是这样,Reservations 没有,但不太可能包含重复项。销售是最有可能的。 我开始了一个很长的答案,但有些事情让我很震惊:你如何管理BarStock
中切割条的长度?此外,First()
绝对不是您的意思,您在查询中使用它的方式绝对可以返回任何内容。
【参考方案1】:
!!!检查一些假设
从您的数据库架构看来:
对于给定的BatchNumber/BarNo
,可能有多个 Sales
记录(例如,我可以想象多个客户可能已经购买了同一条的子部分)。
对于给定的BatchNumber/BarNo
,可能有多个 Reservation
记录(例如,同一条的多个部分可以“保留”)
要检查这些表中是否确实有多条记录,请尝试以下操作:
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
原始库存与销售额
现在,我们应该能够将前 2 个查询合并为一个。我不是想优化,只是为了让数据一起工作:
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()
用于连接右侧的项目:如果给定的BatchNumber/BarNo
对没有Sales
或Reservation
数据,则SumAvQtySold
和@ 的值987654343@ 将是 Null
并且将呈现 OnStock
和 Available
为空,无论实际库存数量是多少,这不会是我们预期的结果。
使用 Access 中的查询设计器,您必须分别创建 3 个查询,然后将它们组合起来。
请注意,虽然查询设计不太擅长处理多个 LEFT
和 RIGHT
连接,所以我认为您不可能一口气写完所有内容。
一些cmets
我相信你应该阅读@Remou 在他的 cmets 中给你的信息。
对我来说,这个数据库有一些不幸的设计选择:获取基本库存数据应该像保存库存记录的列上的SUM()
一样简单。
通常,跟踪库存的一种简单方法是跟踪每笔库存交易:
进货记录有一个 + 数量 出库记录有一个 - 数量 记录还应跟踪零件/项目/棒材参考(或 ID)、交易的日期和时间,以及 - 如果您要管理多个仓库 - 涉及哪个仓库 ID。因此,如果您需要了解所有商品的完整库存,您需要做的就是:
SELECT BarID,
Sum(Quantity)
FROM StockTransaction
GROUP BY BarID
在您的情况下,虽然 BatchNumber/BarNo
是您的自然键,但将它们保存在单独的 Bar
表中会有一些优势:
Bar.ID
取回Bar.BatchNumber
和Bar.BarNo
。
您可以在BarStock
、Sales
和Reservation
表中使用BarID
作为外键。它使连接变得更容易,而不必弄乱复合键的复杂性。
Access 允许的某些事情并不是真正的好习惯,例如表名和字段中的空格,这最终会降低可读性(至少因为您需要将它们保持在 []
之间),与表示这些字段的 VBA 变量名称,并且与不接受表和字段名称以外的任何字符的其他数据库不兼容(如果您希望以后扩大规模或将您的数据库与其他应用程序连接)。
此外,通过坚持单一的命名约定来帮助自己,并保持一致:
不要不一致地混合大小写:使用 CamelCase,或者小写或大写,但始终遵守该规则。 以单数或复数形式命名表,但保持一致。我更喜欢使用单数,例如表Part
而不是Parts
,但这只是一种约定(有其自身的原因)。
拼写正确:它是Received
而不是Recieved
。在调试某些查询或 VBA 代码无法正常工作的原因时,仅这个错误就可能会让您付出代价,因为有人打错了字。
每个表应该/必须有一个ID
列。通常,这将是一个自动增量,以保证表中每条记录的唯一性。如果你保持这个约定,那么外键就很容易被猜测和阅读,而且你永远不必担心一些业务需求会改变这样一个事实,即你会突然发现自己有两个相同的BatchNumbers
,出于某种原因你无法理解现在。
关于数据库设计有很多争论,但有一些人人都同意的“规则”,所以我的建议应该是争取:
简单:确保每个表记录一种数据,并且不包含来自其他表的冗余数据(规范化)。 一致性:命名约定很重要。无论您选择什么,请在整个项目中坚持下去。 清晰:确保 3 年后的您和其他人可以轻松阅读表名和字段并了解它们的含义,而无需阅读 300 页的规范。不一定总是那么清楚,但要努力争取。【讨论】:
再次感谢您的宝贵时间和回答。我也很感谢您关于数据库设计的 cmets。我对关系数据库没有太多经验,所以欢迎您的输入!真的很感激!!! @Rookie 不客气,希望它对您解决问题有用。 确实如此。在我的sql教育方面也很有价值!祝您今天愉快!以上是关于MS Access 2010 查询多次提取相同的记录,sql 挑战的主要内容,如果未能解决你的问题,请参考以下文章