如何编写SQL查询找出每年销售额持续增长的产品名称?
问题:找出每年销售额持续增长的产品名称
表结构与数据
产品表(Product)
列:PRODUCT_ID(产品ID)、PRODUCT_NAME(产品名称)
| PRODUCT_ID | PRODUCT_NAME |
|---|---|
| 100 | NOKIA |
| 200 | IPHONE |
| 300 | SAMSUNG |
| 400 | OPPO |
销售表(Sales)
列:SALE_ID(销售ID)、PRODUCT_ID(产品ID)、YEAR(年份)、QUANTITY(销量)、PRICE(单价)
| SALE_ID | PRODUCT_ID | YEAR | QUANTITY | PRICE |
|---|---|---|---|---|
| 1 | 100 | 2010 | 25 | 5000 |
| 2 | 100 | 2011 | 16 | 5000 |
| 3 | 100 | 2012 | 8 | 5000 |
| 4 | 200 | 2010 | 10 | 9000 |
| 5 | 200 | 2011 | 15 | 9000 |
| 6 | 200 | 2012 | 20 | 9000 |
| 7 | 300 | 2010 | 20 | 7000 |
| 8 | 300 | 2011 | 18 | 7000 |
| 9 | 300 | 2012 | 20 | 7000 |
| 10 | 400 | 2010 | 15 | 7000 |
| 11 | 400 | 2011 | 18 | 7000 |
| 12 | 400 | 2012 | 22 | 7000 |
| 13 | 400 | 2013 | 23 | 7000 |
说明:Quantity为每年售出的产品数量,Price为产品销售单价。
需求
编写SQL查询,找出每年销售额持续增长的产品名称。
预期输出
PRODUCT_NAME IPHONE OPPO
现有查询问题
你提供的SQL仅能处理单个销售额增长产品的场景,无法正确返回多个符合条件的产品。问题出在最后一步:通过max_val = (SELECT MAX(max_val) FROM cte3)只选取了增长次数最多的产品,但我们需要的是所有没有出现销售额下降或持平的产品,和增长次数多少无关。
原查询的逻辑缺陷:
LAG函数第三个参数设为当前销售额,导致首个年份的diff为0、val为0,这部分没问题;但后续通过SUM(val)统计增长次数,再取最大值的逻辑,会漏掉那些增长次数少但全程持续增长的产品(比如IPHONE有2次增长,OPPO有3次,原查询只会返回OPPO)。
正确解法
核心思路:对每个产品,检查其所有年份的销售额是否均严格大于前一年的销售额,即不存在任何一个年份的销售额≤前一年的情况。
实现SQL
WITH product_sales AS ( SELECT p.PRODUCT_NAME, s.PRODUCT_ID, s.YEAR, s.QUANTITY * s.PRICE AS total_sales, LAG(s.QUANTITY * s.PRICE) OVER (PARTITION BY s.PRODUCT_ID ORDER BY s.YEAR) AS prev_year_sales FROM Sales s JOIN Product p ON s.PRODUCT_ID = p.PRODUCT_ID ) SELECT DISTINCT PRODUCT_NAME FROM product_sales WHERE PRODUCT_ID NOT IN ( SELECT PRODUCT_ID FROM product_sales WHERE prev_year_sales IS NOT NULL AND total_sales <= prev_year_sales );
逻辑说明
- product_sales CTE:计算每个产品每年的总销售额,并通过
LAG获取前一年的销售额(首个年份的prev_year_sales为NULL)。 - 子查询:筛选出存在销售额下降或持平的产品ID。
- 主查询:排除上述产品ID,剩下的就是所有销售额持续增长的产品名称。
另一种更简洁的写法(使用COUNT和CASE判断):
WITH product_sales AS ( SELECT p.PRODUCT_NAME, s.PRODUCT_ID, s.QUANTITY * s.PRICE AS total_sales, LAG(s.QUANTITY * s.PRICE) OVER (PARTITION BY s.PRODUCT_ID ORDER BY s.YEAR) AS prev_year_sales FROM Sales s JOIN Product p ON s.PRODUCT_ID = p.PRODUCT_ID ) SELECT PRODUCT_NAME FROM product_sales GROUP BY PRODUCT_ID, PRODUCT_NAME HAVING COUNT(CASE WHEN prev_year_sales IS NOT NULL AND total_sales <= prev_year_sales THEN 1 END) = 0;
这种写法通过分组后统计“销售额未增长”的次数,次数为0的产品即为符合条件的产品。
内容的提问来源于stack exchange,提问作者Rohan Srivastwa
相关产品推荐
相关产品推荐

