我有一张这样的桌子:
+----+---------+------------+
| id | price | date |
+----+---------+------------+
| 1 | 340 | 2018-09-02 |
| 2 | 325 | 2018-09-05 |
| 3 | 358 | 2018-09-08 |
+----+---------+------------+
我需要创建一个每天都有一行的视图。像这样:
+----+---------+------------+
| id | price | date |
+----+---------+------------+
| 1 | 340 | 2018-09-02 |
| 1 | 340 | 2018-09-03 |
| 1 | 340 | 2018-09-04 |
| 2 | 325 | 2018-09-05 |
| 2 | 325 | 2018-09-06 |
| 2 | 325 | 2018-09-07 |
| 3 | 358 | 2018-09-08 |
+----+---------+------------+
我可以使用带有循环(foreach
)的PHP并创建一个临时变量来保持以前的价格,直到有一个新日期为止。
但是我需要提出一个观点...所以我应该使用纯SQL来做到这一点。任何想法我该怎么做?
答案 0 :(得分:2)
您可以使用递归CTE在“间隙”中生成记录。为了避免最后一个日期之后的无限空白,请首先在源数据中获取最大日期,并确保不要在递归中绕过该日期。
我给您的桌子tbl
打电话了
with recursive cte as (
select id,
price,
date,
(select max(date) date from tbl) mx
from tbl
union all
select cte.id,
cte.price,
date_add(cte.date, interval 1 day),
cte.mx
from cte
left join tbl
on tbl.date = date_add(cte.date, interval 1 day)
where tbl.id is null
and cte.date <> cte.mx
)
select id,
price,
date
from cte
order by 3;
答案 1 :(得分:1)
由于您使用的是MariaDB,因此相当简单:
MariaDB [test]> SELECT '2019-01-01' + INTERVAL seq-1 DAY FROM seq_1_to_31;
+-----------------------------------+
| '2019-01-01' + INTERVAL seq-1 DAY |
+-----------------------------------+
| 2019-01-01 |
| 2019-01-02 |
| 2019-01-03 |
| 2019-01-04 |
| 2019-01-05 |
| 2019-01-06 |
(etc)
对此有一些变体,其中您生成大量的日期,但是随后使用WHERE砍切所需的内容。并将LEFT JOIN
与序列“派生表”的左侧一起使用。
在查询中使用类似上面的内容作为派生表。
答案 2 :(得分:0)
这是一种无需分析功能即可工作的方法。此答案使用日历表联接方法。下面的第一个CTE是其余查询所基于的基本表。我们使用相关子查询在CTE中找到比当前日期最近的日期更早,该日期的价格为非NULL
。这是找出日历表中那些未出现在原始数据集中的日期的id
和price
值的基础。
WITH cte AS (
SELECT cal.date, t.price, t.id
FROM
(
SELECT '2018-09-02' AS date UNION ALL
SELECT '2018-09-03' UNION ALL
SELECT '2018-09-04' UNION ALL
SELECT '2018-09-05' UNION ALL
SELECT '2018-09-06' UNION ALL
SELECT '2018-09-07' UNION ALL
SELECT '2018-09-08'
) cal
LEFT JOIN yourTable t
ON cal.date = t.date
),
cte2 AS (
SELECT
t1.date,
t1.price,
t1.id,
(SELECT MAX(t2.date) FROM cte t2
WHERE t2.date <= t1.date AND t2.price IS NOT NULL) AS nearest_date
FROM cte t1
)
SELECT
(SELECT t2.id FROM yourTable t2 WHERE t2.date = t1.nearest_date) id,
(SELECT t2.price FROM yourTable t2 WHERE t2.date = t1.nearest_date) price,
t1.date
FROM cte2 t1
ORDER BY
t1.date;
注意:要使此功能适用于8或更高版本的MySQL版本,您需要内联上述CTE。它将导致冗长的代码,但仍然可以使用。