PostgreSQL11 | 数据类型和运算符

上一篇文章整理并拓展了原书《PostgreSql11从入门到精通》第四章的内容,详细讲述了有关数据库表的创建、修改与删表

PostgreSQL11 | pgsql建表、改表与删表http://t.csdn.cn/P9OKA这一篇整理并拓展原书第五章(书第73页起)的内容。

数据类型和运算符

目录

数据类型和运算符

PostgreSql数据类型介绍

整数类型

浮点数类型

任意精度类型

日期与时间类型

字符串类型

二进制类型

布尔类型

数组类型

如何选择数据类型

常见运算符介绍

运算符概述

算数运算符

比较运算符

逻辑运算符

运算符的优先级


PostgreSql数据类型介绍

PostgreSql支持多种数据类型,主要有整数类型、浮点数类型、任意精度数值、日期/时间类型、字符串类型、二进制类型、布尔类型和数组类型等。

如果看过上一篇文章的人,就会有印象,我们说过,当一个数据表的字段确定时,它自身的数据类型也就固定,当我们想要在已存数据的条件下修改字段的数据类型是需要谨慎存储范围的,那么本章就会介绍pgsql的所有的常用数据类型。

整数类型

整数型数据类型主要是用来存储数字。

在pgsql中,整形的类型有MALLINT、INT(INTEGER)和BIGINT

整数型数据类型
类型名称 说明 存储空间
MALLINT 小范围整数 2 字节
INT(INTEGER) 普通大小的整数 4 字节
BIGINT 大整数 8 字节

不同的整数类型存储所需的空间不一样,占用空间越大的类型所能存储的整数范围也越大。根据他们的存储空间也可以算出他们所能存储的整数范围,例如MALLINT类型,因为它的存储空间是2字节(1Byte<字节>=8bit,所以占16bit),所以所能存储的数的最大范围是(2^15)-1,即32767。

不同整数类型的取值范围
数据类型 取值范围
SMALLINT -32768到32767
INT(INTEGER) -2147483648到2147483647
BIGINT -9223372036854775808到9223372036854775807

我们可以创建一下表temp1,把三种类型的字段都创建并尝试向字段存储范围内与范围外的值查看结果。

create table temp1(x smallint,y int,z bigint);

PostgreSQL11 | 数据类型和运算符_第1张图片

在使用整形字段时注意取值范围。

浮点数类型

pgsql中使用浮点数类型来存储小数。

浮点类型有两种:REAL和DOUBLE PRECISION

小数类型
类型名称 说明 存储需求
REAL 6 位十进制数字精度 4 字节
DOUBLE PRECISION 15 位十进制数字精度 8 字节

不同浮点数类型的取值范围
数据类型 取值范围 精度
REAL 1E-37到1E+37 至少 6 位小数
DOUBLE PRECISION 1E-307到1E+308 至少 15 位数字,太大或太小都会导致错误

pgsql也支持sql标准指示法float和float(p),用于声明非精确的数值类型。其中的“p”声明以二进制位表示的最低可接受精度。

REAL float(1)到float(24)
DOUBLE PRECISION float(25)到float(53)

允许的范围之外将会报错没有声明精度的float将默认为DOUBLE PRECISION类型

可以通过下面展示的sql语句创建一个表来自行尝试数据添加的范围

create table temp2 (x float(5),y real,z double precision);
insert into temp2 () values();

任意精度类型

在pgsql中,使用NUMERIC(M, N)表示任意精度类型的数值。其中,M称为精度,即总共的位数,N称为标度,即小数的位数。

例如,563.186,精度为6,标度为3。

如果用户指定的精度超出精度外,就会进行四舍五入处理。

例如,创建表temp3

create table temp3 (x numeric(5,1),y numeric(5,1),z numeric(5,2));
insert into temp3 (x,y,z) values (9.14,9.15,7.15);
select * from temp3;

PostgreSQL11 | 数据类型和运算符_第2张图片

日期与时间类型

pgsql中有多种表示日期的数据类型,主要有TIMEDATETIMESTAMP。每一个类型都有合法的取值范围,当指定确实不合法的值时系统将“零”值插入数据库中。还有INTERVAL这种用于时间的快速加减计算的时间函数。

日期\时间数据类型
类型名称 含义 日期范围 存储需求
TIME 只用于一日内的时间 00:00:00~24:00:00 8 字节
DATE 只用于日期 4713BC~5874897AD 4 字节
TIMESTAMP 日期和时间 4713BC~5874897AD 8 字节

注意:因为格里高利历法里没有零年,所以数字上的1BC是公元零年。

另外,对于TIME和TIMESTAMP类型,默认情况下为without time zone(不带时区),如有需求可以设置为带时区(with time zone)。

1.TIME

time类型用于只需要时间信息的值,在存储时需要8字节,格式为HH:MM:SS。其中HH-小时,MM-分钟,SS-秒。time类型的取值为00:00:00~24:00:00。

例如,我们可以创建表temp4,并向建好的字段t中存入 10点23分46秒 和 19点37分。

create table temp4 (t time);
insert into temp4 (t) values ('10:23:46'),('19:37');
select * from temp4;

PostgreSQL11 | 数据类型和运算符_第3张图片

 向表temp4中再插入值'101112'

insert into temp4 (t) values ('101112');

PostgreSQL11 | 数据类型和运算符_第4张图片

就是说,pgsql其实是可以识别整数通过系统日期函数转换成时间格式的数据

可以向time类型字段插入系统时间

例如,向表temp4中插入系统当前时间

先修改字段t的数据类型为不带时区的time类型

alter table temp4 alter column t type time without time zone;

删除表中数据

delete from temp4;

 插入系统时间的两种方式

insert into temp4 values (current_time),(now());
select * from temp4;

 PostgreSQL11 | 数据类型和运算符_第5张图片

2.DATE

date类型用在仅需要日期值时,没有时间部分,在存储时需要4字节,日期格式为'YYYY-MM-DD',其中YYYY表示年,MM表示月,DD表示天。

例如,创建表temp5为例

create table temp5 (d date);

向表中插入正确格式的数据

insert into temp5 values ('1998-08-08'),('19980808'),('20101010');
select * from temp5;

PostgreSQL11 | 数据类型和运算符_第6张图片

可以看到各个不同格式的日期都正确的插入到表中。 

有关格式‘YYMMDD’的识别范围

当然,在给DATE类型的字段赋值的时候,可以使用字符串类型或者数字类型的数据插入,在使用格式‘YYMMDD’的整数识别的时候也是有临界值的,因为不知道世纪,所以pgsql规定以下规则解释两位年值。

年值识别范围
范围区间 世纪取值
00~69 2000~2069
70~99 1970~1999

为方便我们查看临界值效果,先将表清空。

delete from temp5;

向表中插入数据

insert into temp5 values ('691231'),('700101'),('000101'),('991231');
select * from temp5;

PostgreSQL11 | 数据类型和运算符_第7张图片

使用时间相关的函数

date类型数据还可以使用比如NOW()这样的时间函数来获取当前日期

先清理表中数据

delete from temp5;
insert into temp5 values (now());
select * from temp5;

PostgreSQL11 | 数据类型和运算符_第8张图片

NOW()函数返回日期和时间值,在保存到数据库时,只保存了其日期部分。

3.TIMESTAMP

TIMESTAMP的日期格式为YYYY-MM-DD HH:MM:SS。在存储的时候需要8字节,因此插入数据的时候需要保证在合法的取值区间内。

例如,创建表temp7,定义一个当前类型的字段ts并插入数据

create table temp7 (ts timestamp);
insert into temp7 values ('1991-12-25 19:38:00'),(now());
select * from temp7;

PostgreSQL11 | 数据类型和运算符_第9张图片

4.创建带时区的时间和时间类型

例如,创建表temp7h,并定义一个带时区的TIME类型字段t并插入数据

create table temp7th (t time with time zone);

PST (北美太平洋标准时间) 是UTC-8时区的知名名称之一,此时区位于格林威治向西8个时区,比UTC(协调世界时)落后8个小时与UTC的时间偏差可写为-08:00。

insert into temp7th values ('10:25:46 pst'),('10:25:46');
select * from temp7th;

PostgreSQL11 | 数据类型和运算符_第10张图片

5.通过时间函数INTERVAL快速加减时间

Interval 是另一种数据类型,用于存储和部署年,月,日,小时,分钟,秒,等中的时间。 月和日值是整数值,而秒的字段可以是分数值。

pgsql的间隔数据类型值占用16字节存储大小,这有助于存储可接受范围为- 178000000年至178000000 年的时间段。

我们可以依旧使用表temp7,但需要先清表后再插入一个时间

delete from temp7;
insert into temp7 values ('2000-10-01 10:30:20');

然后可以在查询时使用该函数来快速获得指定时间的加减计算的结果

select ts,ts-INTERVAL '6 months 2 hours 30 minutes' as "ts通过INTERVAL减去指定的时间" from temp7;

PostgreSQL11 | 数据类型和运算符_第11张图片

Interval的常用时间有:years、months、days、hours、minute、second

字符串类型

字符串类型用来存储字符串数据,除了可以存储字符串数据之外,还可以存储其他数据,比如图片和声音的二进制数据。

字符串数据类型
类型名称 说明

CHAR(n)

CHARACTER(n)

固定长度非二进制字符串,不足补空白

VARCHAR(n)

CHARACTER VARYING(N)

变长非二进制字符串,有长度限制
TEXT 变长非二进制字符串,无长度限制

1.CHARACTER(n)和CHARACTER VARYING(n)

其中的n是个正整数。当存储的字符串超出了n的范围时会产生一个错误,除非超过的部分是空白。

例如新建的表temp8

create table temp8 (
	ch character(4),
	vch character varying(4)
);

插入用于对比的字符串 

insert into temp8 values ('ab','ab'),('abcd','abcd'),('ab  ','ab  ');
select concat('(',ch,')'),concat('(',vch,')') from temp8;

PostgreSQL11 | 数据类型和运算符_第12张图片

 从查询结果来看,可以看到ch在保存‘ab'时在右侧填充空格以达到指定的长度,而vch字段仅仅保留了’ab'。

(上例中的concat()函数用于在查询时返回的结果为连接参数产生的字符串,与python中的字符串拼接输出控制台相似)

如果插入的字符长度完全超过规定的长度,例如插入’abcdefg‘,则报错

insert into temp8 values ('abcefg','abcefg');

PostgreSQL11 | 数据类型和运算符_第13张图片

 2.TEXT类型

在pgsql中的text类型可以存储任何长度的字符串。尽管类型text不是sql标准,但许多其他数据库中也有该类型。

例如,创建表temp9,定义字段te,数据类型为text,向表中插入不同长度的字符串,sql语句如下。

create table temp9 (te text);
insert into temp9 values ('ab'),('abcd'),('ab  ');
select concat('(',te,')') from temp9;

PostgreSQL11 | 数据类型和运算符_第14张图片

二进制类型

pgsql支持两类字符型数据,文本字符串和二进制字符。这里讲二进制数据的数据类型。

pgsql提供了BYTEA类型,用于存储二进制字符串。该类型存储空间为4字节+实际二进制字符串。

例如,创建表temp10

create table temp10(b bytea);
insert into temp10 values(E'\\000');
select * from temp10;

 PostgreSQL11 | 数据类型和运算符_第15张图片

布尔类型

pgsql提供了Boolean布尔类型。布尔类型用1字节来存储,提供了TRUE(真)和FALSE(假)两个值。

另外,用户可以使用其他有效的文本值替代TRUE和FALSE。替代TRUE的文本值为’t'、'true'、'y'、'yes'和'1',替代FALSE的文本值为’f'、'false'、'n'、'no'和'0'。

例如,创建表temp11,定义bytea类型的字段b,向表中插入布尔型数据“TRUE”和“FALSE”。

create table temp11 (b boolean);
insert into temp11 values (TRUE),(FALSE),('y'),('no'),('0');
select * from temp11;

PostgreSQL11 | 数据类型和运算符_第16张图片

数组类型

pgsql允许将字段定义成定长或变长的一维或多维数组。

1.声明数组

在pgsql中,一个数组类型是通过在数组元素后附加方括号来命名的

例如:

numb int[]

xuehao text[][]

zuoye text[4][4]

 这种格式与主流开发语言对于多维数组的定义格式类似,但方框中的整数为声明的数组的长度。

另外,对于一维的数组,也可以使用sql的标准声明。

pay_by_quarter int array[5];

2.插入数据

例如,创建表temp12

create table temp12(bt int[]);
insert into temp12 values('{{1,1,1},{2,2,2},{3,3,3}}');
select * from temp12;

PostgreSQL11 | 数据类型和运算符_第17张图片

如何选择数据类型

pgsql提供了大量的数据类型,为了优化储存、提高数据库性能,在任何情况下均应使用最准确的类型,即在所有可以表示该列值的类型中该类型所使用的存储空间最小。

1.整数与浮点数

如果不需要小数,就用整数来保存数据;如果需要小数,就使用浮点数类型。

对于浮点数,存入的数值会被该列定义的小数位进行四舍五入。例如,列值范围为1~99999,若使用整数,则int是最好的类型;若需要存储小数,则使用浮点数类型。

2.日期与时间类型

如果是需要记录时间,就使用time类型;如果只是需要记录日期,就使用DATE类型。

如果同时都需要记录,就可以使用TIMESTAMP类型。

3.CHAR和VARCHAR之间的特点和选择

CHAR和VARCHAR之间的区别就是,CHAR是固定长度字符,VARCHAR是可变的长度字符。

对于插入数据长度不够时,CHAR会自动填充插入数据的尾部空格,VARCHAR不会自动填充尾部空格。

常见运算符介绍

运算符连接表达式中的各个操作数,用来指明对操作数所进行的运算。

运算符概述

1.算术运算符

用于各类数值运算,包括加(+)、减(-)、乘(*)、除(/)和求余(%)

2.比较运算符

用于比较运算,包括大于(>)、小于(<)、等于(=)、大于等于(>=)、小于等于(<=)、不等于(!=)以及IN、BETWEEN...AND...、GREATEST、LEAST、LIKE等

3.逻辑运算符

逻辑运算符的求值所得结果均为t(TRUE)、f(FALSE)。这类运算符有逻辑非(NOT)、逻辑与(AND)和逻辑或(or)。

4.位操作运算符

参与位操作运算的操作数,按二进制位进行计算。位操作运算符包括与(&)、位或(|)、位非(~)、位异或(^)、左移(<<<)和右移(>>>) 共6种。

算数运算符

算数运算符是sql中最基本的运算符。

算数运算符
运算符 作用
+ 加法运算
- 减法运算
* 乘法运算
/ 除法运算,返回商
% 取余运算,返回余数

下面展示不同的算术运算符的使用

例如,创建表temp14

create table temp14 (num int);
insert into temp14 values (64);
select num,num+10,num-10,num+5-3,num+36.5 from temp14;

PostgreSQL11 | 数据类型和运算符_第18张图片

 对temp14表中的num进行乘法、除法运算

select num,num*2,num/2,num/3,num%3 from temp14;

PostgreSQL11 | 数据类型和运算符_第19张图片

这里num/3,因为64无法被3整除,所以结果位21.3333保留四位小数,又因为整型的数据类型,结果保留为21 

用0去除num

select num,num/0,num%0 from temp4;

PostgreSQL11 | 数据类型和运算符_第20张图片

 在数学运算中,除数为0的运算是无意义的,因此除法中的除数不能为0。

比较运算符

一个比较运算符的结果总是t、f或是空值。

比较运算符
运算符 作用
= 等于
<> (!=) 不等于
<= 小于等于
>= 大于等于
> 大于
< 小于
LEAST 在有两个或多个参数时,返回最小值
GREATEST 在有两个或多个参数时,返回最大值
BETWEEN...AND... 判断一个值是否落在两个值之间
IN 判断一个值是IN列表中的任意一个值
LIKE 通配符匹配

下面展示不同比较运算符的使用方法

本例子中演示无需用到数据表,实际使用中按需求使用即可

1.等于运算符(=)

select 1=0,'2'=2,2=2,'b'='b',(1+3)=(2+1),null=null;

PostgreSQL11 | 数据类型和运算符_第21张图片

等于运算符在进行数值比较时有如下规则:

(1) 若有一个或两个参数为null,则比较运算的结果为空

(2) 若同一个比较运算中的两个参数都是字符串,则按照字符串进行比较

(3) 若两个参数均为整数,则按照整数进行比较

(4) 若一个字符串和数字进行相等判断,则pgsql可以将字符串转换为数字

2.不等于运算符(<> 或者 !=)

不等于运算符用于判断数字、字符串、表达式不相等的判断,如果不相等,返回t;否则返回f。

不等于运算符不能用于判断空值NULL

select 'good'<>'god',1<>2,4!=4,5.5!=5,(1+3)!=(2+1),null<>null;

PostgreSQL11 | 数据类型和运算符_第22张图片

3.小于等于运算符(<=)

小于等于运算符用来判断左边的操作数是否小于或者等于右边的操作数。

如果小于或等于则返回值t,否则返回f。

小于等于不能用于判断空值

select 'good'<='god',1<=2,4<=4,5.5<=5,(1+3)<=(2+1),null<=null;

PostgreSQL11 | 数据类型和运算符_第23张图片

4.小于运算符(<)

小于运算符用来判断左边的操作数是否小于右边的操作数,如果小于,返回值为t,否则返回f。

小于运算符不能用于判断空值NULL

select 'good'<'god',1<2,4<4,5.5<5,(1+3)<(2+1),null

PostgreSQL11 | 数据类型和运算符_第24张图片

5.大于等于运算符(>=)

大于等于运算符用于判断左边的操作数是否大于或等于右边的操作数,如果大于或者等于,则返回值为t,否则返回f。

大于等于运算符不能用于判断空值NULL。

select 'good'>='god',1>=2,4>=4,5.5>=5,(1+3)>=(2+1),null>=null;

PostgreSQL11 | 数据类型和运算符_第25张图片

6.大于运算符(>)

大于运算符用于判断左边的操作数是否大于右边的操作数,如果大于,返回值为1,否则返回0.

大于运算符不能用于判断空值NULL。

select 'good'>'god',1>2,4>4,5.5>5,(1+3)>(2+1),null>null;

PostgreSQL11 | 数据类型和运算符_第26张图片

7.BETWEEN...AND...运算符

BETWEEN...AND...运算符的语法格式为:

expr BETWEEN min AND max

所代表的意思是:假如 变量expr 大于或等于min expr小于或等于max,则返回结果为t,否则为f。

所以该运算符的逻辑可以理解为“介于”,某变量是否在某区间范围内,与IN不同。

select 4 between 2 and 5,4 between 4 and 6,12 between 9 and 10;

PostgreSQL11 | 数据类型和运算符_第27张图片

同时也可以进行字符串的比较

select 'x' between 'f' and 'g','b' between 'a' and 'c','红' between '红' and '星';

PostgreSQL11 | 数据类型和运算符_第28张图片

 (我们的数据库是默认的utf8编码,汉字的排序也遵循在码表中的顺序比较)

8.LEAST运算符

LEAST运算符的语法格式为:

LEAST(值1,值2, .... ,值n)

LEAST运算符在有2个及以上的多个参数中返回其中的最小值,若在其中有NULL值则忽略不参与比较。

select least(2,0),least(100,500,20);

PostgreSQL11 | 数据类型和运算符_第29张图片

9.GREATEST运算符

GREATEST运算符语法格式为:

GREATEST(值1,值2, .... ,值n)

GREATEST运算符在有2个及以上的多个参数中返回其中的最大值,若在其中有NULL值则忽略不参与比较。

select greatest(2,0),greatest(100,500,20);

PostgreSQL11 | 数据类型和运算符_第30张图片

10.IN、NOT IN运算符

IN运算符用来判断操作数是否为IN列表中的其中一个值,如果,则返回t,否则返回f。

NOT IN运算符用来判断操作数是否为 NOT IN列表中的其中一个值,如果不是,则返回t,否则返回f。

(1) IN的使用

select 2 in (1,2,3,4) ,3 in (8,9,7);

PostgreSQL11 | 数据类型和运算符_第31张图片

(2) not in的使用

select 2 not in (1,2,3,4) ,3 not in (8,9,7);

PostgreSQL11 | 数据类型和运算符_第32张图片

通过结果可以看到,IN与NOT IN的返回值刚好相反,在左侧表达式为NULL,或者表中找不到匹配项,并且表中有一个表达式为NULL的情况下,IN的返回值均为空值。

select null in (1,2,3,4) ,10 not in (1,3,null);

PostgreSQL11 | 数据类型和运算符_第33张图片

11.LIKE运算符

LIKE运算符用于匹配字符串,语法为:

expr LIKE 匹配条件

如果变量expr 满足匹配条件,就返回t,否则返回f。

若expr或匹配条件中任何一个为NULL,则结果为空值。

匹配规则:

(1)‘%’,匹配任何数目的字符,甚至包括零字符

(2)‘_’,只能匹配一个字符

select 'stud' like 'stud','stud' like 'stu_','stud' like '%d','stud' like 't___','s' like null;

PostgreSQL11 | 数据类型和运算符_第34张图片

逻辑运算符

在sql中,所有逻辑运算符的求值所得结果均为TRUE、FALSE或空值。不同数据库中的表达方式相同。

逻辑运算符
运算符 作用
NOT 逻辑非
AND 逻辑与
OR 逻辑或

1.NOT

逻辑非运算符NOT表示当操作数为TRUE时,所得值为f;当操作数为FALSE时,所得值为t,当操作数为NULL时,所得返回值为空值。

select not '1',not 'y',not '0',not NULL,not 'n';

PostgreSQL11 | 数据类型和运算符_第35张图片

逻辑运算符的参数必须是布尔变量,如果随意输入其他类型的数值,就将会弹出错误提示信息。

2.AND

逻辑与运算符AND表示当所有操作数均为TRUE并且不为NULL时,计算所得结果为t,当一个或多个操作数为FALSE时,所得结果为f,其余情况返回空值。

select '1' and 'y','1' and '0','1' and NULL,'0' and NULL;

PostgreSQL11 | 数据类型和运算符_第36张图片

“AND”运算符可以有多个操作数,但要注意:多个操作数运算时,AND两边一定要使用空格键隔开,不然会影响结果的正确性。

3.OR

逻辑或运算符OR表示当两个操作数均为非NULL值时,任意一个操作数为TRUE,则结果为t,否则结果为f;有一个操作数为NULL时,若另一个操作数为TRUE,则结果为t,否则结果为空值;当两个操作数均为NULL时,所得结果为空值。

select '1' or 't' or '0','1' or 'y','1' or NULL,'0' or NULL,NULL or NULL;

PostgreSQL11 | 数据类型和运算符_第37张图片

运算符的优先级

运算的优先级决定了不同的运算符在表达式中计算的先后顺序。

运算符按优先顺序级由低到高排列
优先级 运算符
最低 =(赋值运算),:=
| OR
AND
NOT
BETWEEN,CASE,WHEN,THEN,ELSE
=(比较运算),>=,>,<=,<,<>,!=,IS,LIKE,IN
-(减法运算),+
*,/(除法运算),%(取余运算)
-(负号符)
最高 !

结合案例——运算符的使用

案例目的:创建数据表,并对表中的数据进行运算操作,掌握各种运算符的使用方法。

创建表temp15,其中包含VARCHAR类型的字段note和INT类型的字段price,使用运算符对表temp15中不同的字段进行运算;使用逻辑操作符对数据进行逻辑操作。

1.创建表temp15

create table temp15 (note varchar(100),price INT);

2.向表中插入一条记录,note值为“Redstar”,price值为50

insert into temp15 values ('Redstar',50);

3.对temp15表中的整数值字段price进行算数运算

select price,price+10,price-10,price*2,price/2,price%3 from temp15;

PostgreSQL11 | 数据类型和运算符_第38张图片

 4.对temp15中的整型数值字段price进行比较运算

select price,price>10,price<10,price!=10,price=10,price<>10 from temp15;

PostgreSQL11 | 数据类型和运算符_第39张图片

 5.判断price值是否落在30~80之间,返回与70,30相比最大的值,判断是否为IN列表(10,20,50,35)中的某个值

select price,price between 30 and 80,greatest(price,70,30),price in(10,20,50,35) from temp15;

PostgreSQL11 | 数据类型和运算符_第40张图片

 6.对temp15中的字符串数值字段note进行比较运算,判断表temp15中note字段是否为空;使用LIKE判断是否以字母’t‘开头,是否以’r'结尾。

select note,note is NULL,note LIKE 't%',note LIKE '%r' from temp15;

PostgreSQL11 | 数据类型和运算符_第41张图片

作者的话(Alvin):

本文根据原书《PostgreSql11 从入门到精通》(清华大学出版社)第5章总结整理,为提问与解答可以帮助更多人,本博客模拟GitHub的issue方案,所以私信已关,有问题请在评论区直接指正与提问,允许转发、复制或引用本文章,必须遵守开源法则注释来源与作者,感谢您的阅读。

你可能感兴趣的:(Postgresql,sql,postgresql)