我有两个表,一个提到事件的开始和结束时间以及相应的值,另一个表记录每天午夜的值.

CREATE TABLE table1 (
    id integer,
    date_strt timestamp,
    date_end timestamp,
    strt_unit integer,
    end_unit integer
);

INSERT INTO table1 (id, date_strt, date_end,strt_unit,end_unit)
VALUES
    (1, '2023-10-27 12:00:00','2023-10-31 12:00:00', 5,72),
    (2, '2023-10-30 12:15:00','2023-11-02 00:00:00', 78,90);
    
    
CREATE TABLE table2 (
    id integer,
    dates timestamp,
    unit integer
);

INSERT INTO table2 (id, dates, unit)
VALUES
    (1, '2023-10-28 00:00:00', 55),
    (1, '2023-10-29 00:00:00', 60),
    (1, '2023-10-30 00:00:00', 65),
    (1, '2023-10-31 00:00:00', 70),
    (2, '2023-10-30 00:00:00', 75),
    (2, '2023-10-31 00:00:00', 80),
    (2, '2023-11-01 00:00:00', 85),
    (2, '2023-11-02 00:00:00', 90);

我想获得这样的数据集,其中我使用表2中可用的日期获得从表1中提到的开始日期到结束日期在午夜00:00:00小时的每一天的数据差异.

id start_time          start_value    end_time            end_value
1, '2023-10-27 12:00:00', 5,      '2023-10-28 00:00:00', 55
1, '2023-10-28 00:00:00', 55,     '2023-10-29 00:00:00', 60
1, '2023-10-29 00:00:00', 60,     '2023-10-30 00:00:00', 65
1, '2023-10-30 00:00:00', 65,     '2023-10-31 00:00:00', 70
1, '2023-10-31 00:00:00', 70,     '2023-10-31 12:00:00', 72
2, '2023-10-30 12:15:00', 78,     '2023-10-31 00:00:00', 80    
2, '2023-10-31 00:00:00', 80,     '2023-11-01 00:00:00', 85
2, '2023-11-01 00:00:00', 85,     '2023-11-02 00:00:00', 90

我计划使用1天作为间隔来生成开始日期和结束日期之间的日期序列,但无法生成适当的日期,因此无法在其中进一步使用领先或滞后. 我已经加了fiddle link.

推荐答案

下面是如何使用窗口函数LAG()LEAD()来执行此操作:

with cte as (
  select t1.*, CASE WHEN start_time=date_strt THEN start_time ELSE date(start_time) END as start_time,
               lead(date(start_time), 1, date_end) over (partition by id order by start_time) as end_time
  from table1 t1
  cross join generate_series
        ( date_strt, date_end, '1 day'::interval) start_time
),
cte2 as (
  select c.id, c.start_time, c.strt_unit, 
         c.end_time, case when c.end_time = date_end then end_unit else unit end as end_value
  from cte c
  inner join table2 t on c.id = t.id and DATE(t.dates) = DATE(c.end_time)
)
select id, start_time,
       lag(end_value, 1, strt_unit) over (partition by id order by start_time) as start_value,
       end_time, end_value
from cte2;

结果:

id  start_time          start_value end_time            end_value
1   2023-10-27 12:00:00 5           2023-10-28 00:00:00 55
1   2023-10-28 00:00:00 55          2023-10-29 00:00:00 60
1   2023-10-29 00:00:00 60          2023-10-30 00:00:00 65
1   2023-10-30 00:00:00 65          2023-10-31 00:00:00 70
1   2023-10-31 00:00:00 70          2023-10-31 12:00:00 72
2   2023-10-30 12:15:00 78          2023-10-31 00:00:00 80
2   2023-10-31 00:00:00 80          2023-11-01 00:00:00 85
2   2023-11-01 00:00:00 85          2023-11-02 00:00:00 90

解释:

  • 第一个用于使用generate_series生成两个日期之间的范围的CTE

  • 第二个CTE用于将数据与第二个表链接,以获得每个范围的end_value.

  • 第三个CTE用于获得每个范围的start_value.

Demo here

Sql相关问答推荐

在SQL中向每个子字节组添加字节行

如何将资源密集型自连接转换为更快的查询?

查询多个表并返回合并在联合列上的所有表中的所有行

出现5次后,将所有正斜杠替换为连字符

基于前面行的值:当x&>2时重复1,当连续3行x=0时则重复0

用于匹配红旗和绿旗的SQL查询

基于多列比较连接两个表

正在编写查询.我需要将订阅的时间段分为第一个订阅中包含的另一个订阅之前和之后的时间段

数组列的postgres更新查询

Pgsql-返回包含多行数据的行

从类似JSON的字符串列创建新列

Snowflake 中的分层数据

如何在android房间中进行多个加入

将 json 列键映射到第二个表中的匹配列值

group by 并根据同表中其他列的某些条件获取 group by 中的某一列值

SQL的左连接在多对多关系情况下使用

在给定的日期范围内填写缺失的日期

我需要遍历权重值表并确定每个权重是否有效

以 15 分钟为间隔的使用情况SQL 查询

SQL中所有先前日期的累计总和