SQL实现时间序列错位还原案列

目录
  • 一、需求描述
  • 二、思路概述
    • 1 需求延展
    • 2 思路概述
  • 三、SQL代码

一、需求描述

1 原表T1某条记录(记做r1,相邻下一条为r2)的下一行记录的STARTDATE小于上一行ENDDATE,针对这样的记录做转换即:

r1STARTDATE保持不变,ENDDATE为r1STARTDATE-1

r2STARTDATE为r1的ENDDATEENDDATE为r1ENDDATE

2 如果原表T1不存在相邻行“时间重叠”(即为1的定义)时保持原有数据不变。

 # 文本版
#T1
seq id  startdate   enddate     num
1 1 2021-04-20 2021-05-03 200
2 1 2021-05-01 2021-05-24 100
3 1 2021-05-18 2021-05-31 69
4 1 2021-05-20 2021-07-31 34
5 1 2021-08-05 2021-08-25 45
6 1 2021-08-15 2021-09-25 65

#输出结果
ID STARTDATE    ENDDATE     NUM
1  2021-04-20 2021-04-30 200
1  2021-05-01 2021-05-02 300
1  2021-05-03 2021-05-17 100
1  2021-05-18 2021-05-19 169
1  2021-05-20 2021-05-23 203
1  2021-05-24 2021-05-30 103
1  2021-05-31 2021-07-30 34
1  2021-08-05 2021-08-14 45
1  2021-08-15 2021-08-25 110
1  2021-08-26 2021-09-25 65

二、思路概述

1 需求延展

SEQ     ID      STARTDATE       ENDDATE         NUM
1 1 2021-04-20 2021-05-03 200
2 1 2021-05-01 2021-05-24 100
3 1 2021-05-18 2021-05-31 69
4 1 2021-05-20 2021-07-31 34

这里第4条记录同时叠加在第2和3条记录里。

2 思路概述

1) T0 通过上下行函数生成的时间序列

id      new_DATE        nextSTARTDATE   preEndDATE     rn
1 2021-05-24          2021-05-03 1
1 2021-05-03 2021-05-24 2021-05-01 2
1 2021-05-01 2021-05-03 2021-04-20 3
1 2021-04-20 2021-05-01          4

2) last 取出T0里的最后一条记录,为后面的矫正做准备。

new_Date        preENDDATE      id
2021-05-24 2021-05-03 1

3) normal 取出原始数据里不会出现时间叠加的记录,为后面的矫正做准备。
当前演示数据无记录,代码加注释可浮现。

4)T_Serial 统一定义STARTDATE、ENDDATE,首次修正T0。

id      STARTDATE       ENDDATE
1 2021-04-20 2021-04-30
1 2021-05-01 2021-05-03
1 2021-05-04 2021-05-24

 5) T2 对时间没有重叠的记录进行修正(删除T0对应值,更新对应ENDDATE)。
当前示例结果集为空,即无需要修正。

6) T2关联T1(原始表),汇总后取得最终值

STARTDATE   ENDDATE     NUM
2021-04-20 2021-04-30 200
2021-05-01 2021-05-03 300
2021-05-04 2021-05-24 100

三、SQL代码

当前演示版本是Mysql 8.0.23,支持CTE、窗口函数的SQL ServerOracle需要修改Order byADDDATE处语法。
Step0 创建表并初始化数据

DROP TABLE IF EXISTS test_ShenLiang2025;
CREATE TABLE test_ShenLiang2025 (
  seq int DEFAULT NULL,
  id int DEFAULT NULL,
  STARTDATE date DEFAULT NULL,
  ENDDATE date DEFAULT NULL,
  NUM int DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO test_ShenLiang2025 VALUES ('1', '1', '2021-04-20', '2021-05-03', '200');
INSERT INTO test_ShenLiang2025 VALUES ('2', '1', '2021-05-01', '2021-05-24', '100');
INSERT INTO test_ShenLiang2025 VALUES ('3', '1', '2021-05-18', '2021-05-31', '69');
INSERT INTO test_ShenLiang2025 VALUES ('4', '1', '2021-05-20', '2021-07-31', '34');
INSERT INTO test_ShenLiang2025 VALUES ('5', '1', '2021-08-05', '2021-08-25', '45');
INSERT INTO test_ShenLiang2025 VALUES ('6', '1', '2021-08-15', '2021-09-25', '65');

Step1 构建临时结果集以生成时间序列。

WITH T0 AS(
SELECT id,
   new_DATE,
   LEAD(NEW_DATE,1) OVER (PARTITION BY ID ORDER BY NEW_DATE ) nextSTARTDATE,
   LAG(NEW_DATE,1) OVER (PARTITION BY ID ORDER BY NEW_DATE ) preENDDATE,
   ROW_NUMBER()OVER(PARTITION BY ID ORDER BY new_DATE DESC) rn
   FROM
  (
  SELECT DISTINCT ID,STARTDATE new_DATE  FROM test_ShenLiang2025
   WHERE seq in (1,2) -- 可加注释验证,当前仅取原表里2条记录
  UNION
  SELECT DISTINCT ID,ENDDATE new_DATE FROM test_ShenLiang2025
   WHERE seq in (1,2) -- 可加注释验证,当前仅取原表里2条记录
      ORDER BY new_DATE
  )A
),last AS
( SELECT new_DATE,preENDDATE,id
FROM T0
WHERE nextSTARTDATE IS NULL
),normal AS
(
 SELECT * FROM
 (
 SELECT id,
    ENDDATE,
    LEAD(STARTDATE,1) OVER (PARTITION BY ID ORDER BY ENDDATE ) nextSTARTDATE,
    LAG(ENDDATE,1) OVER (PARTITION BY ID ORDER BY ENDDATE ) preENDDATE
    FROM test_ShenLiang2025
 )A
 WHERE ENDDATE > preENDDATE AND ENDDATE < nextSTARTDATE
),T_Serial AS (

SELECT ID,ADDDATE(preENDDATE, INTERVAL 1 DAY ) STARTDATE,
new_DATE ENDDATE
FROM last 

UNION

SELECT bottom_2.ID,bottom_2.new_DATE STARTDATE,
CASE WHEN rn =3 THEN bottom_2.nextSTARTDATE
 ELSE ADDDATE(bottom_2.nextSTARTDATE, INTERVAL -1 DAY ) END ENDDATE
FROM last
JOIN T0 bottom_2
ON bottom_2.nextSTARTDATE<=last.preENDDATE AND bottom_2.id = last.id
),T2 AS(
SELECT B.ID,B.STARTDATE,B.ENDDATE FROM
  (
   SELECT A.*,ROW_NUMBER()OVER(PARTITION BY ID,STARTDATE ORDER BY ENDDATE) rn
   FROM
   (
   SELECT A.ID,A.STARTDATE,A.ENDDATE
   FROM T_Serial A
   LEFT JOIN normal B
   ON A.STARTDATE = B.ENDDATE AND A.ID = B.ID
   WHERE B.ENDDATE IS NULL

   UNION 

   SELECT A.ID,A.STARTDATE,B.ENDDATE
   FROM T_Serial A
   INNER JOIN normal B
   ON ADDDATE(A.ENDDATE, INTERVAL 1 DAY ) = B.ENDDATE AND A.ID = B.ID
   )A
  )B WHERE rn =1
)

Step2 时间序列关联原表生成NUM字段。

SELECT T2.STARTDATE,T2.ENDDATE,SUM(T1.NUM) TOTAL FROM T2
JOIN test_ShenLiang2025 T1
ON T2.STARTDATE>=T1.STARTDATE
 AND T2.ENDDATE<=T1.ENDDATE
GROUP BY T2.STARTDATE,T2.ENDDATE
ORDER BY T2.STARTDATE

Step4 查看结果

STARTDATE   ENDDATE     NUM
2021-04-20 2021-04-30 200
2021-05-01 2021-05-03 300
2021-05-04 2021-05-24 100

执行结果:

到此这篇关于时间序列错位还原之SQL实现案例详解的文章就介绍到这了,更多相关SQL时间错位与还原生成案例内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • mysql、mssql及oracle分页查询方法详解

    本文实例讲述了mysql.mssql及oracle分页查询方法.分享给大家供大家参考.具体分析如下: 分页查询在web开发中是最常见的一种技术,最近在通过查资料,有一点自己的心得 一.mysql中的分页查询 注: m=(pageNum-1)*pageSize;n= pageSize; pageNum是要查询的页码,pageSize是每次查询的数据量, 方法一: select * from table order by id limit m, n; 该语句的意思为,查询m+n条记录,去掉前m条,返

  • Mysql、Oracle中常用的多表修改语句总结

    今天在sql训练题库中看到了这题,这是一道很有代表性的多表修改题,其实解出这道题并不难,无论是mysql中还是oracle中都有很多种解法,接下来就好好归纳一下这些解法. msyql中多表修改 对于mysql中常用的多表修改语句,还是用例子来解释一下吧. //建表 create table aaa(id int,value1 int(5),value2 int(5),value3 int(5),value4 int(5)); create table bbb like aaa; //插入数据 i

  • 浅谈Mysql、SqlServer、Oracle三大数据库的区别

    一.MySQL 优点: 体积小.速度快.总体拥有成本低,开源: 支持多种操作系统: 是开源数据库,提供的接口支持多种语言连接操作 : MySQL的核心程序采用完全的多线程编程.线程是轻量级的进程,它可以灵活地为用户提供服务,而不过多的系统资源.用多线程和C语言实现的mysql能很容易充分利用CPU: MySql有一个非常灵活而且安全的权限和口令系统.当客户与MySql服务器连接时,他们之间所有的口令传送被加密,而且MySql支持主机认证: 支持ODBC for Windows, 支持所有的ODB

  • mysql、oracle默认事务隔离级别的说明

    1.事务的特性(ACID) (1)原子性(Atomicity).事务中所涉及的程序对数据库的修改操作要么全部成功,要么全部失败. (2)一致性(Consistency).事务执行前和执行后来源和去向保持平衡. (3)隔离性(Isolation).并发时每个事务是隔离的,相互不影响. (4)持久性(Durubility).一旦事务成功提交,应该保证数据的完整存在. 2.事务隔离级别 (1)read uncommitted 未提交读 所有事务都可以看到没有提交事务的数据. (2)read commi

  • SQL实现时间序列错位还原案列

    目录 一.需求描述 二.思路概述 1 需求延展 2 思路概述 三.SQL代码 一.需求描述 1 原表T1某条记录(记做r1,相邻下一条为r2)的下一行记录的STARTDATE小于上一行ENDDATE,针对这样的记录做转换即: r1的STARTDATE保持不变,ENDDATE为r1的STARTDATE-1 r2的STARTDATE为r1的ENDDATE,ENDDATE为r1的ENDDATE 2 如果原表T1不存在相邻行"时间重叠"(即为1的定义)时保持原有数据不变. # 文本版 #T1

  • SQL SERVER 2005数据库还原的方法

    在SQL SERVER 2005下还原数据库 1.新建数据库A,右键还原数据库,此时目标数据库为A,选择备份 文件B_db_201311040200.BAK,还原时提示"备份集中的数据库备份与现有的A数据库不同" 2.google一下,有人说是文件名不同,即B的数据库文件为B.MDF, 要还原到A.MDF上,所以报错 3.删除A库,在根目录[数据库]上右键,还原数据库,先选择源文件, 然后再目标数据库中会自动出现B,选择B之后即可还原成功 相信很多的站长网站的时候需要用到SQL Ser

  • SQL Server表中添加新列并添加描述

    注: sql server 2005 及以上支持. 版本估计是不支持(工作环境2005,2008). 工作需要, 需要向SQL Server 现有表中添加新列并添加描述. 从而有个如下存储过程. (先附上存储过程然后解释) /********调用方法********** 作用: 添加列并添加列描述信息 调用: exec [SetColumnInfo] '表名', '列名', N'列说明,描述','列类型{默认:NVARCHAR(50)}','列默认值{默认:NULL}' ************

  • Sql Server中判断表、列不存在则创建的方法

    一.Sql Server中如何判断表中某列是否存在 首先跟大家分享Sql Server中判断表中某列是否存在的两个方法,方法示例如下: 比如说要判断表A中的字段C是否存在两个方法: 第一种方法  IF EXISTS ( SELECT 1 FROM SYSOBJECTS T1 INNER JOIN SYSCOLUMNS T2 ON T1.ID=T2.ID WHERE T1.NAME='A' AND T2.NAME='C' ) PRINT '存在' ELSE PRINT '不存在' 第二种方法,短小

  • SQL Server 2005数据库还原错误的经典解决方案

    在SQL Server 2005数据库还原的过程中出现错误:备份集中的数据库备份与现有的'xxxx'数据库不同,网上找了几个解决方案测试,最终成功还原,特此记录下,提供给需要的人. 第一步: 如果你知道备份数据库名你可以跳过第一步,如果你不知道备份数据库的名称,你可以先执行下面语句: RESTORE FILELISTONLY From disk = 'F:\路径\css_cms1'--备份数据库文件路径名 这样可以列出该文件里的data和log文件名,知道这两个文件名以后可以执行下一步了. 第二

  • javaweb购物车案列学习开发

    本文实例为大家分享了javaweb购物车案列的具体代码,供大家参考,具体内容如下 一.项目目录结构   二.源代码 dao包--dao层:BookDao.java package com.dao; import java.util.Map; import com.DB.DB; import com.domain.Book; public class BookDao { public Map getAll(){ return DB.getAll(); } public Book find(Stri

  • Tensorflow中批量读取数据的案列分析及TFRecord文件的打包与读取

    单一数据读取方式: 第一种:slice_input_producer() # 返回值可以直接通过 Session.run([images, labels])查看,且第一个参数必须放在列表中,如[...] [images, labels] = tf.train.slice_input_producer([images, labels], num_epochs=None, shuffle=True) 第二种:string_input_producer() # 需要定义文件读取器,然后通过读取器中的

  • el-table表头根据内容自适应完美解决表头错位和固定列错位

    将代码复制到指令中即可使用.通过指令方式进行调用.(使用方式 <el-table v-tableFit></el-table>) 通过计算文字的宽度进行表头设置,其他内容无法计算. 5000个单元格以上根据实际情况使用以上根据实际情况使用,因为单元格越多,计算时间越长. 尽量使用v-if,不然有些情况下会计算错误. Vue.directive("tableFit", { //指令所在组件的 VNode 及其子 VNode 全部更新后调用. componentUp

  • 通过SQL语句来备份,还原数据库

    eg: 复制代码 代码如下: /* 通过SQL 语句备份数据库 */ BACKUP DATABASE mydb TO DISK ='C:\DBBACK\mydb.BAK' --这里指定需要备份数据库的路径和文件名,注意:路径的文件夹是必须已经创建的.文件名可以使用日期来标示 /* 通过SQL语句还原数据库 */ USE master RESTORE DATABASE mydb FROM DISK='C:\DBBACK\mydb.BAK' WITH REPLACE 注意:很多时候不能直接还原,因为

  • 推荐SQL Server 重新恢复自动编号列的序号的sql代码

    在sql server中经常有这样的问题:         一个表采用了自动编号的列之后,由于测试了好多数据,自动编号已累计了上万个.现在正是要用这个表了,测试数据已经删了,遗留下来的问题 就是 在录入新的数据,编号只会继续增加,已使用过的但已删除的编号就不能用了, 谁知道如何解决此问题? truncate命令不但会清除所有的数据,还会将IDENTITY的SEED的值恢复到原是值. 而DBCC CHECKIDENT则更加方便一些,可以在不删除数据的情况下指定SEED的值.  1. truncat

随机推荐