订阅更新

平均售价:按销售日期匹配当时的价格

SQL 实战 123 题 · 第 84 题 简单 约 2 分钟读完

LeetCode 1251 · 区间关联(日期落在价格有效期内)、加权平均

本文目录
  1. 面试怎么回答
  2. 题意
  3. 表结构
  4. 思路
  5. 参考解法
  6. 易错点

面试怎么回答

销量表和价格表按 product_id 关联,并且 purchase_date BETWEEN start_date AND end_date,确保用的是销售当天的价格;然后按产品 SUM(price * units) / SUM(units) 求加权平均。这种「事实按日期落到维度有效区间」的关联,和数仓里拉链表的用法完全一样。

先把这段讲顺;面试官追问时,再展开下面的原理和细节。

详细讲解

题意

价格表记录每个产品在一段时间内的单价(时间段不重叠),销量表记录每次销售的日期和数量。求每个产品的平均售价 = 总销售额 / 总销量,保留两位小数。

表结构

  • Prices:product_id、start_date、end_date、price;(product_id, start_date, end_date) 为主键
  • UnitsSold:product_id、purchase_date、units;可能有重复行

思路

每笔销售要用销售当天生效的价格,所以关联条件除了产品 ID 相同,还要「销售日期在价格的起止日期之间」,这是一种区间关联(和拉链表按日期关联维度是同一回事)。关联后按产品算 SUM(price * units) / SUM(units),这是按销量加权的平均价,不是价格的简单平均。

参考解法

SELECT
    product_id,
    Round(SUM(sales) / SUM(units), 2) AS average_price
FROM (
    SELECT
        Prices.product_id AS product_id,
        Prices.price * UnitsSold.units AS sales,
        UnitsSold.units AS units
    FROM Prices 
    JOIN UnitsSold ON Prices.product_id = UnitsSold.product_id
    WHERE UnitsSold.purchase_date BETWEEN Prices.start_date AND Prices.end_date
) T
GROUP BY product_id

易错点

  • 用 AVG(price) 得到的是价格的简单平均,没有按销量加权。
  • 只按产品 ID 关联不加日期条件,一笔销售会匹配到所有价格段。
  • 如果要求没卖出的产品显示 0,需要以价格表为主表 LEFT JOIN,并处理除以 0。
刷题进度保存在当前浏览器