我有一个这样的表:
CREATE TABLE my_data (label text, value integer, date date);
INSERT INTO my_data (label, value, date) VALUES
('AAA', 10, '2014-06-01'),
('AAA', 30, '2014-09-01'),
('AAA', 40, '2014-10-01'),
('AAA', 50, '2015-02-01'),
('BBB', 20, '2014-11-01'),
('BBB', 10, '2015-02-01'),
('BBB', 70, '2015-04-01');
Run Code Online (Sandbox Code Playgroud)
我需要以这种方式填写缺失的日期(想象一个时间序列):
label | value | date
------+-------+------------
AAA | 10 | 2014-06-01
AAA | 10 | 2014-07-01
AAA | 10 | 2014-08-01
AAA | 30 | 2014-09-01
AAA | 40 | 2014-10-01
AAA | 40 | 2014-11-01
AAA | 40 | 2014-12-01
AAA | 40 | 2015-01-01
AAA | 50 | 2015-02-01
AAA | 50 | 2015-03-01
AAA | 50 | 2015-04-01
BBB | 20 | 2014-11-01
BBB | 20 | 2014-12-01
BBB | 20 | 2015-01-01
BBB | 10 | 2015-02-01
BBB | 10 | 2015-03-01
BBB | 70 | 2015-04-01
Run Code Online (Sandbox Code Playgroud)
其中时间范围从“2014-06-01”到“2015-04-01”。到目前为止我所做的是:
WITH
md AS
(
SELECT *, LEAD(date) OVER (PARTITION BY label ORDER BY date) AS next_date FROM my_data
),
calendar AS
(
select date::date from generate_series('2014-06-01'::date, '2015-04-01'::date, '1 month'::interval) date
)
SELECT m.label, m.value, c.date
FROM calendar c
JOIN md m
ON c.date BETWEEN m.date AND (m.next_date - interval '1 month') order by label, date;
label | value | date
-------+-------+------------
AAA | 10 | 2014-06-01
AAA | 10 | 2014-07-01
AAA | 10 | 2014-08-01
AAA | 30 | 2014-09-01
AAA | 40 | 2014-10-01
AAA | 40 | 2014-11-01
AAA | 40 | 2014-12-01
AAA | 40 | 2015-01-01
BBB | 20 | 2014-11-01
BBB | 20 | 2014-12-01
BBB | 20 | 2015-01-01
BBB | 10 | 2015-02-01
BBB | 10 | 2015-03-01
(13 rows)
Run Code Online (Sandbox Code Playgroud)
查询的返回值并未填满整个时间范围(直到 2015 年 4 月)。我怎样才能使查询以这种方式工作?
更新
我想我已经修复了它:
WITH
md AS
(
SELECT *, LEAD(date) OVER (PARTITION BY label ORDER BY date) AS next_date FROM my_data
),
calendar AS
(
select date::date from generate_series('2014-06-01'::date, '2015-04-01'::date, '1 month'::interval) date
)
SELECT m.label, m.value, c.date
FROM calendar c
JOIN md m
ON c.date BETWEEN m.date AND
(CASE WHEN m.next_date IS NULL THEN date '2015-04-01' ELSE m.next_date - interval '1 month' END) order by label, date;
Run Code Online (Sandbox Code Playgroud)
首先,它按标签生成一系列日期,然后您可以使用横向连接:
Run Code Online (Sandbox Code Playgroud)with a as ( select label, generate_series(min(date), '2015-04-01'::date, interval '1 month') dt from my_data group by label ) select label, t1.value, dt from a left join lateral (select t1.value from my_data t1 where t1.label = a.label and t1.date <= a.dt order by label, date desc limit 1) t1 on true order by label, dt
或子查询:
Run Code Online (Sandbox Code Playgroud)with a as ( select label, generate_series(min(date), '2015-04-01'::date, interval '1 month') dt from my_data group by label ) select label, (select t1.value from my_data t1 where t1.label = a.label and t1.date <= a.dt order by label, date desc limit 1), dt from a order by label, dt
标签| 价值| dt :---- | ----: | :---------------------- AAA | 10 | 10 2014-06-01 00:00:00+01 AAA | 10 | 10 2014-07-01 00:00:00+01 AAA | 10 | 10 2014-08-01 00:00:00+01 AAA | 30| 2014-09-01 00:00:00+01 AAA | 40 | 40 2014-10-01 00:00:00+01 AAA | 40 | 40 2014-11-01 00:00:00+00 AAA | 40 | 40 2014-12-01 00:00:00+00 AAA | 40 | 40 2015-01-01 00:00:00+00 AAA | 50 | 50 2015-02-01 00:00:00+00 AAA | 50 | 50 2015-03-01 00:00:00+00 AAA | 50 | 50 2015-04-01 00:00:00+01 BBB | 20 | 2014-11-01 00:00:00+00 BBB | 20 | 2014-12-01 00:00:00+00 BBB | 20 | 2015-01-01 00:00:00+00 BBB | 10 | 10 2015-02-01 00:00:00+00 BBB | 10 | 10 2015-03-01 00:00:00+00 BBB | 70 | 70 2015-04-01 00:00:00+01
dbfiddle在这里