如何用SQL找出每月每日最便宜商品的平均价格?
2024-08-02 16:21:39
如何用SQL找出每月每日最便宜商品的平均价格?
你是否曾为了寻找最划算的购物时机而烦恼?想象一下,如果能从海量销售数据中,精准定位到每月每日最便宜商品的平均价格,就能轻松掌握最佳购物窗口,省钱又省心!
本文将以一个实际案例出发,带你一步步使用 SQL 解锁这个隐藏技能。
假设我们拥有一份包含商品名称、商店名称、销售日期、销售价格等信息的超市销售数据表(Grocery_Data
)。我们的目标是找出每种商品在一年中哪个月份、哪一天的平均售价最低。
你可能尝试了一些 SQL 语句,却发现结果不尽如人意。别担心,让我们先分析一些常见的错误,然后提供最佳解决方案。
错误尝试分析
陷阱一:
SELECT Grocery_Item, Store_Name, MONTH(Sales_Date) AS Month, Sales_Day, Sales_Price
FROM Grocery_Data
WHERE Sales_Price < (SELECT AVG(Sales_Price) FROM Grocery_Data)
ORDER BY Grocery_Item, Sales_Price;
这段代码的思路是先计算所有商品的平均售价,再筛选出价格低于平均售价的记录。问题在于,子查询 (SELECT AVG(Sales_Price) FROM Grocery_Data)
计算的是所有商品的总平均售价 ,而不是针对每种商品、每个月份、每一天计算的平均售价。
陷阱二:
SELECT Grocery_Item, MONTH(Sales_Date) AS Month, Sales_Date,ROUND(AVG(DISTINCT Sales_Price), 2) AS Avg_Sales_Price
FROM Grocery_Data
GROUP BY Grocery_Item, Month, Sales_Date
HAVING AVG(Sales_Price) < (SELECT MIN(Avg_Sales_Price) FROM (SELECT Grocery_Item, AVG(Sales_Price) AS Avg_Sales_Price FROM Grocery_Data GROUP BY Grocery_Item) AS Subquery)
ORDER BY Avg_Sales_Price;
这段代码尝试先计算每种商品在每个月份、每一天的平均售价,再筛选出平均售价低于该商品所有平均售价最小值的记录。然而,HAVING
子句中的子查询语法存在错误,导致无法正确执行。
陷阱三:
SELECT Store_Name, Grocery_Item, Month, Sales_Day, AVG_Sales_Price
FROM (
SELECT Store_Name, Grocery_Item, MONTH(Sales_Date) AS Month, Sales_Day,
ROUND(AVG(Sales_Price), 2) AS AVG_Sales_Price,
ROW_NUMBER() OVER (PARTITION BY Grocery_Item ORDER BY AVG(Sales_Price)) AS rank
FROM Grocery_Data
GROUP BY Grocery_Item, Month, Sales_Day
) ranked_data
WHERE rank = 1;
这段代码的思路是使用窗口函数 ROW_NUMBER()
对每种商品在每个月份、每一天的平均售价进行排名,并筛选出排名第一的记录。这个方法虽然接近目标,但它只能找到每个月最低平均售价的一天 ,而不是所有日期中平均售价最低的一天。
最佳解决方案
为了找到每种商品每月每日最便宜的平均价格,我们需要结合分组、排序和子查询等技巧。以下SQL语句可以实现这个目标:
WITH DailyAveragePrices AS (
SELECT
Grocery_Item,
MONTH(Sales_Date) AS Month,
DAY(Sales_Date) AS Day,
AVG(Sales_Price) AS AvgPrice
FROM Grocery_Data
GROUP BY
Grocery_Item,
MONTH(Sales_Date),
DAY(Sales_Date)
),
RankedPrices AS (
SELECT
Grocery_Item,
Month,
Day,
AvgPrice,
ROW_NUMBER() OVER (PARTITION BY Grocery_Item, Month ORDER BY AvgPrice ASC) AS rn
FROM DailyAveragePrices
)
SELECT
Grocery_Item,
Month,
Day,
AvgPrice
FROM RankedPrices
WHERE rn = 1
ORDER BY
Grocery_Item,
Month,
Day;
代码解析
- 创建
DailyAveragePrices
CTE: 首先,我们创建一个名为DailyAveragePrices
的公用表表达式 (CTE),用于计算每种商品在每个月份、每一天的平均售价。 - 创建
RankedPrices
CTE: 接着,我们创建另一个名为RankedPrices
的 CTE,使用窗口函数ROW_NUMBER()
对每种商品在每个月份的平均售价进行排名,并按照价格升序排列。 - 最终查询: 最后,我们从
RankedPrices
CTE 中选择排名第一的记录,即平均售价最低的记录,并将结果按商品、月份和日期排序。
通过这段 SQL 语句,我们可以直接从数据库中获取每种商品在一年中哪个月份、哪一天的平均售价最低,无需再进行繁琐的数据导出和整理。
常见问题解答
问题一: 为什么使用 CTE 而不是直接嵌套子查询?
解答: 使用 CTE 可以使代码更易读、易理解,尤其是在处理复杂的查询逻辑时。CTE 可以将复杂的查询分解成多个逻辑步骤,使代码更清晰易懂。
问题二: ROW_NUMBER()
函数的作用是什么?
解答: ROW_NUMBER()
函数是一个窗口函数,它可以为查询结果集中的每一行分配一个唯一的行号。在本例中,我们使用 ROW_NUMBER()
函数对每种商品在每个月份的平均售价进行排名。
问题三: 如何修改代码以查找每月最便宜的平均售价,而不考虑具体日期?
解答: 只需修改 RankedPrices
CTE 中的 PARTITION BY
子句,将其改为 PARTITION BY Grocery_Item, Month
,然后将最终查询中的 Day
字段移除即可。
问题四: 如何将结果保存到新的数据表中?
解答: 可以使用 CREATE TABLE AS
语句将查询结果保存到新的数据表中。例如:
CREATE TABLE CheapestPrices AS
-- 将上面的最终查询语句粘贴到这里
;
问题五: 如何根据不同的数据库系统调整代码?
解答: 虽然本文使用的 SQL 语法适用于大多数主流数据库系统,但部分数据库系统可能存在语法差异。建议查阅相关数据库系统的文档以获取准确的语法信息。
希望本文能帮助你轻松掌握使用 SQL 查找每月每日最便宜商品的平均价格的方法!