
3.2 创建表
创建表是数据库管理的基础操作,包括表和列的定义,列数据类型的定义、虚拟列和不可见列的使用等。
3.2.1 表和列的命名规则
创建表和列需要用户为表和列命名,Oracle数据库对表和列的命名有着一定的规则限制。好的命名能够有利于提高表和列的可读性,方便用户使用。本节介绍表和列的命名规则。
Oracle数据库对表和列的命名要求如下。
(1)必须以字母开头。
(2)长度不能超过30字符。
(3)不能使用Oracle保留字。
(4)只能使用如下字符:A~Z, a~z,0~9, $, #等。
(5)不能和已经存在的其他对象重名。
另外,为了增加表和列的可读性,通常表以名词或名词短语命名,确定表名是采用复数还是单数形式。为了区分系统的对象,也可对表、视图、列等对象添加不同的前缀来区分,如对表添加TB前缀。
3.2.2 使用设计器建表
使用设计器创建新表的步骤比较简单。首先打开Oracle SQL Developer并创建对数据库的连接,展开连接,找到表节点右击,选择【新建表】选项即可打开如图3-1所示的对话框。

图3-1 【创建表】对话框
如图3-1所示,可直接修改表的名称,单击右下方的【添加列】按钮可添加新的列,图3-1中有默认的一个列,可直接修改列的名称、类型、大小,是否为空和是否为主键。单击图3-1中的DDL标签可打开表的定义语句,如图3-2所示。

图3-2 表的定义语句
为空属性和主键属性是列的约束,将在3.4节详细介绍。图3-1可创建一个简单的表。若想详细定义列的属性,可选择右上角的【高级】复选框,打开表的高级设置对话框如图3-3所示。

图3-3 表的高级设置
如图3-3所示,在该对话框中可详细设置列的属性,包括主键设置、唯一约束条件设置、外键设置、检查约束条件设置、索引设置、列序列设置、表属性设置等。如选择【表属性】选项,可打开表的属性如图3-4所示。单击【存储选项】可打开【表存储选项】对话框,如图3-5所示。

图3-4 表的属性

图3-5 表存储选项
如图3-5所示,在该对话框下可设置表的存储选项,如表的初始、最大值、最小值等。设置完成后单击【确定】按钮回到图3-4对话框,再单击【确定】按钮回到图3-3所示的对话框,单击【确定】按钮即可实现表的创建。
新建表的时候除了可以在表节点下右击,选择【新建表】选项,还可以使用另外两种方式打开【创建表】对话框,如下所示。
(1)在Oracle SQL Developer下找到工具栏中的【文件】,单击并选择【新建】选项打开如图3-6所示的对话框,选择【表】并单击【确定】按钮打开【选择连接】对话框,如图3-7所示。选择表所在的连接,单击【确定】按钮即可打开【创建表】对话框。

图3-6 新建对象
(2)在Oracle SQL Developer下找到图标并单击,可打开如图3-6所示的对话框,使用上述(1)中的步骤可打开【创建表】对话框。

图3-7 选择连接
注意
如果用户需要在自己的模式下创建一个新表,必须具有CREATE TABLE权限;如果需要在其他用户模式中创建表,则必须具有CREATE ANY TABLE的系统权限。
3.2.3 使用SQL语句创建表
虽然使用设计器创建表步骤简单,但很多地方不允许使用设计器,此时只能使用SQL语句创建表。使用SQL语句创建表需要使用CREATE关键字,语法格式如下:
CREATE TABLE [schema.]table_name( column_name data_type [DEFAULT expression] [constraint] [, column_name data_type [DEFAULT expression] [constraint]] [, column_name data_type [DEFAULT expression] [constraint]] [, …] )[TABLESPACE tablespace_name]|[STORAGE (INITIAL nk|M NEXT nk|M PCTINCREASE n)]|[ CACHE];
中括号包括的内容为可选项。其中各个参数含义如下。
(1)schema:指定表所属的用户名或者所属的用户模式名称。
(2)table_name:所要创建的表的名称。
(3)column_name:表中包含的列的名称,列名在一个表中必须具有唯一性。
(4)data_type:列的数据类型。
(5)DEFAULT expression:列的默认值。
(6)constraint:为列添加的约束,表示该列的值必须满足的规则。
(7)TABLESPACE:指定将创建在哪个表空间。
(8)STORAGE:指定存储参数信息。
存储参数信息中各个参数的含义如下所示。
(1)INITIAL:用来指定表中的数据分配的第一个盘区的大小,以KB或者MB作为单位,默认值是5个Oracle数据块的大小。
(2)NEXT:用来指定表中的数据分配的第二个盘区的大小。该参数只有在字典管理的表空间中起作用,在本地化管理表空间中,该盘区大小将由Oracle自动决定。
(3)PCTINCREASE:用来指定表中的数据分配的第三个以及其后的盘区的大小,同样,在本地化管理表空间中,该参数不起作用。
使用CACHE关键字来对缓存块进行换入、换出调度操作,这样在查询已经查询过的数据时就不用再次查询数据库,加快了查询时间。
重做日志用来存储对表的一些操作记录信息。LOGGING子句将对表的所有操作都记录到重做日志中。
重做日志文件的主要目的是,万一实例或者介质失败,重做日志文件就能派上用场,或者可以作为一种维护备用数据库的方法来完成故障恢复。如果数据库所在主机掉电,导致实例失败,Oracle会使用在线重做日志将系统恢复到掉电前的那个时刻。如果包含数据文件的磁盘驱动器出现永久性故障,Oracle会使用归档重做日志以及在线重做日志,将磁盘驱动器的备份恢复到适当的时间点。
在创建表的时候,如果使用NOLOGGING子句,则对该表的操作不会保存到日志文件中去。使用这种方式可以节省重做日志文件的存储空间。但是某些情况下将无法使用数据库的恢复操作,从而无法防止数据信息的丢失。
在创建表的时候,如果没有使用LOGGING或者NOLOGGING子句的时候,则Oracle会默认使用LOGGING子句。
根据表中要添加的数据长度大小,在创建表的时候选择合适的数据类型以及数据类型精度,能够避免使用最大精度,减少了Oracle数据库占用的不必要的资源空间。
【范例1】
创建有一个主键的图书信息表TBBOOK,有数字类型表示标号的B_ID字段、长度可变的字符串类型表示书名的B_TITLE字段、长度可变的字符串类型表示图书类型的B_TYPE字段和长度可变的字符串类型表示图书出版社的B_PUBLISHER字段,其中将B_ID字段设置为主键,代码如下。
CREATE TABLE TBBOOK ( B_ID NUMBER NOT NULL , B_TITLE VARCHAR2(20) , B_TYPE VARCHAR2(20) , B_PUBLISHER VARCHAR2(20) , CONSTRAINT TBBOOK_PK PRIMARY KEY(B_ID) ENABLE );
3.2.4 虚拟列
在Oracle 11g中,Oracle以不可见索引和虚拟列的形式引入了一些增强特性;Oracle 12c继承前者并发扬光大,引入了不可见列的思想,来隐藏重要的数据列。这里先介绍虚拟列的创建和使用,在3.2.5节介绍不可见列的知识。
在老的Oracle版本中,需要使用表达式或者一些计算公式来计算列的值时,通常会创建数据库视图;如果需要在这个视图上使用索引,通常会创建基于函数的索引。Oracle 11g允许用户直接在表上使用虚拟列来存储表达式。
虚拟列的值是不存储在磁盘上的,它们是在查询时根据定义的表达式临时计算的。用户不能往虚拟列中插入数据;也不能隐式地添加数据到虚拟列。虚拟列的数据并没有存储在数据文件中,而是Oracle通过列数据的生成放到了数据字典中。
创建表的时候可以创建虚拟列,其完整定义包括列名、数据类型、GENERATED ALWAYS关键字、AS(列表达式)和VIRTUAL关键字,如下所示。
列名 数据类型 GENERATED ALWAYS AS (列表达式) VIRTUAL
其中,GENERATED ALWAYS和VIRTUAL为可选关键字,主要用于描述虚拟列的特性。如果忽略列的数据类型,那么Oracle会根据AS后面的表达式最终结果的数据类型来确定虚拟列的数据类型。
虚拟列的数值是通过真实列中的数据计算而来的,虚拟列的位置可以放在它参考的列的前面,也可以包括多个实际列的值,但是不能引用其他的虚拟列。一个表中不能只有虚拟列。
虚拟列可以使用Oracle自带的函数,也可以使用用户定义的函数,不过对于用户定义的函数要求必须声明函数的确定性。Oracle虽然在创建表的时候会检查函数的确定性,在表建立之后,却可以将函数替换为非确定性函数。
建立虚拟列可以有效地减少数据的存储,简化查询语句中对列进行的处理,而且还可以利用虚拟列进行分区。不过虚拟列还会带来其他问题,如下所示。
(1)包含虚拟列的表在INSERT INTO语句中不能省略字段列表。
(2)由于虚拟列的值是由其他列的值计算得出的,且Oracle并不存储虚拟列的值,因此无论是INSERT还是UPDATE都不能对虚拟列进行修改。
(3)如果程序选择使用了一些工具来自动生成表的INSERT、UPDATE语句,那么遇到包含虚拟列的表时就会报错。
(4)无法使用CREATE TABLE AS SELECT创建一个包含虚拟列的表。但可以在创建表之后通过ALTER TABLE添加虚拟列。
(5)当虚拟列的值被实体化,那么虚拟列表达式发生变化会造成实体化结果与虚拟列不一致。因为虚拟列的结果是在查询的时候确定的,如果修改了虚拟列的表达式,下次执行查询时,虚拟列的值就会发生变化。
(6)一旦对虚拟列建立了索引,或者对包含虚拟列的表建立了物化视图,那么虚拟列的数值就被实际地存储下来,当虚拟列的表达式发生修改后,会导致索引或物化视图中已有的数据与目前虚拟列结果不一致。
【范例2】
创建职工信息表,有职工编号W_ID字段,职工姓名W_NAME字段,职工出生年份W_BIRTHYEAR字段和入职年份W_INTIME字段,另外有虚拟列W_INAGE表示职工入职时的年龄,由职工出生年份和入职年份计算得出。创建职工信息表代码如下。
CREATE TABLE TBWORK ( W_ID NUMBER, W_NAME VARCHAR2(20), W_BIRTHYEAR NUMBER, W_INTIME NUMBER, W_INAGE NUMBER GENERATED ALWAYS AS (W_INTIME-W_BIRTHYEAR) VIRTUAL );
可向表中添加一条记录,查看虚拟列的效果。添加一条数据,包含职工编号、姓名、出生年份和入职年份,代码如下。
INSERT INTO TBWORK(W_ID, W_NAME, W_BIRTHYEAR, W_INTIME) VALUES(1, ' 何 明 ',1984,2007); COMMIT;
上述代码执行后查看表中的数据,代码如下。
SELECT * FROM TBWORK;
上述代码的执行效果如下所示。从下面的执行效果可以看出,虚拟列在查询时被系统默认添加了数据。
W_ID W_NAME W_BIRTHYEAR W_INTIME W_INAGE ---- --------- ------------- ----- -------- 1 何明 1984 2007 23
3.2.5 不可见列
在之前的版本中,为了隐藏重要的数据列,用户往往会创建一个视图来隐藏所需信息或应用某些安全条件。在Oracle 12c中,用户可以在表中创建不可见列。当一个列定义为不可见时,这一列就不会出现在通用查询中,除非在SQL语句或条件中有显式地提及这一列,或是在表定义中有DESCRIBED。
虚拟列和分区列同样也可以定义为不可见类型。但临时表、外部表和集群表并不支持不可见列。对于不可见列添加数据,必须在INSERT语句中显式提及不可见列名,将不可见列插入到数据库中。
列的可见和不可见属性可通过INVISIBLE(不可见)和VISIBLE(可见)两个关键字来设置,如在创建表的时候创建不可见列,代码如下。
列名 数据类型 INVISIBLE
也可使用ALTER TABLE语句修改数据列的可见和不可见属性,代码如下。
ALTER TABLE 表名 MODIFY (列名 INVISIBLE|VISIBLE);
【范例3】
创建学生成绩表,有学生学号、姓名、语文成绩、数学成绩和总成绩字段,为保护学生隐私,将学生姓名设置为不可见列,在查询成绩时仅显示学生学号和成绩信息。另外,将总成绩字段设置为虚拟列,值为语文成绩和数学成绩的和,代码如下。
CREATE TABLE TBREPORT ( R_ID NUMBER NOT NULL , R_NAME VARCHAR2(20) INVISIBLE , R_CHINESE NUMBER , R_MATHS NUMBER , R_TOTAL NUMBER GENERATED ALWAYS AS (R_CHINESE + R_MATHS) VIRTUAL );
向表中添加数据,包含学生编号、姓名、语文成绩和数学成绩,代码如下。
INSERT INTO TBREPORT (R_ID, R_NAME, R_ CHINESE, R_MATHS) VALUES(1, ’梁红 ',88,72); COMMIT;
上述代码执行后查询表中的数据,代码如下。
SELECT * FROM TBREPORT;
上述代码查询表中的所有数据,其执行效果如下所示。
R_ID R_CHINESE R_MATHS R_TOTAL ---- --------- ------- ------- 1 88 72 160
由上述执行效果可以看出,默认的查询没有提供学生的姓名信息。使用查询语句查询表中指定列的数据,包括学生姓名、语文成绩、数学成绩和总成绩信息,代码如下:
SELECT R_NAME, R_CHINESE, R_MATHS, R_TOTAL FROM TBREPORT;
上述代码的执行效果如下所示。
R_NAME R_CHINESE R_MATHS R_TOTAL -------- ----------- --------- ---------- 梁红 88 72 160
由上述执行效果可以看出,不可见列只有在指定查询时才能够看到。