第八章、PG数据类型(数字类型、货币类型、字符串类型)【一】


https://www.cnblogs.com/yaochong-chongzi/p/12637681.html


数值类型由2字节,4字节和8字节整数,4字节和8字节浮点数以及可变精度的小数组成。

 

NameStorage SizeDescriptionRange
smallint2 bytessmall-range integer-32768 to +32767
integer4 bytestypical choice for integer-2147483648 to +2147483647
bigint8 byteslarge-range integer-9223372036854775808 to +9223372036854775807
decimalvariableuser-specified precision, exactup to 131072 digits before the decimal point; up to 16383 digits after the decimal point
numericvariableuser-specified precision, exactup to 131072 digits before the decimal point; up to 16383 digits after the decimal point
real4 bytesvariable-precision, inexact6 decimal digits precision
double precision8 bytesvariable-precision, inexact15 decimal digits precision
smallserial2 bytessmall autoincrementing integer1 to 32767
serial4 bytesautoincrementing integer1 to 2147483647
bigserial8 byteslarge autoincrementing integer1 to 9223372036854775807

 

8.1.1. 整型

与MySQ类似PG中整型也是smallint,integer(int)和bigint类型,并且与MySQL一样基于范围,存储大小和性能之间实现最佳平衡考虑通常使用int(integer)整数类型,MySQL中往往自增主键用bigint,pg中当int类型取值不够时,也会用bigint代替。

如下integer类型插入1.1可以插入进去,但是存的值是整数1,四舍五入精度确实

复制代码
postgres=# \d products;
                Table "public.products"
   Column   |  Type   | Collation | Nullable | Default 
------------+---------+-----------+----------+---------
 product_no | integer |           |          | 
 name       | text    |           |          | 
 price      | numeric |           |          | 

postgres=# insert into products values(1.1,'banana',1.2);
INSERT 0 1
postgres=# select * from products;
 product_no |  name  |  price  
------------+--------+---------
          1 | Cheese |        
          1 | Cheese |        
          1 | Cheese |        
          1 | Cheese | 10.9890
          1 | banana |     1.2
复制代码

SQL仅指定整数类型integer(或int),smallint和bigint。 类型名称int2,int4和int8是扩展名,有些SQL数据库系统也使用这些扩展名,也就是说pg中int2是smallint的别名。

1
2
3
4
5
6
7
8
postgres=# create table test (int_c int2);
CREATE TABLE
postgres=#
postgres=# \d test;
                Table "public.test"
 Column |   Type   | Collation | Nullable | Default
--------+----------+-----------+----------+---------
 int_c  | smallint |           |          |

8.1.2. 精确浮点型

MySQL中称为精确浮点型,PG中原英文是Arbitrary Precision Numbers,翻译成中文是任意精度数,那么也好理解,decimal可以指定精确度,例如,数字23.5141的精度为6,小数位数为4。可以将整数视为小数位数为零,那么定义的时候即为decimal(6,4)或者NUMERIC(6,4)。实际存储空间类似于varchar(n),两个字节对于每组四个十进制数字,再加上三到八个字节的开销。

复制代码
postgres=# create table f (money decimal,a float);
CREATE TABLE
postgres=# insert into f select 1.214151515151321313123213,1.214151515151321313123213;
INSERT 0 1
postgres=# select * from  f;
           money            |        a         
----------------------------+------------------
 1.214151515151321313123213 | 1.21415151515132
(1 row)

postgres=# \d f;
                      Table "public.f"
 Column |       Type       | Collation | Nullable | Default 
--------+------------------+-----------+----------+---------
 money  | numeric          |           |          | 
 a      | double precision |           |          | 
复制代码

 

复制代码
postgres=# create table a ( a decimal(10,2));
CREATE TABLE
postgres=# \d a;
                    Table "public.a"
 Column |     Type      | Collation | Nullable | Default 
--------+---------------+-----------+----------+---------
 a      | numeric(10,2) |           |          | 

postgres=# insert into a values(1.23);
INSERT 0 1
postgres=# insert into a values(1.234);
INSERT 0 1
postgres=# insert into a values(1.2345);
INSERT 0 1
postgres=# insert into a values(1.2);
INSERT 0 1
postgres=# select * from a;
  a   
------
 1.23
 1.23
 1.23
 1.20
(4 rows)


postgres=# insert into a values(123456789.2);
ERROR:  numeric field overflow
DETAIL:  A field with precision 10, scale 2 must round to an absolute value less than 10^8.
postgres=# insert into a values(12345678.2);
INSERT 0 1
postgres=# select * from a;
      a      
-------------
        1.23
        1.23
        1.23
        1.20
 12345678.20
(5 rows)
复制代码

8.1.3. 浮点类型

real 和double precision类型是不精确的,实际上,这些类型通常是二进制浮点算术的IEEE标准754的实现(分别为单精度和双精度),只要底层处理器,操作系统和编译器支持它即可。存储钱之类的要求精度高的数据再次强调一定要用numeric,real和double 类型可以指定负无穷大,正无穷大值。

复制代码
postgres=# create table abc (abc real);
CREATE TABLE
postgres=# \d abc
               Table "public.abc"
 Column | Type | Collation | Nullable | Default 
--------+------+-----------+----------+---------
 abc    | real |           |          | 

postgres=# update abc set abc = '-Infinity';
UPDATE 0
postgres=# select * from abc;
 abc 
-----
(0 rows)

postgres=# insert into abc values (-10);
INSERT 0 1
postgres=# insert into abc values ('-Infinity');
INSERT 0 1
postgres=# insert into abc values ('-Infinity');
INSERT 0 1
postgres=# select * from abc;
    abc    
-----------
       -10
 -Infinity
 -Infinity
(3 rows)
复制代码

PostgreSQL还支持SQL标准float和float(p)来指定不精确的数字类型。在这里,“p”以二进制数指定最小可接受精度。 PostgreSQL以float(1)到float(24)来表示real类型,而float(25)float(53)表示double precision

1
2
3
4
5
6
7
8
postgres=# create table float_test(a float(10),b float(30));
CREATE TABLE
postgres=# \d float_test;
                 Table "public.float_test"
 Column |       Type       | Collation | Nullable | Default
--------+------------------+-----------+----------+---------
 a      | real             |           |          |
 b      | double precision |           |          |

8.1.4. Serial 类型

MySQL中自增可以指定auto increment关键字,Oracle可以使用序列,PG与Oracle有些类似,本节描述了PostgreSQL特定自增列的方法。

数据类型smallserial,serial和bigserial不是真实类型,而仅仅是创建唯一标识符列的符号方便(类似于某些其他数据库支持的AUTO_INCREMENT属性)。 在当前的实现中,指定:

复制代码
postgres=# create table test (id serial, money decimal);
CREATE TABLE
--或者
postgres=# CREATE SEQUENCE product_id_seq AS integer;
CREATE SEQUENCE
postgres=# CREATE TABLE product (id integer NOT NULL DEFAULT nextval('product_id_seq') primary key,country varchar(20));
CREATE TABLE

postgres=# ALTER SEQUENCE product_id_seq OWNED BY product.id;
ALTER SEQUENCE
postgres=# insert into product(country) values('China');
INSERT 0 1
postgres=# insert into product(country) values('Japan');
INSERT 0 1
postgres=# select * from product;
 id | country 
----+---------
  1 | China
  2 | Japan
(2 rows)
postgres=# select nextval('product_id_seq');
 nextval 
---------
       3
(1 row)

postgres=# select nextval('product_id_seq');
 nextval 
---------
       4
(1 row)

postgres=# insert into product(country) values('USA');
INSERT 0 1
postgres=# select * from product;
 id | country 
----+---------
  1 | China
  2 | Japan
  5 | USA
(3 rows)

postgres=# \d product;
                                    Table "public.product"
 Column  |         Type          | Collation | Nullable |               Default               
---------+-----------------------+-----------+----------+-------------------------------------
 id      | integer               |           | not null | nextval('product_id_seq'::regclass)
 country | character varying(20) |           |          | 
Indexes:
    "product_pkey" PRIMARY KEY, btree (id)
复制代码

类型名称“ serial”和“ serial4”是等效的:都创建“ integer”类型的列。 类型名称“ bigserial”和“ serial8”的工作方式相同,不同之处在于它们创建了“ bigint”列。 如果您预计在表的生命周期内使用超过231个标识符,则应使用“ bigserial”。 类型名称“ smallserial”和“ serial2”的工作方式相同,只是它们创建了“ smallint”列。删除列时,将自动删除列上对应的序列。 您可以删除序列而不删除列,但是这将强制删除列默认表达式。

8.2. Monetary Types货币类型

 money类型(货币类型)以固定的分数精度存储货币金额,见下表。 小数精度由数据库的lc_monetary设置确定。 表中显示的范围假设有两个小数位。 接受的输入格式有多种,包括整数和浮点文字,以及典型的货币格式,例如“ $ 1,000.00”。 输出通常采用后一种形式,但取决于语言环境。

复制代码
postgres=# create table money_test( id bigint primary key, money money);
CREATE TABLE
postgres=# \d money_test;
            Table "public.money_test"
 Column |  Type  | Collation | Nullable | Default 
--------+--------+-----------+----------+---------
 id     | bigint |           | not null | 
 money  | money  |           |          | 
Indexes:
    "money_test_pkey" PRIMARY KEY, btree (id)

postgres=# insert into money_test values (1 ,20);
INSERT 0 1
postgres=# select * from money_test;
 id | money  
----+--------
  1 | $20.00
(1 row)
复制代码
NameStorage SizeDescriptionRange
money8 bytescurrency amount-92233720368547758.08 to +92233720368547758.07

由于此数据类型的输出对语言环境敏感,因此将“ money”数据加载到具有“ lc_monetary”不同设置的数据库中可能不起作用。 为了避免出现问题,在将转储恢复到新数据库之前,请确保“ lc_monetary”具有与转储数据库中相同或相等的值。

set lc_monetary='zh_CN';
show lc_monetary;

 

可以将“ numeric”,“ int”和“ bigint”数据类型的值强制转换为“ money”。 从“ real”和“ double precision”数据类型的转换可以通过首先转换为“ numeric”来完成,例如:

postgres=# SELECT '12.34'::float8::numeric::money;
money
--------
$12.34
(1 row)

但是,不建议这样做。 由于可能会舍入错误,因此不应使用浮点数来处理资金。

可以将“ money”值转换为“ numeric”而不会损失精度。 转换为其他类型可能会失去精度,并且必须分两个阶段完成:

SELECT '52093.89'::money::numeric::float8;

将“货币”值除以整数值的过程是将小数部分截断为零。 要获得四舍五入的结果,请除以浮点值,或将“ money”值转换为“ numeric”,然后除以,然后再返回至“ money”。 (最好避免使用后者,以免损失精度。)将“货币”值除以另一个“货币”值时,结果是“双精度”(即纯数字,而不是货币);

8.3.字符串类型

NameDescription
character varying(n)varchar(n)variable-length with limit
character(n)char(n)fixed-length, blank padded
textvariable unlimited length

PostgreSQL提供了“text”文本类型,该类型存储任何长度的字符串。

短字符串(最多126个字节)的存储要求是1个字节加上实际字符串,如果是'character',则包括空格。较长的字符串的开销为4个字节,而不是1个字节。较长的字符串由系统自动压缩,因此对磁盘的物理需求可能会更少。非常长的值也存储在后台表中,这样它们就不会干扰对较短列值的快速访问。在任何情况下,可以存储的最长字符串约为1 GB。 (数据类型声明中允许n 的最大值小于该值。更改此值无用,因为对于多字节字符编码,字符和字节数可以如果您希望存储没有特定上限的长字符串,请使用不带长度说明符的“文本”或“字符变化”,而不是设置任意长度限制。)

这三种类型之间没有性能差异,除了使用空白填充类型时增加了存储空间,只不过存在长度受限,尽管在其他一些数据库系统中,“ char(n)”具有性能上的优势,但在PostgreSQL中却没有这种优势。实际上,“char(n)”通常是三个字符中最慢的一个,因为它会增加存储成本。在大多数情况下,应改用“text”或“varchar”。

复制代码
postgres=# CREATE TABLE test1 (a character(4));
CREATE TABLE
postgres=# 
postgres=# INSERT INTO test1 VALUES ('ok');
INSERT 0 1
postgres=# SELECT a, char_length(a) FROM test1; -- (1)
  a   | char_length 
------+-------------
 ok   |           2
(1 row)

 
postgres=# CREATE TABLE test2 (b varchar(5));
CREATE TABLE
postgres=# INSERT INTO test2 VALUES ('ok');
INSERT 0 1
postgres=# 
postgres=# INSERT INTO test2 VALUES ('good   ');
INSERT 0 1
postgres=# 
postgres=# INSERT INTO test2 VALUES ('too long');
ERROR:  value too long for type character varying(5)

INSERT INTO test2 VALUES ('too long'::varchar(5)); -- explicit truncation

SELECT b, char_length(b) FROM test2;

 
  b    | char_length
-------+-------------
 ok    |      2
 good  |      5
 too l |      5
 
复制代码

 

PostgreSQL中还有另外两种定长字符类型。名称类型仅存在于内部系统目录中,用于存储标识符,不适合普通用户使用。 目前,它的长度定义为64个字节(63个可用字符加终止符),但应使用C源代码中的常量“ NAMEDATALEN”来引用。 该长度是在编译时设置的(因此对于特殊用途可以调整); 默认的最大长度可能会在将来的版本中更改。 “ char”类型(请注意引号)与“ char(1)”不同之处在于它仅使用一个字节的存储空间。 在系统目录中内部使用它作为一种简单的枚举类型。

NameStorage SizeDescription
"char"1 bytesingle-byte internal type
name64 bytesinternal type for object names
©小网格工作室 2013-2025