Oracle Database SQL Language Reference 笔记(4)—— SQL语句基本元素

这部分可以看作 SQL 语句的基本语法规则。主要包括:

  • 数据类型
  • 不同数据类型的比较规则
  • 数据的字面量
  • 格式模型
  • 空值
  • 注释
  • 数据库对象
  • 数据库对象名称及限定
  • SQL语句中引用数据库对象的语法


1、数据类型

Oracle 数据库管理的每个数值都有一种数据类型,数据类型实际上限定了该数据的取值范围、长度、精度乃至格式等要求。可以八卦一下,为什么要区分数据类型,都用一种数据类型(比如字符类型)来处理数据不是更简单吗?Alex Kriegel 和 Boris M. Trukhnow的《SQL Bible》对此有描述,主要是由于两个原因:一是历史原因,为了更有效地利用存储空间,比如如果把数字也用字符格式存储而不用二进制形式存储的话,那么-32768~32768之间的数字就需要6个字节(二进制形式存储只需要2个字节);二是因为逻辑一致性,每种数据类型都有自身的规则、排序次序、与其他数据类型的关系、固有的转换法则等,处理同样类型的集合比处理各种混在一起数据类型要方便得多。

Oracle 数据库数据类型涉及到的问题包括:

  • 有哪些内置的数据类型?
  • 能不能支持ANSI或其他数据库的数据类型?
  • 用户要自定义数据类型怎么做?
  • Oracle预置提供了哪些自定义数据类型?

此外,还有个外部数据类型的概念(external data type),注意要不要混淆外部数据类型与内置数据类型、用户定义类型。

1-1、有哪些内置的数据类型?

包括:

  • 字符类型
  • 数字类型
  • long和raw类型
  • 日期时间型
  • lob类型
  • rowid型

1-1-1、字符类型

字符类型分为两种:以ASCII编码存储的和以民族字符编码存储的。

每种字符类型又有两种串:定长的和变长的。这样分下来,就一共有4种:char、varchar2、nchar 和 nvarchar2。

使用 Oracle SQL 中的 dump 函数可以返回列或者属性的类型码(code),上述四种类型对应的类型码分别是 char 和 nchar 都是 96,varchar2 和 nvarchar2 都是 1。

字符类型的特点:

  • char:固定长度,类型说明表示为 CHAR [ ( size [ BYTE | CHAR ] ) ] ,长度计量单位按字节(BYTE,8位二进制串)或字符(CHAR,)计默认长度的计量单位由NLS_LENGTH_SEMANTICS参数确定(可在具有  dba 权限的用户会话中使用 show parameter NLS_LENGTH_SEMANTICS;来显示),默认长度同时也是最小长度为 1 字节(或字符),最大的长度为2000字节(或字符)。
  • varchar2 :可变长度,类型说明为 varchar2 ( size [ BYTE | CHAR ] ), 长度计量单位按字节(BYTE,8位二进制串)或字符(CHAR,)计默认长度的计量单位由NLS_LENGTH_SEMANTICS参数确定(可在具有  dba 权限的用户会话中使用 show parameter NLS_LENGTH_SEMANTICS;来显示),最小的长度上界(必须指定)为 1 字节(或字符),最大的长度上界为4000字节(或字符)。

nchar 和 char 的区别在于 nchar 不能指定长度计量单位,它的长度计量单位就是 char,而且长度不能超过2000字节;也就是说大部分情况下,不能超过 nchar(1000)。

nvarchar2 和 varchar2 的区别在于 nvarchar 不能指定长度计量单位,它的长度计量单位就是 char,而且长度不能超过4000字节;也就是说大部分情况下,不能超过 nvarchar2(2000)。


如果向 char 类型的数据中插入的实际字符串比定义的长度短,那么 oracle 会在数值中填充空格,确保每个值都达到定义中指定的长度;但如果向 varchar2 类型的数据中插入较短的字符串,oracle 不会填充空格。可以看出来,使用 varchar2 明显对空间的使用效率要高,一个有意思的问题是,既然有了高效率的 varchar2,那为嘛还要有 char 呢?有兴趣的读者可以参考CSDN上的这篇博文。



这里啰嗦几句关于计量单位 BYTE 和 CHAR 的问题。


BYTE 计量单位,表示按字节来计数;而 CAHR 计量单位,表示按字符来计数,这种计量方式与环境变量的字符集相关。举例子:

首先查看下当前会话的字符集:

scott@ORA11G> select userenv('language') from dual;

USERENV('LANGUAGE')
----------------------------------------------------
AMERICAN_AMERICA.WE8MSWIN1252


按照 Oracle 字符集命名规则 <语言><比特位数><编码>可知,当前环境是西欧、8位<8>、编码为 MSWIN1252。这是一个8位字符集,意味着1个CAHR等于1个BYTE。接下来创建一个表 T,包含两列数据: CBYTE 表示按 Byte 计量的长度为 3 的 char 类型数据,CCHAR 表示按 Char 计量的长度为 3 的 char 类型数据;

scott@ORA11G> create table t (cbyte char( 3 byte),cchar char (3 char) );

Table created.


现在往里面插数据,先插 ASCII 字符串:

scott@ORA11G> insert into t(cbyte) values('123');

1 row created.

向表中的 cbyte 列插入字符串'123'没有问题,因为该列的长度为 3byte,下面还是向 cbyte 列插入'1234'试试:

scott@ORA11G> insert into t(cbyte) values('1234');
insert into t(cbyte) values('1234')
                            *
ERROR at line 1:
ORA-12899: value too large for column "SCOTT"."T"."CBYTE" (actual: 4, maximum: 3)


报错了!说明要插入的数据长度不能超过 3 byte

现在来考察 cchar 列,向 ccahr 列插入 '123',也没问题:

scott@ORA11G> insert into t(cchar) values('123');

1 row created.

插入'1234' 会发生什么呢?

scott@ORA11G> insert into t(cchar) values('1234');
insert into t(cchar) values('1234')
                            *
ERROR at line 1:
ORA-12899: value too large for column "SCOTT"."T"."CCHAR" (actual: 4, maximum: 3)

Oops! 也报错了。

这两个例子说明,在编码长度为8位的环境中,CHAR 和 BYTE 的长度是一个意思,都是1个字节。

那么此时如果插入多字节字符会是什么情况呢?

首先我们来看看环境(Linux 中)的 LANG 变量,

scott@ORA11G> !echo $LANG
en_US.utf8


是 UTF8 编码,那么我现在如果输入中文字符的话,应该是 UTF8 编码的,试一下,首先试 cbyte:

scott@ORA11G> insert into t(cbyte) values('一二');
insert into t(cbyte) values('一二')
                            *
ERROR at line 1:
ORA-12899: value too large for column "SCOTT"."T"."CBYTE" (actual: 6, maximum: 3)


这里传入了2个字符,但是长度为6个字节,因此无法插入,现在试试 cchar:

scott@ORA11G> insert into t(cchar) values('一二');
insert into t(cchar) values('一二')
                            *
ERROR at line 1:
ORA-12899: value too large for column "SCOTT"."T"."CCHAR" (actual: 6, maximum: 3)

同样滴,cchar 并没有按照我们以为的2个字符来计算字符串 '一二' 的长度,而是仍然按照当前环境的1字符长度来算。


现在我们到另一个数据库环境下面来继续试验,这个数据库的字符集是 ZHS16GBK 字符集,可以看出这是个16位的字符集,查看下会话变量

scott@ORA11GR2> select userenv('language') from dual;


USERENV('LANGUAGE')
----------------------------------------------------
SIMPLIFIED CHINESE_CHINA.ZHS16GBK

跟上面一样创建一个完全一样的表格 T :

scott@ORA11GR2> create table t (cbyte char( 3 byte),cchar char (3 char) );


表已创建。


插入4个 ASCII 字符到 CBYTE 中,可以预见不会成功:

scott@ORA11GR2> insert into t(cbyte) values('1234');
insert into t(cbyte) values('1234')
                            *
第 1 行出现错误:
ORA-12899: 列 "SCOTT"."T"."CBYTE" 的值太大 (实际值: 4, 最大值: 3)


那插入 4 个 ASCII 字符到 CCHAR 中会是什么效果呢?

scott@ORA11GR2> insert into t(cchar) values('1234');
insert into t(cchar) values('1234')
                            *
第 1 行出现错误:
ORA-12899: 列 "SCOTT"."T"."CCHAR" 的值太大 (实际值: 4, 最大值: 3)

依然出错,试试双子节字符(汉字):

scott@ORA11GR2> insert into t(cbyte) values('一二');
insert into t(cbyte) values('一二')
                            *
第 1 行出现错误:
ORA-12899: 列 "SCOTT"."T"."CBYTE" 的值太大 (实际值: 4, 最大值: 3)


可以看到,cbyte 依然不行,因为 '一二' 占了4个字节,超出了 cbyte 定义的长度 3。但是 cchar 会怎样呢?


scott@ORA11GR2> insert into t(cchar) values('一二');

已创建 1 行。

scott@ORA11GR2> insert into t(cchar) values('一二三');

已创建 1 行。

scott@ORA11GR2> insert into t(cchar) values('一二三四');
insert into t(cchar) values('一二三四')
                            *
第 1 行出现错误:
ORA-12899: 列 "SCOTT"."T"."CCHAR" 的值太大 (实际值: 4, 最大值: 3)


我们看到,将双子节字符插入 cchar 中时,不仅 '一二' 成功了,'一二三' 也成功了,但是 '一二三四'失败了,失败的原因说有4个字符,超出了3个字符的限制。



你可能感兴趣的:(oracle,读书笔记)