LeetCode mysql 刷题六:指定日期的产品价格——3种方法处理未查询到日期
题目
题目链接:指定日期的产品价格
编写一个解决方案,找出在 2019-08-16 时全部产品的价格,假设所有产品在修改前的价格都是 10 。
以 任意顺序 返回结果表。
结果格式如下例所示。
输入:
Products 表:
+------------+-----------+-------------+
| product_id | new_price | change_date |
+------------+-----------+-------------+
| 1 | 20 | 2019-08-14 |
| 2 | 50 | 2019-08-14 |
| 1 | 30 | 2019-08-15 |
| 1 | 35 | 2019-08-16 |
| 2 | 65 | 2019-08-17 |
| 3 | 20 | 2019-08-18 |
+------------+-----------+-------------+
(product_id, change_date) 是此表的主键(具有唯一值的列组合)。
这张表的每一行分别记录了 某产品 在某个日期 更改后 的新价格。
输出:
+------------+-------+
| product_id | price |
+------------+-------+
| 2 | 50 |
| 1 | 35 |
| 3 | 10 |
+------------+-------+
Create table If Not Exists Products (product_id int, new_price int, change_date date);
Truncate table Products;
insert into Products (product_id, new_price, change_date) values ('1', '20', '2019-08-14');
insert into Products (product_id, new_price, change_date) values ('2', '50', '2019-08-14');
insert into Products (product_id, new_price, change_date) values ('1', '30', '2019-08-15');
insert into Products (product_id, new_price, change_date) values ('1', '35', '2019-08-16');
insert into Products (product_id, new_price, change_date) values ('2', '65', '2019-08-17');
insert into Products (product_id, new_price, change_date) values ('3', '20', '2019-08-18');
解析
这题考察的点是如何查出 product_id 为 3 的数据,因为这个产品在 2019-08-16 之前没有修改过价格
方法一
思路:
查询出在 2019-08-16 之前的最新修改过价格的 product_id,
如果修改过价,那么 new_price 是有值的
没有修改过价格,那么 new_price 是 null,给它赋值为 10
+------------+-------------+
| product_id | new_price |
+------------+-------------+
| 1 | 35 |
| 2 | 50 |
| 3 | NULL |
+------------+-------------+
步骤:
- 按照
product_id,查询出2019-08-16日期之前的最新修改过价格的产品,注意:这里查询不出价格 - 使用子查询,根据
product_id和change_date查询出product_id和new_price,作为临时表tmp2 - 查询出所有产品的
product_id,作为临时表tmp1SELECT product_id FROM Products GROUP BY product_idSELECT DISTINCT product_id FROM Products
- 左连查询,将
tmp1和tmp2左连,连接条件是product_id- 使用
if或者ifnull判断new_price是否为空,如果为空,则使用10作为价格
- 使用
SELECT
product_id, IF(new_price, new_price, 10) price
FROM (
SELECT product_id FROM Products GROUP BY product_id
) tmp1
LEFT JOIN (
SELECT product_id, new_price FROM Products WHERE ( product_id, change_date )
IN ( SELECT product_id, max(change_date) FROM Products WHERE DATE ( change_date ) <= DATE ( "2019-08-16" ) GROUP BY product_id )
) tmp2 USING ( product_id )
方法二
方法二的思路正好和方法一是相反的
思路:
查询出每个产品在 2019-08-16 之前,最后修改价格的日期,在左连 Products 表,那么 product_id 为 3 的产品就没有价格
+------------+-------------+
| product_id | change_date |
+------------+-------------+
| 1 | 2019-08-16 |
| 2 | 2019-08-14 |
| 3 | NULL |
+------------+-------------+
步骤:
- 按照
product_id分组,查询出2019-08-16之前,最后修改价格的日期,作为临时表tmp - 将
tmp和Products左连,连接条件是product_id和change_date- 使用
if或者ifnull判断new_price是否为空,如果为空,则使用10作为价格
- 使用
WITH tmp AS (
SELECT
product_id, MAX(IF(DATE ( change_date ) <= DATE ( "2019-08-16" ), change_date, NULL)) change_date
FROM Products GROUP BY product_id
)
SELECT
product_id, IF(new_price, new_price, 10) price
FROM tmp LEFT JOIN Products USING(product_id, change_date)
方法三
思路:
使用窗口函数,将每个产品按照修改日期进行排序
步骤:
- 查询出在
2019-08-16日期前修改过价格的记录,将大于2019-08-16的日期设置为null,作为临时表tmp - 使用窗口函数,按照
product_id分组,按照change_date降序排序,作为临时表tmp2 - 查询出
tmp2,筛选出rk = 1的product_id和new_price- 使用
if或者ifnull判断new_price是否为空,如果为空,则使用10作为价格 - 使用
distinct去重,可能会有某个产品某天修改多次的记录
- 使用
SELECT
DISTINCT product_id, IF(change_date, new_price, 10) price
FROM (
SELECT
*, RANK() OVER(PARTITION BY product_id ORDER BY change_date DESC) AS rk
FROM (
SELECT product_id, new_price, IF(DATE( change_date ) > DATE( "2019-08-16" ), NULL, change_date) change_date FROM Products
) tmp
) tmp2 WHERE rk = 1
相关联的题目
往期 MySQL 题目
转载自:https://juejin.cn/post/7282696271865085964