Oracle 11g 虚拟列

创建虚拟列

建立一个简单的测试表:

SQL> CREATE TABLE EMP
  2  (
  3    EMPNO     NUMBER(6),
  4    SAL       NUMBER(8),
  5    COMM      NUMBER(8),
  6    SAL_PACK  NUMBER(8) GENERATED ALWAYS AS ( SAL + NVL(COMM,0) ) VIRTUAL
  7  );
Table created

其中, SAL_PCAK是虚拟列,虚拟列的数值是通过真实列中的数值计算而来的,虚拟列不能引用虚拟列。
虚拟列的值是不存储在磁盘中的,在查询的时候根据定义的表达式临时计算出来。
虚拟列的完整写法如SAL_PACK列,包括列名、数据类型、GENERATED ALWAYS关键字、AS加列表达式和VIRTUAL关键字。其中GENERATED ALWAYS和VIRTUAL为可选关键字,主要用于描述虚拟列的特性,写与不写没有本质区别。而列的数据类型如果忽略,那么Oracle会根据AS后面的表达式最终结果的数据类型来确定虚拟列的数据类型。即可简写为:

SQL> CREATE TABLE EMP
  2  (
  3    EMPNO     NUMBER(6),
  4    SAL       NUMBER(8),
  5    COMM      NUMBER(8),
  6    SAL_PACK  AS ( SAL + NVL(COMM,0) )
  7  );

虚拟列可以使用oracle自带的函数,也可以使用用户自定义的函数,但是函数必须是确定的,也就是带DETERMINISTIC关键字。

SQL> CREATE OR REPLACE FUNCTION f_test(p_empno IN NUMBER) RETURN NUMBER DETERMINISTIC AS
  2    BEGIN
  3      RETURN p_empno* 5;
  4    END;
  5  /
Function created
SQL> alter table emp add sal_num as (f_test(empno));
Table altered

Oracle虽然在创建创建的时候会检查函数的确定性,在表建立之后,却可以将函数替换为非确定性函数。
建立了虚拟列可以有效的减少数据的存储,简化查询语句中对列进行的处理,而且还可以利用虚拟列进行分区。不过虚拟列还会带来其他问题。
首先包含了虚拟列的表在INSERT INTO语句中不能省略COLUMN列表。由于虚拟列的值是由其他列的值计算得出的,且Oracle并不存储虚拟列的值,因此无论是INSERT还是UPDATE都不能对虚拟列进行修改

我们不能往虚拟列中直接插入数据:

SQL> insert into emp values(10,100,100,200);
insert into emp values(10,100,100,200)
ORA-54013: INSERT operation disallowed on virtual columns

也不能隐式的添加数据:

SQL> insert into emp values(10,100,100);
insert into emp values(10,100,100)
ORA-00947: not enough values

必须使用物理列来插入数据,不能省略COLUMN列名:

SQL> insert into emp(empno,sal,comm) values(10,100,100);
1 row inserted

插入成功后可以查询到虚拟列的值:

SQL> select * from emp;
  EMPNO       SAL      COMM   SAL_PACK
------- --------- --------- ----------
     10       100       100        200

更新comm的值为200,再重新查看虚拟列结果:

SQL> update emp set comm = 200 where empno = 10;
1 row updated
SQL> select * from emp;
  EMPNO       SAL      COMM   SAL_PACK
------- --------- --------- ----------
     10       100       200        300

由此可见,虚拟列中的值并不是固定的,而是根据公式在查询的时候即时计算的。

虚拟列的索引和约束

索引和约束同样可以应用在虚拟列中,创建索引如下:

SQL> create index sal_pack_idx on emp(sal_pack);
Index created

查看表中是否存在虚拟列,可以在plslq中,使用view查看emp表结构,如图:
这里写图片描述
如果程序选择一些工具来自动生成表的INSERT、UPDATE语句,那么遇到包含虚拟列的表就会报错。因为虚拟列不可以直接插入或者更新数据。
同样的原因,也无法使用Create table as select创建一个包含虚拟列的表。解决方法是Create table as select结束后通过alter table添加虚拟列。
虚拟列的结果是查询时确定,如果修改了虚拟列的表达式,下次执行查询的时候,虚拟列的值就会发生变化。
但是一旦对虚拟列建立了索引,或者对包含虚拟列的表建立了物化视图,那么虚拟列的值就被实际的存储下来,当虚拟列的表达式发生修改后,会导致索引或物化视图中已有的数据与目前虚拟列结果不一致。解决办法:删除索引并重建,或者将物化视图完全刷新。
如下sal_pack虚拟列已建立索引,修改其表达式,报错。

SQL> alter table emp modify sal_pack as (sal*10);
alter table emp modify sal_pack as (sal*10)
ORA-54022: Virtual column expression cannot be changed because an index is defined on column

一旦建立了索引,Oracle会禁止虚拟列发生更改,但是,Oracle并不禁止虚拟列参考函数的修改。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值