Oracle拉链表

什么是拉链表?

简单点说:记录一个事物,从开始一直到当前状态的所有变化信息。

复杂点说:记录数据在某一时间内的状态,以及数据在某一时间点的变化的数据存储方式。

为什么需要拉链表?

针对一些数据量大的表,像是保存了几年的数据,但是新增或者需要操作查看的数据只有一部分,或者只需要某个时间节点的数据,这个时候就可以使用拉链表进行操作。

怎么编写拉链表代码?

  1. 创建一个拷贝了emp的临时表emp1,防止修改到emp源表。
sql 复制代码
  	   drop table emp1;--如果以前有
       alter table emp1 add up_date date; --添加了一个新增数据的时间节点字段
       insert into emp1 e1(
          e1.empno,
          e1.ename,
          e1.job,
          e1.mgr,
          e1.hiredate,
          e1.sal,
          e1.comm,
          e1.deptno,
          e1.up_date
          )
          select 
          et.empno,
          et.ename,
          et.job,
          et.mgr,
          et.hiredate,
          et.sal,
          et.comm,
          et.deptno,
          sysdate-5
       from emp et;
       select * from emp1
  1. 创建目标表,用来比对emp1的数据
    重要字段start_date 、end_date 主要是这两个字段提取一段时间的数据。
sql 复制代码
---目标表
 drop table linkTable;
 create table linkTable as select * from emp where 1=2;
 select * from linkTable;
 alter table linkTable add up_date date;
 alter table linkTable add start_date date;--开始时间
 alter table linkTable add end_date date;--结束时间
 
 insert into linkTable lt(
        lt.empno,
        lt.ename,
        lt.job,
        lt.mgr,
        lt.hiredate,
        lt.sal,
        lt.comm,
        lt.deptno,
        lt.up_date,
        lt.start_date,
        lt.end_date
       
 )
        select 
          et.empno,
          et.ename,
          et.job,
          et.mgr,
          et.hiredate,
          et.sal,
          et.comm,
          et.deptno,
          et.up_date,
          to_date('2024-4-26','YYYY-MM-DD'),
          to_date('9999-9-9','YYYY-DD-MM')
        from emp1 et;
        
  1. 手动模拟新增的emp1数据
sql 复制代码
 update emp1 set sal=sal+1000,up_date=sysdate where ename='SMITH';
 insert into emp1 values(9999,'张三','xingjiapo',7369,
 				  date'1998-06-01',3600,1000,10,sysdate-1);
 select * from emp1;
 
  1. 创建一个存储过程,封装更新数据的动作。
    开链:目标中没有改记录,新增插入该条记录并把结束时间改成无穷大。
    闭链:目标中存在该条记录,只是部分状态值不同,update该数据,并把end_date调整为当日时间。
sql 复制代码
 ---创建存储过程
        create or replace procedure updateLinkTable(startTime varchar2,endTime varchar2)
        is
        v_start date := to_date(startTime,'YYYY-MM-DD HH24:MI:SS');
        v_end date := to_date(endTime,'YYYY-MM-DD HH24:MI:SS');
        cursor update_cursor is --创建游标保存指定时间内需要比对的数据
        select * from emp1  
        where up_date>=v_start and up_date<=v_end; ---指定时间内的数据
        v_count number;
        begin 
          for i in update_cursor loop --目标表与源表比对,
            select count(1) into v_count from linkTable lk --找到当前的数据并且当前数据未过期
            where i.empno = lk.empno and lk.end_date=to_date('9999-9-9','YYYY-MM-DD');
            
            if v_count=1 then
               update linkTable lk set lk.end_date=trunc(sysdate-1) --把原先的数据更新为过期数据(历史数据) 也就是闭链
               where i.empno = lk.empno and lk.end_date=to_date('9999-9-9','YYYY-MM-DD');
               --添加当前已更新的业务变动数据,并更新end_date无穷大
               insert into linkTable lk(
                      lk.empno,
                      lk.ename,
                      lk.job,
                      lk.mgr,
                      lk.hiredate,
                      lk.sal,
                      lk.comm,
                      lk.deptno,
                      lk.up_date,
                      lk.start_date,
                      lk.end_date
               ) values(
                      i.empno,
                      i.ename,
                      i.job,
                      i.mgr,
                      i.hiredate,
                      i.sal,
                      i.comm,
                      i.deptno,
                      i.up_date,
                      trunc(sysdate),
                      to_date('9999-9-9','YYYY-MM-DD')
               );
               elsif v_count=0 then --没有匹配上说明当前数据是新增数据,直接插入进去即可 (更新end_date无穷大 开链)
                  insert into linkTable lk(
                      lk.empno,
                      lk.ename,
                      lk.job,
                      lk.mgr,
                      lk.hiredate,
                      lk.sal,
                      lk.comm,
                      lk.deptno,
                      lk.up_date,
                      lk.start_date,
                      lk.end_date
               ) values(
                      i.empno,
                      i.ename,
                      i.job,
                      i.mgr,
                      i.hiredate,
                      i.sal,
                      i.comm,
                      i.deptno,
                      i.up_date,
                      trunc(sysdate),
                      to_date('9999-9-9','YYYY-MM-DD')
               );
            end if;
          end loop;
            exception
              when others then
                dbms_output.put_line(sqlcode);
                dbms_output.put_line(sqlerrm);
        end;
        
        select * from linkTable;
        select * from emp1;
  1. 调用存储过程,更新指定时间数据。
sql 复制代码
 ---方法一 pl/sql调用
begin
updateLinkTable('2024-5-28  00:00:00','2024-5-29 23:59:59');
end;
--方法二 SQL语句调用
call updateLinkTable(p_star => '2024-05-28 00:00:00',p_end => '2024-05-29 23:59:59');
-- 或者
call updateLinkTable('2024-05-28 00:00:00','2024-05-29 23:59:59');

拉链表的优缺点

优点

  • 节省存储空间,避免没必要的重复数据
  • 能查询到历史快照

缺点

  • 内存占用,查询效率受拉链长度的影响
  • 断链难以恢复
相关推荐
2301_788756063 分钟前
Python在2024年的主要趋势与发展方向
jvm·数据库·python
uoKent10 分钟前
MySQL示例数据库
数据库·mysql
麦聪聊数据12 分钟前
利用SQL2API模式重构微服务中的数据查询层
数据库·sql·低代码·微服务·架构
占疏19 分钟前
数据库-BRIN 索引
数据库·mysql
u01092727122 分钟前
Python虚拟环境(venv)完全指南:隔离项目依赖
jvm·数据库·python
m0_6860416123 分钟前
Python类型提示(Type Hints)详解
jvm·数据库·python
晚风_END23 分钟前
postgresql数据库|pgbouncer连接池压测和直连postgresql数据库压测对比
数据库·postgresql·oracle·性能优化·宽度优先
三水不滴42 分钟前
Redis 持久化机制
数据库·经验分享·redis·笔记·缓存·性能优化
lusasky1 小时前
Claude Code v2.1.0+ 版本集成LSP
大数据·数据库·人工智能
凯子坚持 c1 小时前
Qt常用控件指南(7)
服务器·数据库·qt