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');

拉链表的优缺点

优点

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

缺点

  • 内存占用,查询效率受拉链长度的影响
  • 断链难以恢复
相关推荐
tyler_download5 分钟前
golang 实现比特币内核:实现基于椭圆曲线的数字签名和验证
开发语言·数据库·golang
weixin_4493108430 分钟前
高效集成:聚水潭采购数据同步到MySQL
android·数据库·mysql
Cachel wood1 小时前
Github配置ssh key原理及操作步骤
运维·开发语言·数据库·windows·postgresql·ssh·github
standxy1 小时前
如何将钉钉新收款单数据高效集成到MySQL
数据库·mysql·钉钉
汪小敏同学1 小时前
【Django进阶】django-rest-framework中文文档——快速入门
网络·windows·oracle
Narutolxy3 小时前
MySQL 权限困境:从权限丢失到权限重生的完整解决方案20241108
数据库·mysql
Venchill3 小时前
安装和卸载Mysql(压缩版)
数据库·mysql
Humbunklung3 小时前
一种EF(EntityFramework) MySQL修改表名去掉dbo前缀的方法
数据库·mysql·c#
PGCCC4 小时前
【PGCCC】postgresql 缓存池并发设计
数据库·缓存·postgresql
小爬虫程序猿4 小时前
如何利用Python解析API返回的数据结构?
数据结构·数据库·python