0%

PL/SQL数据类型关注点

数据类型决定了它的存储格式、有效值范围以及可以对它进行的操作。本文主要记录一些PL/SQL中标量数据类型需要注意的一些点。
首先简单解释下什么是标量数据类型,当第一次在ORACLE官方文档中看到这个词的时候也是有点懵的。ORACLE对其的解释是store values with no internal components,意思是标量数据类型只有一个值,没有内部分量,比如VARCHAR2、BOOLEAN、NUMBER等。与其相对的就是属性数据类型,比较常见的就是在PL/SQL中定义一个变量为数据库中的一行。

下面看看PL/SQL中定义的标量数据类型都有哪些:

  • SQL中的所有数据类型
  • BOOLEAN
  • PLS_INTEGER
  • BINARY_INTEGER
  • REF CURSOR
  • 用户定义的子类型

CHAR和VARCHAR2

CHAR数据类型会用空格对接收到的字符补齐到它定义的最大长度,VARCHAR2不会。即CHAR是定长的,而varchar2是可变长度的。

1
2
3
4
5
6
7
8
9
10
11
DECLARE
p_char CHAR(10 CHAR);
p_varchar2 VARCHAR2(10 CHAR);
BEGIN
p_char := 'char';
p_varchar2 := 'varchar2';

DBMS_OUTPUT.PUT_LINE('*' || p_char || '*');
DBMS_OUTPUT.PUT_LINE('*' || p_varchar2 || '*');
END;
/

输出如下:

1
2
*char      *
*varchar2*

在SQL数据类型中还有一个用于保存字符的数据类型——VARCHAR,在目前的版本中,它VARCHAR2完全一样的。在未来的发布版本中有可能会将其独立为单独的数据类型,以兼容新的数据SQL标准。

用PLS_INTEGER取代NUMBER

当需要进行大量的数据计算的时候建议使用PLS_INTEGER来取代NUMBER数据类型。它相比NUMBER具有以下优势:

  • 需要更少的存储空间
  • 对PLS_INTEGER的计算是直接基于硬件的,而NUMBER是通过库函数来完成的。

但是需要注意的是PLS_INTEGER的计算范围在-2,147,483,648到2,147,483,647之间。在此范围之外的计算就只能使用NUMBER或者他的子类型INTEGER。
PLS_INTEGR还有一个子类型——SIMPLE_INTEGER,它相比PLS_INTEGER加了NOT NULL的约束,以及对范围溢出的计算作了不同的处理。
当所有的操作数都为SIMPLE_INTEGER时,对溢出的计算操作会进行二补数计算。

二补数(2’s complement)是一种用二进制表示有号数的方法,也是一种将数字的正负号变号的方式,常在计算机科学中使用。在中国大陆地区通常称作补码。 一个数字的二补数就是将该数字作位反相计算(即一补数),再将结果加 1,即为该数字的二补数。在二补数系统中,一个负数就是用其对应正数的二补数来表示。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
DECLARE
n SIMPLE_INTEGER := 2147483645;
BEGIN
FOR j IN 1..4 LOOP
n := n + 1;
DBMS_OUTPUT.PUT_LINE(TO_CHAR(n, 'S9999999999'));
END LOOP;
FOR j IN 1..4 LOOP
n := n - 1;
DBMS_OUTPUT.PUT_LINE(TO_CHAR(n, 'S9999999999'));
END LOOP;
END;
/

结果如下

+2147483646
+2147483647
-2147483648
-2147483647
-2147483648
+2147483647
+2147483646
+2147483645

PL/SQL procedure successfully completed.

下面简单讲下这个过程,我们将范围限制在-8~7之间。

7+1的过程如下:
结果为8,溢出了,这时候对其进行二补码运算
8对应的二进制为:0000 1000
取反:1111 0111
+1:1111 1000
转换成十进制为-8