Oracle、SqlServer——临时表
一、oracle
1、概述:
oracle数据库的临时表的特点:
- 临时表默认保存在TEMP中;
- 表结构一直存在,直到删除;即创建一次,永久使用;
- 不支持主外键。
- 可以索引临时表和在临时表基础上建立视图。建立在临时表上的索引也是临时的,也是只对当前会话或者事务有效. 临时表可以拥有触发器.
临时表分为事务型和会话型
- 会话型:基于会话的临时表,数据从会话开始到会话结束之间是有效的,当会话结束时,表中的数据会自动清空。不同会话之间的数据是隔离的,互不影响。
- 事务型:基于事务的临时表,其比会话型的临时表更灵活,可以认为是从会话型临时表的优化,因为表中的数据的保存时间与会话型相同,有效期从会话开始,在会话结束时,数据库自动清空临时表中的数据。与会话型临时表不同的是 在事务提交或者事务回滚 时将清空临时表中的数据。当然,会话型临时表在会话期间可以采用 delete 临时表名;的方式清空临时表数据。
语法:
create global temporary table 临时表名
(
……
)
on commit [preserve|delete] rows;
- preserve时就是会话(SESSION)型的临时表
- delete就是事务(TRANSACTION)型的临时表
2、示例:
(1)、创建临时表
declare tempisexist integer:=0;
begin
select count(*) into tempisexist from all_tables where table_name='NK_SLTJ';
if tempisexist=0 then--不存在临时表就创建一个
execute immediate('
CREATE GLOBAL TEMPORARY TABLE NK_SLTJ
(
LCK_FJNM varchar(36),
LCMC varchar(70),
GFX integer,
ZFX integer,
DFX integer,
KZDSL integer
)
on commit preserve rows' --preserve表示回话级。
);
end if;
end;
(2)、使用临时表
declare
FXZ NUMBER;
FJNM varchar(36);
ZZNM varchar(36):='77c48880-a2be-4d3c-97b7-26f8de0bee63';
CURSOR NKFXZcur is select NKFXJZ_FXZ,NKLCK_FJNM from NKFXJZ INNER JOIN NKLCK ON NKLCK_NM=NKFXJZ_LCNM where NKLCK_ZZNM=ZZNM;
begin
delete NK_SLTJ; --防止在统一会话中多次执行导致数据重复,因此程序一开始就应清空临时表数据
insert into NK_SLTJ SELECT NKLCK_FJNM, NKLCK_MC,0,0,0,KZD FROM --向临时表插入数据。
( select KZDSL.NKLCK_FJNM,KZDSL.KZD,LCJZ.NKLCK_MC from
(select substr(NKLCK_FJNM,1,4) as NKLCK_FJNM, count(NKNKJZ_KZD) AS KZD from NKLCK LEFT join NKNKJZ ON NKNKJZ_LCNM =NKLCK_NM WHERE NKLCK_ZZNM=ZZNM group by substr(NKLCK_FJNM,1,4)) KZDSL
INNER JOIN
(select NKLCK_FJNM, NKLCK_MC from NKLCK WHERE NKLCK_JC=1 and NKLCK_ZZNM=ZZNM) LCJZ ON LCJZ.NKLCK_FJNM=KZDSL.NKLCK_FJNM) ccc;
open NKFXZcur; --打开游标
fetch NKFXZcur INTO FXZ,FJNM; --提取游标数据
while NKFXZcur%FOUND loop --循环
if FXZ>=3.5 and FXZ<=5 then --高风险
update NK_SLTJ set GFX=GFX+1 where LCK_FJNM=substr(FJNM,0,4);
elsif FXZ>2 and FXZ<3.5 then --中风险
update NK_SLTJ set ZFX=ZFX+1 where LCK_FJNM=substr(FJNM,0,4);
else
if FXZ>=0 and FXZ<=2 then --低风险
update NK_SLTJ set DFX=DFX+1 where LCK_FJNM=substr(FJNM,0,4);
end if;
end if;
fetch NKFXZcur INTO FXZ,FJNM ;
end loop;--结束循环
close NKFXZcur; --关闭游标
end;
3、oracle创建全局表
- 以常规表的形式创建临时数据表的表结构,但要在每一个表的主键中加入一个 SessionID 列以区分不同的会话。(可以有 lob 列和主外键)
- 写一个用户注销触发器,在用户结束会话的时候删除本次会话所插入的所有记录 (SessionID 等于本次会话 ID 的记录 ) 。
- 程序写入数据时,要顺便将当前的会话 ID(SessionID) 写入表中。
- 程序读取数据时,只读取与当前会话 ID 相同的记录即可。
功能增强的扩展设计:
- 可以在数据表上建立一个视图,视图对记录的筛选条件就是当前会话的SessionID 。
- 数据表中的SessionID 列可以通过Trigger 实现,以实现对应用层的透明性。
- 高级用户可以访问全局数据,以实现更加复杂的功能。
二、SqlServer
1、临时表概述
SqlServer临时表有两种:局部临时表、全局临时表。
(1)临时表的共同特点:
- 无论会话的数据库上下文如何,临时表都被保存到 tempdb 数据库中;
- 当临时表数据较少时,页被保存到内存中;内存不足时,才持久化临时表的页;
- 判断临时表是否存在:if object_id('tempdb..#临时表名','U') N) is not null print '存在';
(2)临时表之间的区别
局部临时表:
临时表名前以#开头,临时表由创建该表的会话所有,为实现不同会话之间同名的临时表相互隔离,SqlServer为表名称添加下划线和唯一的数字后缀以区分不同会话间同名的临时表。即不同会话之间创建的临时表表名虽然我们看到的是一样,但实际上不一样。临时表的可见性与C#、C语言的变量类似,只对调用堆栈中的创建级别和创建级别的内部级别可见,如在存储过程中创建临时表,在存储过程结束后,临时表即被自动销毁。如果临时表在会话的最外层创建临时表,则在会话、批处理和内部级别中的任何地方都有效,直到会话终止时才销毁。 有效期为到创建级别范围内。同一个会话内可以在不同的级别内创建相同名称的局部临时表,但容易在表名解析时导致错误。
全局临时表:
表名以##开头,可以被所有的会话访问,且任何会话均可以删除全局临时表。全局临时表适用于在多个会话之间共享临时数据而不用担心安全问题,全局临时表的有效期为会话期间而不是创建级别,在创建全局临时表的会话结束后,全局临时表不再向新的会话发放锁,而等现有的会话访问完释放完锁后将销毁全局临时表。
2、创建不属于任何会话的全局临时表
该全局临时表由SqlServer维护一个大于0的引用计数器以确保不会被数据库自动删除。
方法:
在master数据库中创建有 sp_前缀、使用 startup 选项标记的特殊存储过程,
例:
use master;
go
if object_id('dbo.sp_test') is not null
drop proc dbo.sp_test
go
create proc dbo.sp_test
as
create table ##test
(
name varchar(36)
);
go
exec dbo.sp_procoption 'sp_test','startup','true';
这样一来,这种临时表的作用就和永久表没有多大区别了。
三、oracle与SqlServer 临时表的区别
oracle:
- 有事务表和会话表两种;
- 临时表永远保留表结构,数据保存在磁盘上。与永久表唯一不同的是在用户会话结束或者事务提交、回滚后删除数据,但是保留表结构;
SqlServer则是本地和全局临时表。
- SqlServer:在需要临时表时手动创建,会话结束时直接删除表结构。
- 当临时表数据较少时,页被保存到内存中;内存不足时,才持久化临时表的页;