我目前正在开发一个程序来跟踪我公司的库存,使用ms Access 2010.我很难获得用于显示库存的查询,以显示我想要的信息.问题似乎是查询多次拉出相同的记录,使预留和已售产品的总和膨胀.
背景:我公司库存钢筋.我们提议将条形切成碎片.从库存方面来说,我们希望跟踪每个酒吧的长度,从进入仓库的那一刻起,到仓库中的时间(可能会被切成小块),直到整个酒吧出售并消失.
数据库:提出问题的查询,是咨询3个表;
(BatchNumber和BarNo组合,是主键)
销售
预订(卖方可以预留一些材料,当客户表示兴趣,但需要时间来决定)
我想把这三个表中的信息拉到一个列表中,显示:-Barstock.orginial length As Received - Sales.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
Run Code Online (Sandbox Code Playgroud)
我知道查询多次拉同一条记录,因为; - 当我删除GROUP BY术语时,我会得到几条完全相同的记录. - 但是,相应表中只有这些记录的一个实例.
我希望我已经能够正确解释自己,请问我是否需要详细说明.
感谢您抽出宝贵时间来看看我的问题!
!检查一些假设
从您的数据库架构,似乎:
Sales记录,对于给定的BatchNumber/BarNo(例如,我可以想像,多个客户可能已经买了同样的酒吧小节).Reservation了一个给定的记录BatchNumber/BarNo(例如,同一棒的多个部分,可以"保留")要检查这些表中是否确实有多条记录,请尝试以下操作:
SELECT CountOfDuplicates
FROM (SELECT COUNT(*) AS CountOfDuplicates
FROM Sales
GROUP BY BatchNumber & "," & BarNo)
WHERE CountOfDuplicates > 1
Run Code Online (Sandbox Code Playgroud)
如果查询返回一些记录,那么有重复项,这可能是您的查询返回错误值的原因.
现在,让你的查询工作的诀窍是真正考虑你想要显示的主要数据是什么,并从那开始:
所以很清楚,你的中心数据是库存中的柱状列表.
不要试图立即将所有内容都放到一个大型查询中,而是最好为每个目标创建简单查询,并确保在每种情况下都能获得正确的数据.
根据您的解释,每个单独的条记录在BarStock表中.
正如我在评论中所说,根据我的理解,所有交付的柱子在BarStock表格中都有一条记录,没有重复.因此,您应该测量库存的主要清单是BarStock表格:
SELECT BatchNumber,
BarNo,
OrgLength
FROM BarStock
Run Code Online (Sandbox Code Playgroud)
同样,这应该非常简单:我们只需要找出每BatchNumber/BarNo对售出的总长度:
SELECT BatchNumber,
BarNo,
Sum(QtySold) AS SumAvQtySold
FROM Sales
GROUP BY BatchNumber, BarNo
Run Code Online (Sandbox Code Playgroud)
与销售相同:
SELECT BatchNumber,
BarNo,
SUM(QtyReserved) AS Reserved
FROM Reservation
GROUP BY BatchNumber, BarNo
Run Code Online (Sandbox Code Playgroud)
现在,我们应该能够将前两个查询合并为一个.我不是想优化,只是为了使数据协同工作:
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)
Run Code Online (Sandbox Code Playgroud)
我们这样做是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)
Run Code Online (Sandbox Code Playgroud)
请注意Nz()对于连接右侧的项目的使用:如果没有Sales或Reservation给定BatchNumber/BarNo对的数据,则无论库存中的实际数量如何,for SumAvQtySold和的值Reserved都Null将呈现OnStock并呈现为Availablenull.不会是我们期望的结果.
使用Access中的查询设计器,您必须单独创建3个查询,然后将它们组合在一起.
请注意,查询设计在处理多个LEFT和RIGHT连接时不是很好,所以我不认为你可以一次性编写整个事情.
我相信你应该阅读@Remou在评论中给你的信息.
对我来说,这个数据库有一些不幸的设计选择:获取基本库存数据应该像SUM()保存库存记录的列一样简单.
通常,跟踪库存的一种简单方法是跟踪每个库存交易:
因此,如果您需要知道所有物品的库存情况,您需要做的就是:
SELECT BarID,
Sum(Quantity)
FROM StockTransaction
GROUP BY BarID
Run Code Online (Sandbox Code Playgroud)
在您的情况下,虽然BatchNumber/BarNo是您的自然键,但将它们保存在单独的Bar表中会有一些优点:
Bar.ID取回Bar.BatchNumber和Bar.BarNo任何你需要它.BarID在你的外键BarStock,Sales和Reservation表.它使连接变得更容易,而不必混淆复合键的复杂性.Access允许的东西不是很好的做法,例如表名和字段中的空格,最终使得可读性降低(至少因为你需要将它们保持在两者之间[]),与表示这些的VBA变量名不太一致字段,与其他数据库不兼容,除了表和字段名称的字母数字字符之外不接受任何其他内容(如果您希望稍后调整大小或将数据库与其他应用程序连接).
此外,通过坚持单一命名约定来帮助自己,并保持一致:
Part而不是表Parts,但它只是一个约定(有其自身的原因).Received不是Recieved.在调试为什么某些查询或VBA代码不起作用时,单独这个错误可能会花费你,只是因为某人犯了错字.ID列.通常,这将是一个自动增量,保证表中每条记录的唯一性.如果你保持这种惯例,那么外键变得容易猜测和阅读,你永远不必担心一些业务需求改变你可能突然发现自己与2相同的事实BatchNumbers,由于某种原因你现在无法理解. 关于数据库设计有很多争论,但是每个人都同意某些"规则",所以我的建议应该是努力: