目录
定义
使用 virtual_column_definition子句可以定义虚拟列,它不存在磁盘中,相反它是一个函数或是一组表达式,按照需求派生出来的一列值
column_name [datatype] [GENERATED ALWAYS] AS [expression] [VIRTUAL]
特性
虚拟列可以用在select,update,delete语句的where条件中,但是不能用于DML语句
可以基于虚拟列来做分区
可以在虚拟列上建索引,类似于oracle的函数索引。
可以在虚拟列上建约束
创建带虚拟列的表
创建一个带虚拟列的表
SQL> create table tb_vc01 ( empno number(2), ename varchar2(10), monthly_sal number(10,3), bonus number(10,3), yearly_sal number(10,3) generated always as (monthly_sal*12+bonus) ); |
其中yearly_sal为虚拟列
查看tb_vc01列的定义
SQL> select column_name,data_type,data_length,data_default,virtual_column from user_tab_cols where table_name='TB_VC01'; |
可以在virtual_column中看出值为YES
创建基于函数的虚拟列
在建表的过程也可以加上virtual显示声明虚拟列,并且在该列引用一个自建的函数
SQL> CREATE OR REPLACE FUNCTION get_emp_yearly_sal (p_monthly_sal NUMBER,p_bonus NUMBER) RETURN NUMBER DETERMINISTIC IS BEGIN RETURN p_monthly_sal * 12 + p_bonus; END; / |
SQL> create table tb_vc02 ( empno number(2), ename varchar2(10), monthly_sal number(10,3), bonus number(10,3), yearly_sal number(10,3) as (get_emp_yearly_sal(monthly_sal,bonus))VIRTUAL ); |
查看tb_vc02上列的定义
SQL> select column_name,data_type,data_length,data_default,virtual_column from user_tab_cols where table_name='TB_VC02'; |
分别向tb_vc01和tb_vc02插入测试数据并查看
SQL> insert into tb_vc01 (empno,ename,monthly_sal,bonus) values(01,'aaa',1000,10); |
可以看出yearly_sal列中的数值被计算出来
insert中不可以向虚拟列添加数据
SQL> insert into tb_vc01 values(02,'bbb',2000,20,9999); |
也不可以对其update
SQL> update tb_vc01 set yearly_sal=99999 where empno=10; |
在虚拟列上创建索引
SQL> create index ind_vc01 on tb_vc01(yearly_sal); |
索引定义为函数索引
SQL> select index_name,index_type from user_indexes where table_name='TB_VC01'; |
由于函数是表定义的一部分,如果删除以后,表也无法查看了
SQL> drop function get_emp_yearly_sal; |
添加虚拟列
虚拟列可以在建表以后添加
创建表TB_VC03
SQL> create table tb_vc03 (empno number(2),ename varchar2(10),monthly_sal number(10,3),bonus number(10,3)); |
像TB_VC03中添加虚拟列,可以不指定数据类型
SQL> alter table tb_vc03 add(yearly_sal as(monthly_sal*12+bonus)); |
可以在有虚拟列的表上收集统计信息
SQL> exec dbms_stats.gather_table_stats('scott','tb_vc03'); |
基于虚拟列分区
创建分区表tb_vc04
SQL> tb_vc04(empno number(2), ename varchar2(10), monthly_sal number(10,3), bonus number(10,3), yearly_sal number(10,3) as(monthly_sal*12+bonus) ) partition by range(yearly_sal)( partition sal_10000 values less than(10000), partition sal_30000 values less than(30000), partition sal_50000 values less than(50000), partition sal_70000 values less than(70000), partition sal_default values less than(maxvalue) ); |
添加一些数据并查看
SQL> select 10 empno,'aaa' ename,1000 monthly_sal,100 bonus from dual union select 20,'bbb',2000,200 from dual union select 30,'ccc',3000,300 from dual union select 40,'ddd',4000,400 from dual union select 50,'eee',5000,500 from dual union select 60,'fff',6000,600 from dual ; |
查看分区情况
SQL> select table_name,partition_name,num_rows from user_tab_partitions where table_name='TB_VC04' order by partition_name; |
收集一下统计信息
SQL> exec dbms_stats.gather_table_stats('scott','tb_vc04'); |
在分区的情况下,不能对虚拟列的引用列更新
SQL> update tb_vc04 set monthly_sal=8000 where empno=10; |
如果需要更新则要设置enable row movement
SQL> alter table tb_vc04 enable row movement; |
不可以创建基于函数的虚拟列的分区
SQL> CREATE OR REPLACE FUNCTION get_emp_yearly_sal (p_monthly_sal NUMBER,p_bonus NUMBER) RETURN NUMBER DETERMINISTIC IS BEGIN RETURN p_monthly_sal * 12 + p_bonus; END; / |
SQL> create table tb_vc05( empno number(2), ename varchar2(10), monthly_sal number(10,3), bonus number(10,3), yearly_sal number(10,3) as(get_emp_yearly_sal(monthly_sal,bonus)) ) partition by range(yearly_sal)( partition sal_10000 values less than(10000), partition sal_30000 values less than(30000), partition sal_50000 values less than(50000), partition sal_70000 values less than(70000), partition sal_default values less than(maxvalue) ); |