有一个表(mileage_event)显示所有汽车的里程。 包含以下列: 创建时间 - 日期, car_id - 汽车 ID, car_mileage - 汽车的里程
值得考虑的是,并非所有日子都有数据。 例如:
汽车 ID | 创建于 | 汽车_里程 |
---|---|---|
d016e61c5326-f246894a | 2023-05-22 | 100000 |
d016e61c5326-f246894a | 2023-05-26 | 105000 |
d016e61c5326-f246894a | 2023-05-27 | 110000 |
如您所见,在 2023-05-22 和 2023-05-26 之间(即缺席 3 天)这辆车没有行。说明这几天车子没有开过。
我想要什么:生成缺失的天数并为其添加最接近的里程值。
(注:Exasol数据库)
结果:
汽车 ID | 创建于 | 汽车_里程 |
---|---|---|
d016e61c5326-f246894a | 2023-05-22 | 100000 |
d016e61c5326-f246894a | 2023-05-23 | 100000 |
d016e61c5326-f246894a | 2023-05-24 | 100000 |
d016e61c5326-f246894a | 2023-05-25 | 100000 |
d016e61c5326-f246894a | 2023-05-26 | 105000 |
d016e61c5326-f246894a | 2023-05-27 | 110000 |
提前致谢!
啊,总是很高兴看到有人问一个合理的问题并且人们评论“你应该用谷歌搜索它”。
您可以通过利用公共表表达式 (CTE)、窗口函数以及连接一系列日期来实现此目的。总体策略是:
生成一系列涵盖您感兴趣范围的日期。 对于每个 car_id,使用 LEFT JOIN 将此日期系列与您现有的里程数据结合起来。 使用窗口函数来填充缺失的里程数据。 我会这样做:
-- Create a CTE with a series of dates. Adjust the start and end dates as needed.
WITH date_series AS (
SELECT CAST('2023-05-22' AS DATE) + ROW_NUMBER() OVER() - 1 AS created_at
FROM (SELECT 1 FROM DUAL CONNECT BY LEVEL <= 30) -- Generating 30 days, adjust this number as needed
),
-- LEFT JOIN the date series with your mileage data and use LAG() to fill in gaps.
combined AS (
SELECT
m.car_id,
d.created_at,
COALESCE(m.car_mileage,
LAG(m.car_mileage, 1) OVER (PARTITION BY m.car_id ORDER BY d.created_at)) AS car_mileage
FROM date_series d
LEFT JOIN mileage_event m ON d.created_at = m.created_at
)
-- Get result
SELECT * FROM combined WHERE car_id IS NOT NULL ORDER BY car_id, created_at
我希望能够回答您的问题并且有效。如果您需要更多帮助,请告诉我。
我不知道 Exasol 语法。在 SQL 中,您通常会使用递归查询来填补一系列空白。您要做的就是获取每一行,查看其下一行(如果有),这样您就知道要添加多少天。然后根据需要添加任意多的行。
以下是Oracle语法。在 Exasol 中,您可能需要添加关键字
RECURSIVE
或将间隔更改为 interval '1 days'
等。您可能可以在文档中找到它。
with cte (car_id, created_at, car_mileage, next_created_at) as
(
select
car_id, created_at, car_mileage,
lead(created_at) over (partition by car_id order by created_at) as next_created_at
from mytable
union all
select car_id, created_at + interval '1' day, car_mileage, next_created_at
from cte
where created_at + interval '1' day < next_created_at
)
select car_id, created_at, car_mileage
from cte
order by car_id, created_at;