PostgreSQL从菜鸟到专家系列教程(9)数据定义 数字数据类型 数组

发布时间:2019-11-28编辑:脚本学堂
PostgreSQL从菜鸟到专家系列教程(9)数据定义 数字数据类型 数组

数字数据类型

PostgreSQL的数字数据类型比我们现在为止遇到的类型都稍复杂,但是它们也不是特别难理解。我们可以存储两类不同的数字到数据库中,整数和浮点数字。再细分,整数类型有一些子类型,包括serial类型(我们已经使用过,用于在一个表中建立一个唯一的值)和不同大小的整数,如表8-3所示。

表8-3 PostgreSQL整数数据类型  

复制代码 代码如下:
子类型  标准名  描述
Smalll integer  Smallint  一个2字节的符号型整数,可以存储-32768到32767的数字
Integer  Int  一个4字节的符号型整数,可以存储-2147483648到2147473647的数字
Serial   和integer一样,除了它的值通常是由PostgreSQL自动输入的。

浮点数据也可以再细分,分为提供通用功能的浮点值和固定精度的数字,如表8-4所示。

表8-4 PostgreSQL浮点数据类型
 

复制代码 代码如下:
子类型  标准名  描述
float  float(n)  支持最少精度为n,存储为最多8字节的浮点数。
float8  real  双精度(8字节)浮点数字
numeric  numeric(p,s)  拥有p个数字的实数,其中小数点后有s位。不像float,这始终是一个确切的数字,但工作效率比普通浮点数字低。
money  numeric(9,2)  PostgreSQL特有的类型,但在其他数据库里也普遍存在。Money类型从PostgreSQL 8.0开始不赞成使用,且可能在以后版本中取消。你应该使用number类型代替。

被分成整数和浮点数据这两类的原因很容易理解,但numeric类型的用途不太明显。

浮点数据以科学计数法方式,使用尾数和幂存储。对于numeric类型,你可以在执行计算时同时指出精度和准确的存储的数字。你还可以指出小数点后的数字个数。实际的小数点位置变得非常自由了!

警告:最常见的错误时认为numeric(5,2)可以存储一个类似于12345.12的数字。这是错误的。在这里头存储的总归数字个数只有五个,所以定义为numeric(5,2)的数字在溢出前最大只能存储999.99。

PostgreSQL一般会捕捉对无法存储到字段中的值的插入,所以尝试插入很大的数字到任何类型的数字列将失败。
尝试:使用数字类型

现在,我们可以实验数字数据类型。首先,我们需要删除我们的testtype表,然后使用一些不同的列类型来重新建立它:
 

复制代码 代码如下:

test=> DROP TABLE testtype;
DROP TABLE

test=> CREATE TABLE testtype (
test(>     asmallint    smallint,
test(>     anint        int,
test(>     afloat       float(2),
test(>     areal        real,
test(>     anumeric     numeric(5,2)
test(> );

CREATE TABLE
test=> INSERT INTO testtype VALUES(2, 2, 2.0, 2.0, 2.0);
INSERT 17883 1
test=> INSERT INTO testtype VALUES(-100, -100, 123.456789, 123.456789, 123.456789);
INSERT 17884 1
test=> INSERT INTO testtype VALUES(-32768, -123456789, 1.23456789,
test-> 1.23456789, 1.23456789);
INSERT 17885 1
test=> INSERT INTO testtype VALUES(-32768, -123456789, 123456789.123456789,
test-> 23456789.123456789, 123456789.123456789);
ERROR:  numeric field overflow
DETAIL:  The absolute value is greater than or equal to 10^8 for field with
precision 5, scale 2.
test=>
test=> INSERT INTO testtype VALUES(-32768, -123456789, 123456789.123456789,
test-> 123456789.123456789, 123.123456789);
INSERT 17886 1
test=>
test=> SELECT * FROM testtype;
asmallint |   anint    |    afloat    |    areal     | anumeric
———–+————+————–+————–+———-
2 |          2 |            2 |            2 |     2.00
-100 |       -100 |      123.457 |      123.457 |   123.46
-32768 | -123456789 |      1.23457 |      1.23457 |     1.23
-32768 | -123456789 | 1.23457e+008 | 1.23457e+008 |   123.12
(4 rows)

test=>

解析

我们建立了一个表,包含一个短整数列,一个普通整数列,一个浮点数字列,一个实数列,一个精度为5,小数点后为2的数字列。

你会发现float和real类型的行为非常相似,但是numeric列的行为有点不同。Numeric类型不是存储接近的数,而是在小数后面进行后超出固定长度的部分进行四舍五入。如果我们存储太大的数据到其中,INSERT将失败。还要注意float和real也会对数字四舍五入;例如123.456789被四舍五入为123.457。
时间型数据类型

时间型数据类型存储和时间相关的信息,在第四章,我们看到了如何控制数据的格式。PostgreSQL有一系列的与日期和时间相关的类型,如表8-5所示,但是我们在本书中通常只限制于SQL92标准的类型。

表8-5 PostgreSQL的时间数据类型
 

复制代码 代码如下:
定义  意义
date  存储日期信息
time  存储时间信息
timestamp  存储日期和时间
interval  存储timestamp之间差别的信息
timestamptz  PostgreSQL扩展的类型,存储包含时区信息的timestamp
特殊数据类型

由于PostgreSQL源于一个用于研究的数据库系统,PostgreSQL拥有一些少见的数据类型用于存储几何和网络数据类型,如表8-6所示。使用PostgreSQL的这些任何一种特殊功能都会使一个Postgresql数据库的可移植性变得非常的差,所以通常,我们趋向于避免这些扩展。要获得更多的关于这些类型的信息,查询PostgreSQL的文档,在“数据类型”部分。

表8-5 PostgreSQL的特殊数据类型
 

复制代码 代码如下:
定义  意义
box  矩形盒子
line  一组点
point  一对几何学的数字
lseg  一条线段
polygon  一条封闭的几何线
cidr或inet  一个IPv4的地址,录入192.168.0.1
macaddr  以mac地址(以太网卡物理地址)

注:PostgreSQL也允许你使用SQL命令CREATE TYPE在数据库中建立你自己的类型。这通常不需要,而且在一定程度上,它是PostgreSQL独有的。更多的信息可以在官方文档中找到。注意建立你自己的类型可能导致数据库的模式非常限于PostgreSQL中使用,因为用户自定义类型无法被移植。

数组

PostgreSQL有另一个独特的功能:能够在表中存储数组。在SQL99标准之前,这不是一个标准的功能,所以在数据库实践中很少见。通常,一个数组需要通过使用一个附加表实现。但是,数组的能力有时候很有用,特别是当你需要存储固定数量的重复元素时,而且它非常容易使用。

建立数组的方法有两种:传统的PostgreSQL的方法和SQL99标准的方法。我们在这里会简单介绍这两种方法。
PostgreSQL样式的数组

要将一个表的列定义为数组,你可以简单地在类型后面添加[];不需要定义元素的个数。如果你使用了大小来定义,PostgreSQL接受你的定义,但它不强制接受指定数量的元素。
尝试:使用PostgreSQL语法定义数组

作为一个示例,假设我们决定要有一个雇员表,表中要包含一个指示他们工作日的指示器。通常,我们需要为每一天分配一个列,或者一个单独的表来储存工作日。在PostgreSQL中,我们可以简化这个工作,直接存储工作日的数组,就像这样:
 

复制代码 代码如下:

test=> CREATE TABLE empworkday (
test(>     refcode char(5),
test(>     workdays int[]
test(> );

CREATE TABLE
test=>

这建立了一个有两个列的empworkday表:一个参考字符串以及一个叫做workdays的整数数组。要网数组列中插入值,我们需要用大括号分隔符包围由逗号分割的值的列表,就像这样:
 

复制代码 代码如下:

test=> INSERT INTO empworkday VALUES(‘val01′, ‘{0,1,0,1,1,1,1}’);
INSERT 17892 1
test=> INSERT INTO empworkday VALUES(‘val02′, ‘{0,1,1,1,1,0,1}’);
INSERT 17893 1
test=>

我们可以一次性选择数组元素的所有值,就像这样:
test=> SELECT * FROM empworkday;
refcode |    workdays
———+—————–
val01   | {0,1,0,1,1,1,1}
val02   | {0,1,1,1,1,0,1}
(2 rows)

test=>
我们也可以通过给出数组的索引值来取出单个元素:
test=> SELECT workdays[2] FROM empworkday WHERE refcode = ‘val02′;
workdays
———-
1
(1 row)
test=>

解析

PostgreSQL的行为很像传统的编程语言,存储一个数组的值,甚至还有不需要指出数组的大小的好处。如果你选择整个数组,PostgreSQL显示在花括号之间的所有的用逗号分隔的值。

有一个需要注意的事情是PostgreSQL的数组中第一个元素的索引值是1而不是0,而很多编程语言通常是0.如果你尝试选择一个不存在的数组元素,将返回NULL。

注:PostgreSQL也允许多维数组。要知道更多PostgreSQL关于数组的内容,请参考文档。
SQL99样式的数字

在SQL99标准中,新的数组定义语法被提出。这比PostgreSQL样式更明确的一种语法,必须指出元素的个数,而PostgreSQL在实现时是不强制执行这个标准的。
尝试:使用SQL99语法的数组

让我们定义我们早前的表,使用SQL99样式的定义来做实验:

复制代码 代码如下:

test=> DROP TABLE empworkday;
DROP TABLE
test=> CREATE TABLE empworkday (
test(>     refcode char(5),
test(>     workdays int array[7]
test(> );

CREATE TABLE
test=> INSERT INTO empworkday VALUES(‘val01′, ‘{0,1,0,1,1,1,1}’);
INSERT 17899 1
test=> INSERT INTO empworkday VALUES(‘val02′, ‘{0,1,1,1,1,0,1}’);
INSERT 17900 1
test=>
test=> SELECT * FROM empworkday;
refcode |    workdays
———+—————–
val01   | {0,1,0,1,1,1,1}
val02   | {0,1,1,1,1,0,1}
(2 rows)
 
test=>
test=> SELECT workdays[2] FROM empworkday WHERE refcode = ‘val02′;
workdays
———-
1
(1 row)

test=>

解析

就像你看到的,SQL99样式的数组和PostgreSQL样式的数组基本一样。唯一的不同是定义的语法有点不同。

本文转自: http://www.mysqlops.com/2012/05/06/postgresql-date-type-3.html