J. *_*lor 8 join ms-access sorting date distinct
我正在使用 MS Access 2013 中的食品采购/发票系统,并尝试创建一个 SQL 查询,该查询将返回每个单独食品的最新购买价格。
我对 SQL 的理解是非常基本的,我尝试了以下(不正确的)查询,希望它只返回每个项目的一条记录(因为DISTINCT
运算符)并且它只会返回最近购买的(因为我做了ORDER BY [Invoice Date] DESC
)
SELECT DISTINCT ([Food items].Item),
[Food items].Item, [Food purchase data].[Price per unit], [Food purchase data].[Purchase unit], Invoices.[Invoice Date]
FROM Invoices
INNER JOIN ([Food items]
INNER JOIN [Food purchase data]
ON [Food items].ID = [Food purchase data].[Food item ID])
ON Invoices.ID = [Food purchase data].[Invoice ID]
ORDER BY Invoices.[Invoice Date] DESC;
Run Code Online (Sandbox Code Playgroud)
然而,上面的查询只是返回所有的食品购买(即 中每个记录的多条记录[Food items]
),结果按日期降序排序。有人可以向我解释我对DISTINCT
运营商的误解吗?也就是说,为什么它不只为 中的每个项目返回一条记录[Food items]
?
更重要的是 -考虑到上面显示的表格结构,对我来说,为每个单独的食品提取最新的食品购买数据的最简单方法是什么?我并不真正关心效率和简单性(我正在使用的数据库相当小 - 它甚至需要数年才能达到数万条记录的范围)。我更关心查询对于对 SQL 知之甚少的人是否可以理解。
更新: 所以我尝试了下面建议的两个答案,但它们都不起作用(它们只是抛出语法错误)。
根据以下建议并进一步阅读在线内容,我使用聚合函数max()
和GROUP BY
子句编写了以下新查询:
SELECT [Food purchase data].[Food item ID], [Food purchase data].[Price per unit], max(Invoices.[Invoice Date]) AS MostRecentInvoiceDate
FROM [Food purchase data], Invoices
GROUP BY [Food purchase data].[Food item ID], [Food purchase data].[Price per unit];
Run Code Online (Sandbox Code Playgroud)
但我仍然有同样的问题:也就是说,我仍然看到每种食品的结果不止一个。谁能解释为什么这个查询不仅返回每个食品的最近购买?
更新 2(已解决!):
下面的答案都没有完全解决,但基于对下面Vladimir 的答案的一些重大修改,我能够创建以下查询,这些查询似乎给出了正确的结果。
首先,我创建了这个视图并将其命名为“LatestInvoices”:
SELECT InvoicesMaxDate.ItemID, InvoicesMaxDate.MaxDate, InvoicesMaxDate.MaxID
FROM [Food purchase data], Invoices, (SELECT [Food purchase data].[Food item ID] AS ItemID, MAX(Invoices.[Invoice Date]) AS MaxDate, MAX(Invoices.[Invoice ID]) AS MaxID
FROM [Food purchase data], Invoices
WHERE Invoices.[Invoice ID] = [Food purchase data].[Invoice ID]
GROUP BY [Food purchase data].[Food item ID]
) AS InvoicesMaxDate
WHERE InvoicesMaxDate.MaxID = [Food purchase data].[Invoice ID] AND
InvoicesMaxDate.ItemID = [Food purchase data].[Food item ID] AND
InvoicesMaxDate.MaxDate = Invoices.[Invoice Date]
GROUP BY InvoicesMaxDate.ItemID, InvoicesMaxDate.MaxDate, InvoicesMaxDate.MaxID
Run Code Online (Sandbox Code Playgroud)
然后我写了另一个查询来拉入我需要的字段:
SELECT [Food items].ID AS FoodItemID, [Food items].Item AS FoodItem, [Food purchase data].[Price], [Food purchase data].[Price per unit], [Food purchase data].[Purchase unit], LatestInvoices.MaxDate as InvoiceDate
FROM [Food items], [Food purchase data], LatestInvoices
WHERE LatestInvoices.[MaxID] = [Food purchase data].[Invoice ID] AND
LatestInvoices.ItemID = [Food purchase data].[Food item ID] AND
LatestInvoices.ItemID = [Food items].ID
ORDER BY [Food items].Item;
Run Code Online (Sandbox Code Playgroud)
感谢所有花时间帮助我解决这个问题的人!
MS Access 相当有限。
我假设同一日期可能有多个发票。在这种情况下,我将选择 ID 最高的发票。
首先,我们会找到每个食品项目的最大发票日期。
SELECT
FPD1.[Food item ID] AS ItemID
,MAX(I1.[Invoice Date]) AS MaxDate
FROM
[Food purchase data] AS FPD1
INNER JOIN Invoices AS I1 ON I1.ID = FPD1.[Invoice ID]
GROUP BY
FPD1.[Food item ID]
Run Code Online (Sandbox Code Playgroud)
由于找到的最大日期可能有几张发票,我们将选择一张带有每个项目最大 ID 的发票
基于嵌套连接的MS Access 语法并使用文档中的此示例:
Run Code Online (Sandbox Code Playgroud)SELECT fields FROM table1 INNER JOIN ( table2 INNER JOIN ( table3 INNER JOIN tablex ON table3.field3 = tablex.fieldx ) ON table2.field2 = table3.field3 ) ON table1.field1 = table2.field2 ;
让我们试着把它放在一起:
SELECT
InvoicesMaxDate.ItemID
,InvoicesMaxDate.MaxDate
,MAX(I2.ID) AS MaxInvoiceID
FROM
(
SELECT
FPD1.[Food item ID] AS ItemID
,MAX(I1.[Invoice Date]) AS MaxDate
FROM
[Food purchase data] AS FPD1
INNER JOIN Invoices AS I1 ON I1.ID = FPD1.[Invoice ID]
GROUP BY
FPD1.[Food item ID]
) AS InvoicesMaxDate INNER JOIN
(
[Food purchase data] AS FPD2
INNER JOIN Invoices AS I2 ON I2.ID = FPD2.[Invoice ID]
) ON
InvoicesMaxDate.ItemID = FPD2.[Food item ID] AND
--- you may need to put extra "ON" here as well, not sure
InvoicesMaxDate.MaxDate = I2.[Invoice Date]
GROUP BY
InvoicesMaxDate.ItemID
,InvoicesMaxDate.MaxDate
Run Code Online (Sandbox Code Playgroud)
现在我们有该项目的最后一张发票的 ItemID 和 ID。将此连接到原始表以获取其他详细信息(列)。
SELECT
FI3.Item
,FI3.Item
,FPD3.[Price per unit]
,FPD3.[Purchase unit]
,I3.[Invoice Date]
FROM
(
SELECT
InvoicesMaxDate.ItemID
,InvoicesMaxDate.MaxDate
,MAX(I2.ID) AS MaxInvoiceID
FROM
(
SELECT
FPD1.[Food item ID] AS ItemID
,MAX(I1.[Invoice Date]) AS MaxDate
FROM
[Food purchase data] AS FPD1
INNER JOIN Invoices AS I1 ON I1.ID = FPD1.[Invoice ID]
GROUP BY
FPD1.[Food item ID]
) AS InvoicesMaxDate INNER JOIN
(
[Food purchase data] AS FPD2
INNER JOIN Invoices AS I2 ON I2.ID = FPD2.[Invoice ID]
) ON
InvoicesMaxDate.ItemID = FPD2.[Food item ID] AND
InvoicesMaxDate.MaxDate = I2.[Invoice Date]
GROUP BY
InvoicesMaxDate.ItemID
,InvoicesMaxDate.MaxDate
) AS LastInvoices INNER JOIN
(
[Food items] AS FI3 INNER JOIN
(
[Food purchase data] AS FPD3
INNER JOIN Invoices AS I3 ON I3.ID = FPD3.[Invoice ID]
) ON FI3.ID = FDP3.[Food item ID]
) ON
LastInvoices.MaxInvoiceID = I3.ID AND
LastInvoices.ItemID = FI3.ID
Run Code Online (Sandbox Code Playgroud)
在实践中,我会使用单个连接为第一个查询创建一个视图。然后我会创建第二个视图,将第一个视图与表连接起来,然后是第三个视图,依此类推,以避免嵌套连接或最小化它们。整体查询会更容易阅读。
根据您在问题中提出的最终解决方案进行编辑以阐明我的意思。
最后一次尝试传达我的信息。
这是你根据我上面的建议写的:
SELECT
InvoicesMaxDate.ItemID
,InvoicesMaxDate.MaxDate
,Invoices.[Invoice ID]
FROM [Food purchase data], Invoices,
(
SELECT
[Food purchase data].[Food item ID] AS ItemID
,MAX(Invoices.[Invoice Date]) AS MaxDate
FROM [Food purchase data], Invoices
WHERE Invoices.[Invoice ID] = [Food purchase data].[Invoice ID]
GROUP BY [Food purchase data].[Food item ID]
) AS InvoicesMaxDate
WHERE
Invoices.[Invoice ID] = [Food purchase data].[Invoice ID] AND
InvoicesMaxDate.ItemID = [Food purchase data].[Food item ID] AND
InvoicesMaxDate.MaxDate = Invoices.[Invoice Date]
GROUP BY InvoicesMaxDate.ItemID, InvoicesMaxDate.MaxDate, Invoices.[Invoice ID];
Run Code Online (Sandbox Code Playgroud)
这就是我的意思:
SELECT
InvoicesMaxDate.ItemID
,InvoicesMaxDate.MaxDate
,MAX(Invoices.[Invoice ID]) AS [Invoice ID]
FROM [Food purchase data], Invoices,
(
SELECT
[Food purchase data].[Food item ID] AS ItemID
,MAX(Invoices.[Invoice Date]) AS MaxDate
FROM [Food purchase data], Invoices
WHERE Invoices.[Invoice ID] = [Food purchase data].[Invoice ID]
GROUP BY [Food purchase data].[Food item ID]
) AS InvoicesMaxDate
WHERE
Invoices.[Invoice ID] = [Food purchase data].[Invoice ID] AND
InvoicesMaxDate.ItemID = [Food purchase data].[Food item ID] AND
InvoicesMaxDate.MaxDate = Invoices.[Invoice Date]
GROUP BY InvoicesMaxDate.ItemID, InvoicesMaxDate.MaxDate;
Run Code Online (Sandbox Code Playgroud)
你看得到差别吗?
每个的InvoicesMaxDate
返回 MAX 。如果有两张相同的 MAX 的发票,我们应该在其中选择一张发票。这是通过分组来完成的。这里应该没有分组,因为我们要选择具有最大 ID 的发票。Invoice Date
Food item ID
Food item ID
Invoice Date
InvoicesMaxDate.ItemID, InvoicesMaxDate.MaxDate
Invoices.[Invoice ID]
将此查询保存为LatestInvoices
视图后,它会在您正确编写时进一步使用(请注意,最终查询使用LatestInvoices.[Invoice ID]
and LatestInvoices.ItemID
,但不使用LatestInvoices.MaxDate
):
SELECT
[Food items].ID as FoodItemID
,[Food items].Item as FoodItem
,[Food purchase data].[Price]
,[Food purchase data].[Price per unit]
,[Food purchase data].[Purchase unit]
,Invoices.[Invoice Date]
FROM [Food items], [Food purchase data], Invoices, LatestInvoices
WHERE
Invoices.[Invoice ID] = [Food purchase data].[Invoice ID] AND
[Food items].ID = [Food purchase data].[Food item ID] AND
LatestInvoices.[Invoice ID] = Invoices.[Invoice ID] AND
LatestInvoices.ItemID = [Food items].ID
ORDER BY [Food items].Item
Run Code Online (Sandbox Code Playgroud)
至于为什么您在问题中的最后一个查询每个项目返回几行:
SELECT
[Food purchase data].[Food item ID]
, [Food purchase data].[Price per unit]
, max(Invoices.[Invoice Date]) AS MostRecentInvoiceDate
FROM [Food purchase data], Invoices
GROUP BY [Food purchase data].[Food item ID], [Food purchase data].[Price per unit];
Run Code Online (Sandbox Code Playgroud)
您在此处按[Food item ID]
和分组[Price per unit]
,因此您将获得与这两列的独特组合一样多的行。
以下查询将每个 返回一行[Food item ID]
。
SELECT
[Food purchase data].[Food item ID]
, max(Invoices.[Invoice Date]) AS MostRecentInvoiceDate
FROM [Food purchase data], Invoices
GROUP BY [Food purchase data].[Food item ID];
Run Code Online (Sandbox Code Playgroud)
附带说明,您确实应该使用显式INNER JOIN
而不是,
. 该语法已有 20 年历史。
SELECT
[Food purchase data].[Food item ID]
, max(Invoices.[Invoice Date]) AS MostRecentInvoiceDate
FROM
[Food purchase data]
INNER JOIN Invoices ON Invoices.ID = [Food purchase data].[Invoice ID]
GROUP BY [Food purchase data].[Food item ID];
Run Code Online (Sandbox Code Playgroud)