SQL实现根据时间戳和增量标记IDU获取最新记录和脱IDU标记

需求说明:表中有 id, info, cnt 三个字段,对应的增量表多idu增量标记字段和时间戳字段ctimestamp。增量表中的 id 会有重复,其他字段 info、cnt 会不断更新,idu为增量标记字段,ctimestamp为IDU操作的时间戳。目的时要做到:

1)获取增量表中的时间戳字段(ctimestamp)为最新值对应的记录、进行id去重;

2)将第一步的查询结果进行脱IDU标记和时间戳字段、合并到最终的表中(不带IDU标记和时间戳字段)。

SQL查询根据时间戳字段和id字段获取最新值的记录

-- 表字段说明:id 会有重复,其他字段 info、cnt 会不断更新,idu为增量标记字段,ctimestamp为IDU操作的时间戳,需求是要获取时间戳字段(ctimestamp)为最新值对应的记录:

-- 脱IDU和时间戳以后的最终目的表(不带增量标记和时间戳字段)

drop table if exists test81;

-- 带IDU标记idu字段和时间戳字段ctimestamp,id字段可能存在重复的值的记录

drop table if exists test81_idu;

-- 基于 test81_idu 生成的 D 的记录,id唯一(去重后无重复记录)

drop table if exists test81_tmp2_d;

-- 基于 test81_idu 生成的 I、U 的记录,id唯一(去重后无重复记录)

drop table if exists test81_tmp3_iu;

-- 创建最终目的表、并构部分已有数据

create table test81 (

id int not null,

info varchar(100),

cnt int,

primary key(id));

insert into test81 (id,info,cnt) values (1, 'aaa', 31);

insert into test81 (id,info,cnt) values (2, 'bbb', 33);

insert into test81 (id,info,cnt) values (3, 'ccc', 35);

注意:如果是GBase8a primary key(id) 主键约束无效。

select * from test81;

查询结果:

+----+------+------+

| id | info | cnt |

+----+------+------+

| 1 | aaa | 31 |

| 2 | bbb | 33 |

| 3 | ccc | 35 |

+----+------+------+

-- 创建带IDU标记的表,id存在重复多条记录

create table test81_idu (

id int not null,

info varchar(100),

cnt int,

idu varchar(10),

ctimestamp timestamp);

insert into test81_idu (id,info,cnt,idu,ctimestamp) values (1, 'aaa', 31, 'I', '2023-10-27 12:31:31.123456789');

insert into test81_idu (id,info,cnt,idu,ctimestamp) values (2, 'bbb', 33, 'I', '2023-10-27 12:33:33.123456789');

insert into test81_idu (id,info,cnt,idu,ctimestamp) values (3, 'ccc', 35, 'I', '2023-10-27 12:35:35.123456789');

insert into test81_idu (id,info,cnt,idu,ctimestamp) values (1, 'aaa', 50, 'U', '2023-10-27 12:50:50.123456789');

insert into test81_idu (id,info,cnt,idu,ctimestamp) values (1, 'aaa', 41, 'U', '2023-10-27 12:41:41.123456789');

insert into test81_idu (id,info,cnt,idu,ctimestamp) values (2, NULL, NULL, 'D', '2023-10-27 12:52:52.123456789');

注意:MySQL支持上面9位(精确到纳秒的输入),只是数据库行为实际上丢弃后面3位,只取前面6位,但不会报错,能执行成功。但如果是GBase8a,则不行,只能指定6位:

insert into test81_idu (id,info,cnt,idu,ctimestamp) values (1, 'aaa', 31, 'I', '2023-10-27 12:31:31.123456');

insert into test81_idu (id,info,cnt,idu,ctimestamp) values (2, 'bbb', 33, 'I', '2023-10-27 12:33:33.123456');

insert into test81_idu (id,info,cnt,idu,ctimestamp) values (3, 'ccc', 35, 'I', '2023-10-27 12:35:35.123456');

insert into test81_idu (id,info,cnt,idu,ctimestamp) values (1, 'aaa', 50, 'U', '2023-10-27 12:50:50.123456');

insert into test81_idu (id,info,cnt,idu,ctimestamp) values (1, 'aaa', 41, 'U', '2023-10-27 12:41:41.123456');

insert into test81_idu (id,info,cnt,idu,ctimestamp) values (2, NULL, NULL, 'D', '2023-10-27 12:52:52.123456');

select * from test81_idu;

执行结果:

+----+------+------+------+---------------------+

| id | info | cnt | idu | ctimestamp |

+----+------+------+------+---------------------+

| 1 | aaa | 31 | I | 2023-10-27 12:31:31 |

| 2 | bbb | 33 | I | 2023-10-27 12:33:33 |

| 3 | ccc | 35 | I | 2023-10-27 12:35:35 |

| 1 | aaa | 50 | U | 2023-10-27 12:50:50 |

| 1 | aaa | 41 | U | 2023-10-27 12:41:41 |

| 2 | NULL | NULL | D | 2023-10-27 12:52:52 |

+----+------+------+------+---------------------+

表字段说明:id 会有重复,其他字段 info、cnt 会不断更新,idu为增量标记字段,ctimestamp为IDU操作的时间戳,需求是要获取时间戳字段(ctimestamp)为最新值对应的记录:

脱IDU标记合并处理(中间用多个到临时表)

-- 先查询一下根据时间戳字段和id进行处理,对id去重(同一个id的多条重复记录,只取时间戳最新的一条记录)

SELECT a.id,a.info,a.cnt,a.idu FROM test81_idu a,(

SELECT

id, MAX(ctimestamp)AS time

FROM test81_idu

GROUP BY id

ORDER BY COUNT(*)DESC)b WHERE a.id=b.id and a.ctimestamp=b.time;

执行结果:

+----+------+------+------+

| id | info | cnt | idu |

+----+------+------+------+

| 3 | ccc | 35 | I |

| 1 | aaa | 50 | U |

| 2 | NULL | NULL | D |

+----+------+------+------+

-- 如果用 INSERT INTO 则需要先创建目标表、如果用 SELECT INTO 则要保证目标表不存在(执行时会创建目标表)

DROP TABLE IF EXISTS test81_tmp2_d;

-- CREATE TABLE IF NOT EXISTS test81_tmp2_d LIKE test81_idu;

-- 根据id和时间戳查询最新记录、并只显示idu='D'的结果

-- MySQL不支持的方式:

-- SELECT id,info,cnt INTO test81_tmp2_d FROM test81_idu;

-- MySQL能支持的方式:

DROP TABLE IF EXISTS test81_tmp2_d;

CREATE TABLE test81_tmp2_d

(

SELECT a.id,a.info,a.cnt,a.idu FROM test81_idu a,(

SELECT

id, MAX(ctimestamp)AS time

FROM test81_idu

GROUP BY id

ORDER BY COUNT(*)DESC)b WHERE a.id=b.id AND a.ctimestamp=b.time AND a.idu='D'

);

-- 查询结果:

select * from test81_tmp2_d;

+----+------+------+------+

| id | info | cnt | idu |

+----+------+------+------+

| 2 | NULL | NULL | D |

+----+------+------+------+

-- 根据id和时间戳查询最新记录、并只显示idu='IU'的结果

-- MySQL能支持的方式

DROP TABLE IF EXISTS test81_tmp3_iu;

CREATE TABLE test81_tmp3_iu

(

SELECT a.id,a.info,a.cnt,a.idu FROM test81_idu a,(

SELECT

id, MAX(ctimestamp)AS time

FROM test81_idu

GROUP BY id

ORDER BY COUNT(*)DESC)b WHERE a.id=b.id AND a.ctimestamp=b.time AND (a.idu IN ('I','U'))

);

-- 查询结果:

select * from test81_tmp3_iu;

+----+------+------+------+

| id | info | cnt | idu |

+----+------+------+------+

| 3 | ccc | 35 | I |

| 1 | aaa | 50 | U |

+----+------+------+------+

-- 将'D'的数据从最终目标表删除

DELETE FROM test81 WHERE id in (SELECT DISTINCT id FROM test81_tmp2_d);

-- 'D' 记录删除后,查看目的表数据

select * from test81;

+----+------+------+

| id | info | cnt |

+----+------+------+

| 1 | aaa | 31 |

| 3 | ccc | 35 |

+----+------+------+

-- 将'I'和'U'的数据插入或更新到最终的目标表

-- merge into, 目的表的关联id存在则update、不存在则insert:

-- GBase8a 使用 merge into (MySQL 不支持该语法)

-- merge into test81 t1 using test81_tmp3_iu tmp on t1.id=tmp.id when matched then update set t1.info=tmp.info,t1.cnt=tmp.cnt when not matched then insert(id,info,cnt)values(tmp.id,tmp.info,tmp.cnt);

-- MySQL 使用 insert into (GBase8a 不支持该语法)

INSERT INTO test81(id,info,cnt) SELECT id,info,cnt FROM test81_tmp3_iu ON DUPLICATE KEY UPDATE info=VALUES(info), cnt=VALUES(cnt);

-- 'I'和'U'合并到目的表后,查询结果

select * from test81;

+----+------+------+

| id | info | cnt |

+----+------+------+

| 1 | aaa | 50 |

| 3 | ccc | 35 |

+----+------+------+

到此为止,整个脱IDU表级和时间戳的流程处理完毕。

相关推荐
人生在勤,不索何获-白大侠4 分钟前
day17——Java集合进阶(Collections、Map)
java·开发语言
程序员小羊!16 分钟前
Java教程:JavaWeb ---MySQL高级
java·开发语言·mysql
白仑色24 分钟前
Spring Boot 多环境配置详解
java·spring boot·后端·微服务架构·配置管理
超级小忍26 分钟前
在 Spring Boot 中优化长轮询(Long Polling)连接频繁建立销毁问题
java·spring boot·后端
David爱编程30 分钟前
Java 中 Integer 为什么不是万能的 int 替代品?
java·后端
老马啸西风32 分钟前
个人网站一键引入免费开关评论功能 giscus
java
木木子999937 分钟前
SQL138 连续两次作答试卷的最大时间窗
sql·题解记录
wkj00138 分钟前
php 如何通过mysqli操作数据库?
android·数据库·php
Z_W_H_1 小时前
【springboot】IDEA手动创建SpringBoot简单工程(无插件)
java·spring boot·intellij-idea
HeXDev1 小时前
【SkyWalking】服务端部署与微服务无侵入接入实战指南
java·微服务·架构·skywalking·链路追踪·微服务治理