PostgreSQL資料型別
第六章 資料型別
6.1概述
PostgreSQL提供了豐富的資料型別。使用者可以使用 CREATE TYPE 命令在資料庫中建立新的資料型別。PostgreSQL 的資料型別被分為四種,分別是基本資料型別、複合資料型別、域和偽型別。
基本資料型別是資料庫內建的資料型別,包括integer、char、varchar等資料型別。表6-1列出了PostgreSQL提供的所有基本資料型別。複合資料型別是使用者自己定義的,使用CREATE TYPE命令就能建立一個複合資料型別。域是一種特殊的基本資料型別,它由基本資料型別加上一個約束條件構成,使用CREATE DOMAIN
下面的小節將會詳細介紹基本資料型別、複合資料型別和偽型別。
表 6-1. 基本資料型別
名字 |
描述 |
bigint |
有符號 8 位元組整數 |
bigserial |
自增八位元組整數 |
bit [ (n) ] |
定長位串 |
bit varying [ (n |
變長位串 |
boolean |
邏輯布林量 (真/假) |
box |
平面中的長方形 |
bytea |
二進位制資料("位元組陣列") |
character varying [ (n) ] |
變長字串 |
character [ (n) ] |
定長字串 |
cidr |
IPv4 或者 IPv6 網路地址 |
circle |
平面中的圓 |
date |
日曆日期(年,月,日) |
double precision |
雙精度浮點數字 |
inet |
IPv4 或者 IPv6 網路地址 |
integer |
四位元組長有符號整數 |
interval [ (p) ] |
時間間隔 |
line |
平面中的無限長直線 |
lseg |
平面中的線段 |
macaddr |
MAC 地址 |
numeric [ (p, s) ] |
可選精度的準確數字 |
path |
平面中的幾何路徑 |
point |
平面中的點 |
polygon |
平面中的封閉幾何路徑 |
real |
單精度浮點數 |
smallint |
有符號兩位元組整數 |
serial |
自增四位元組整數 |
text |
變長字串 |
time [ (p) ] [ without time zone ] |
一天裡的時間 |
time [ (p) ] with time zone |
一天裡的時間,包括時區 |
timestamp [ (p) ] [ without time zone ] |
日期和時間 |
timestamp [ (p) ] with time zone |
日期和時間 |
tsquery |
全文檢索查詢 |
tsvector |
全文檢索文件 |
txid_snapshot |
使用者級別事務ID快照 |
uuid |
通用唯一識別符號 |
xml |
XML資料 |
相容性: 下列型別是在SQL標準中定義的: bit,bit varying,boolean,char,character,character varying,varchar,date, double precision,integer,interval,numeric,decimal, real,smallint,time(包括有時區和無時區的), timestamp(包括有時區和無時區的)。
PostgreSQL的詞法分析器在解析使用者發出的SQL命令時,首先將其中的單詞分成五類:整數、非整數數字、字串、識別符號和關鍵字。大部分的非數值常量首先被認為是字串。
SQL語言提供了明確地指定字串的型別的機制。例如:
SELECT 'Origin':: text AS "label", '(0,0)':: point AS "value";
label | value
--------+-------
Origin | (0,0)
(1 row)
在上面的例子中,使用者指定'Origin' 的型別是text,'(0,0)'的型別是 point。如果使用者沒有明確地指定和'Origin'和'(0,0)'的資料型別,系統先把它們的型別設為unknown,以後再確定它們的具體資料型別。
6.2 數值型別
數值型別包括2、4或8位元組的整數,4或8位元組的浮點數和可以定義精度的十進位制數。 表6-2 列出了所有數值型別。
表6-2. 數值型別
名字 |
儲存空間 |
描述 |
取值區間 |
smallint |
2 位元組 |
小整數 |
-32768 到 +32767 |
integer |
4 位元組 |
常用的整數 |
-2147483648 到 +2147483647 |
bigint |
8 位元組 |
大整數 |
-9223372036854775808 到9223372036854775807 |
decimal |
變長 |
使用者定義精度,可以精確地表示小數 |
無限制 |
numeric |
變長 |
使用者定義精度,可以精確地表示小數 |
無限制 |
real |
4 位元組 |
精度可變,不能精確地表示小數 |
精度是6個十進位制位 |
double precision |
8 位元組 |
精度可變,不能精確地表示小數 |
精度是15個十進位制位 |
serial |
4 位元組 |
小範圍的自增整數 |
大範圍的自增整數 |
bigserial |
8 位元組 |
大範圍的自增整數 |
1 到 9223372036854775807 |
數值型別常量的語法在第1.4.4節裡描述。 數值型別有一套完整的數學運算子和函式。相關資訊請參考第7章。下面將詳細描述這些型別。
6.2.1 整數型別
型別 smallint、integer和 bigint只能儲存整數,也就是沒有小數部分的數字。如果試圖在一個整數型別中儲存一個超過它能夠表示的值範圍的整數,資料庫將會報錯。
常用的型別是integer,因為它提供了在表示範圍、儲存空間和效能之間的最佳平衡。只有在磁碟空間緊張的情況下才使用 smallint。只有在 integer太小的時候才使用 bigint,因為在進行數學運算時,interger型別的資料bigint型別的資料要快。
SQL標準只定義了整數型別 integer(或int)、smallint和bigint。
6.2.2 任意精度數值
numeric型別最多能儲存有1000個數字位的數字並且能進行準確的數值計算。它主要用於需要準確地表示數字的場合,如貨幣金額。不過,對numeric 型別進行算術運算比整數型別和浮點型別要慢很多。
numeric型別有兩個術語,分別是標度和精度。numeric型別的標度(scale)是到小數點右邊所有小數位的個數, numeric 的精度(precision)是所有數字位的個數,因例如, 23.5141 的精度是6而標度為4。可以認為整數的標度是零。
numeric 型別的最大精度和最大標度都是可以配置的。可以用下面的語法定義一個numeric型別:
(1)NUMERIC(precision, scale)
(2)NUMERIC(precision)
(3)NUMERIC
精度必須為正數,標度可以為零或者正數。在上面的第二種語法中沒有指定標度,則系統會將標度設為0,所以NUMERIC(precision,0)和 NUMERIC(precision)是等價的。第三種類型的語法沒有指定精度和標度,則這種型別的列可以接受任意精度和標度的numeric資料(在系統能表示的最大精度範圍內),而不會對輸入的資料進行精度或標度的變換。如果一個列被定義成numeric型別而且指定了標度,那麼輸入的資料將被強制轉換成這個標度(如果它的標度比定義列的numeric的標度大),進行標度轉換時的規則是四捨五入。如果輸入的資料進行標度轉換後得到的資料在小數點左邊的資料位的個數超過了列的型別的精度減去標度的差,系統將會報告類似下面的錯誤:
錯誤: numeric型別資料溢位。
細節: precision為3, scale為3的數必須被四捨五入成小於1的數。
下面是一個例項:
create table test ( col1 numeric(3,3));
insert into test values(0.5678);
insert into test values(0.5671);
insert into test values ( 1.4);
錯誤: numeric型別資料溢位。
細節: precision為3, scale為3的數必須被四捨五入成小於1的數。
=>select * from test;
col1
-------
0.568
0.567
(2 rows)
numeric 型別接受一個特殊的值 “NaN”,它的意思是“不是一個數字"。任何在 NaN 上面的操作都生成另外一個 NaN。 如果在 SQL 命令裡把這些值當作一個常量寫,必須把它用單引號引起來,比如 UPDATE table SET x = 'NaN'。在輸入時,”NaN”的大小寫無關緊要。
注意:在其它的資料庫中,NaN和任何的數值資料都不相等,兩個NaN也是不相等的,在postgresSQL中,為了索引實現的方便,NaN被看成大於或等於所有非NaN的數值。
型別 decimal和numeric是等價的,兩種型別都是SQL標準定義的,SQL標準要求numeric的預設精度應該是0,PostgreSQL沒有執行這個規則,為了增強程式的移植性,最好同時指定numeric的精度和標度。
6.2.3 浮點型別
資料型別 real 和 double precision 表示不準確的變精度的數字。這些型別實現了IEEE 標準754二進位制浮點數算術(分別對應單精度和雙精度)。
不準確的意思是一些數值不能準確地用real和double precision表示,儲存在資料庫裡的只是它們的近似值。如果要求準確地儲存某些數值(比如計算貨幣金額),應使用 numeric 型別。另外,比較兩個浮點數是否相等時,可能會得到意想不到的結果。
通常,real 型別的表示的數值範圍是至少-1E+37到+1E+37,精度至少是6位小數。double precision 型別表示的範圍通常是-1E+308到+1E+308 ,精度是至少15位小數。太大或者太小的數值都會導致錯誤。如果輸入資料的精度太高,會被約成可以被接受的精度。太接近零的數字,如果和0的內部表示形式一樣,會產生下溢(underflow)的錯誤。
浮點型別還有幾個特殊值:
Infinity
-Infinity
NaN
這些值分別表示 IEEE 754標準中的特殊值"正無窮大","負無窮大", 以及"不是一個數字"。如果在 SQL 命令裡把這些數值當作常量寫,必須在它們用單引號引起來,例如UPDATE table SET x = 'Infinity'。 輸入時,這些值的大小寫無關緊要。
注意:IEEE 754標準要求NaN和任何的數值資料都不相等,兩個NaN也是不相等的,在postgresSQL中,為了索引實現的方便,NaN被看成大於或等於所有非NaN的數值。
PostgreSQL 還支援 SQL 標準中定義的型別float和float(p)。p 定義以二進位制位表示的最低可以接受的精度,p的取值在1到53之間。實際上,如果p的取值在1到24之間,float(p)被看成是real型別,如果p的取值在25到53之間,float(p)被看成是double precision型別。不帶精度的float被看成是double precision型別。
6.2.4 序列號型別(Serial)
serial 和 bigserial 並不是真正的資料型別,只是為了可以給表中的資料行設定一個唯一的標識。它類似其它一些資料庫中的 AUTO_INCREMENT 屬性。使用它們的方法如下:
CREATE TABLE tablename (
colname SERIAL
);
上面的命令實際上上等價於下面的兩條命令:
CREATE SEQUENCE tablename_colname_seq;
CREATE TABLE tablename(
colname integer DEFAULT nextval('tablename_colname_seq') NOT NULL
);
上面的命令在表中建立了一個型別為無符號整數的列,該列與一個序列物件相關聯,這個序列物件的初始值是1, 表中每插入一條新的記錄,該序列的值會自動加一,在向表中插入資料時,INSERT命令不要為該列指定資料,或者指定它的值為DEFAULT。
下面是一個例項:
create table test3 ( product_id serial, name char(5));
insert into test3(name) values('pen');
insert into test3(name) values('car');
insert into test3 values(DEFAULT, 'bike');
=>select * from test3;
product_id | name
------------+-------
1 | pen
2 | car
3 | bike
(3 rows)
注意:insert命令中一定不要為serial或bigserial型別的列指定一個不是DEFAULT的值,因為對於這樣的命令系統是不會報錯的,會導致serial或bigserial型別的列上的數值出現混亂。
6.3 字元型別
表 6-3. 字元型別
名字 |
描述 |
character varying(n), varchar(n) |
變長,最大長度有限制 |
character(n), char(n) |
定長, 不足補空白 |
text |
變長,最大長度沒有限制 |
表6-3列出了PostgresSQL中可以使用的字元型別。
SQL標準定義了兩種基本的字元型別:character varying(n) 和 character(n),這裡的n是一個正整數。兩種型別最多可以儲存n個字元。試圖儲存更長的字串到這些型別的列裡,系統會報錯,除非所有超出長度n的字元都是空格(這種情況下該字串將被截斷成長度為n的字串)。如果要儲存的字串的長度比n小,型別為 character的列將自動用空格填充該字串,使它的長度達到n,而型別為 character varying 的列直接儲存該字串,不會對它進行任何處理。
如果明確將把一個數值轉換成character(n)或者 character varying(n)型別,如果轉換以後的字串的長度超過n,那麼它將被自動截斷成長度為n的字串,系統不會報錯(這也是SQL標準要求的)。
char(n) 和 varchar(n) 分別是 character(n)和character varying(n)的別名。沒有定義長度的character等同於 character(1)。沒有定義長度的character varying型別接受任意長度的字串,這是PostgreSQL的擴充套件特性。
另外,PostgreSQL 提供了text型別,它可以儲存任意長度的字串,而且長度沒有最大限制。儘管SQL標準中沒有定義text型別,但許多其它 SQL 資料庫系統中有這個型別。
character(n)型別的資料在儲存時長度不足n的字串會用空格填充,在顯示資料時也會把填充的空格顯示出來,但是在比較兩個character型別的值的時候,字串的所有結尾空格符號將自動被忽略,在轉換成其它字串型別的時候,character型別的值裡面結尾的空格字元都會被刪除。請注意,對於 character varying 和 text型別的值,結尾的空格在處理時是不會被忽略的。
對於character(n) 和 character varying(n)型別,允許儲存的最長字串所佔的儲存空間大概1GB。如果想儲存長度沒有上限的長字串,那麼使用 text型別或者沒有指定長度的character varying。
提示: 這三種資料型別之間沒有效能差別,不過character(n)比character varying(n)型別多使用了物理儲存空間。 雖然在某些其它的資料庫系統裡,character(n) 比character varying(n)快一些, 但在 PostgreSQL 裡沒有這種情況。在大多數情況下,應該使用text或者character varying。
請參考第1.4.1節和1.4.2節得到字串常量的的語法資訊,參考第7.4節得到處理字串的運算子和函式的資訊。資料庫的字符集決定用於儲存文字值的字符集,有關字符集的詳細資訊,請參考《資料庫管理員指南》第5章。
下面是一個使用字串的例項:
CREATE TABLE test1 (a character(4));
INSERT INTO test1 VALUES ('ok');
INSERT INTO test1 VALUES ('ok '); --ok後面跟了一個空格
SELECT a, char_length(a) FROM test1; --函式char_length
在
第7.4節中有詳細介紹.
a | char_length
------+-------------
ok | 2
ok | 2
(2 rows)
CREATE TABLE test2 (b varchar(5));
INSERT INTO test2 VALUES ('ok');
INSERT INTO test2 VALUES ('good ');
INSERT INTO test2 VALUES ('too long');
錯誤: 輸入的字串對於型別character varying(5)來說過長。
INSERT INTO test2 VALUES ('too long'::varchar(5)); -- 截斷字串
SELECT b, char_length(b) FROM test2;
b | char_length
-------+-------------
ok | 2
good | 5
too l | 5
在 PostgreSQL 還有另外兩種定長字串型別,在表6-4 裡顯示。這兩種型別是供系統內部使用的,應用程式不應該使用這兩種型別。name型別長度當前定為 64 位元組(63 可用字元加上結束符)。型別"char"(注意引號)和char(1)是不一樣的,它只佔一個位元組的儲存空間,它在系統內部當列舉型別用。
表6-4。 特殊字元型別
名字 |
儲存空間 |
描述 |
"char" |
1 位元組 |
單位元組內部型別 |
name |
64 位元組 |
物件名的內部型別 |
6.4 二進位制資料型別
bytea 型別可以儲存二進位制字串,如表6-5所示。
表6-5. 二進位制資料型別
名字 |
儲存空間 |
描述 |
bytea |
1或4 位元組加上實際的二進位制字串 |
變長的二進位制字串 |
二進位制字串是一個位元組數值的序列。SQL 標準定義了一種不同的二進位制字串型別,叫做 BLOB 或者BINARY LARGE OBJECT,其輸入格式和 bytea 不同,但是提供的函式和操作符大多一樣。bytea型別資料的具體含義由應用程式自己決定,資料庫也提供了和普通文字字串的處理方式類似的方法來對bytea型別資料進行輸入和輸出。
可以使用字串常量的語法來輸入bytea型別的資料,對特殊的字元如單引號、反斜槓、不可列印的字元以及0,要使用轉義表示法,具體用法如表6-6所示。
表6-6. 需要進行轉義處理的字元
十進位制數值 |
描述 |
輸入格式 |
例子 |
輸出格式 |
0 |
零 |
'//000' |
select '//000'::bytea; |
/000 |
39 |
單引號 |
'/'' 或者 '//047' |
select '/''::bytea; |
' |
92 |
反斜槓 |
'////' 或者 '//134' |
select '////'::bytea; |
// |
0 到 31 和 127 到255 |
不可列印的字元 |
'//xxx' (八進位制值) |
SELECT '//001'::bytea; |
/001 |
bytea型別的資料在輸出時也要進行轉義處理,反斜槓用兩個反斜槓表示,不可列印的字元用反斜槓加上表示它們的值的三個八進位制位表示,可列印的字元用它們自身表示。如表6-7所示。
表6-7. bytea輸出格式
十進位制數值 |
描述 |
轉義以後的輸出個數 |
例子 |
輸出結果 |
92 |
反斜槓 |
// |
select '//134'::bytea; |
// |
0 到31和127到255 |
不可列印的八進位制字元 |
/xxx(octal value) |
select '//001'::bytea; |
/001 |
32 到126 |
可列印的八進位制字元 |
客戶端字符集表現形式 |
(1)select '//175'::bytea; (2)select '//165//166'::bytea |
(1)} (2)uv |
6.5 日期/時間型別
PostgreSQL支援 SQL標準中所有的日期和時間型別,如表6-8所示。這些資料型別上可以進行的操作在第7.9節裡描述。
表6-8. 日期/時間型別
名字 |
儲存空間大小 |
描述 |
最小值 |
最大值 |
解析度 |
timestamp [ (p) ] [ without time zone ] |
8 bytes |
包括日期和時間 |
4713 BC |
294276 AD |
1微妙/ 14 位 |
timestamp [ (p) ] with time zone |
8 bytes |
包括日期和時間,帶時區 |
4713 BC |
294276 AD |
1微妙/ 14 位 |
interval [ (p) ] |
12 bytes |
時間間隔 |
-178000000 年 |
178000000 年 |
1微妙/ 14 位 |
date |
4 bytes |
只有日期 |
4713 BC |
5874897 AD |
1 天 |
time [ (p) ] [ without time zone ] |
8 bytes |
只有時間 |
00:00:00 |
24:00:00 |
1微妙/ 14 位 |
time [ (p) ] with time zone |
12 bytes |
只有時間,帶時區 |
00:00:00+1459 |
24:00:00-1459 |
1微妙/ 14 位 |
time、timestamp 和interval可以定義精度值p,這個精度值定義用來表示秒的小數位的個數,預設的情況下,沒有精度限制。對於timestamp和interval,p的取值範圍是0到6(實際的精度可能小於6)。對於time,p的取值範圍是0到10。
型別time with time zone是SQL標準定義的,這個型別有些多餘。在大多數情況下,date、time、timestamp without time zone 和 timestamp with time zone 的組合就能滿足任何應用需求。
型別 abstime和reltime 是低解析度時間型別,它們是資料庫內部使用的型別,在應用程式裡面不應該使用這兩個型別。
6.5.1 日期/時間輸入
日期和時間可以用多種格式來表示,包括 ISO 8601、SQL標準中定義的格式等。對於一些格式,日期輸入裡的月和天的表示可能會有歧義,如果引數DateStyle被設定為 MDY,資料庫將按“月-日-年”的格式來解釋輸入的資料,DMY 表示“日-月-年”,而 YMD表示“年-月-日”。
PostgreSQL在處理日期/時間輸入上比SQL標準要靈活得多。像一個文字字串一樣,任何日期或時間的輸入都必須用單引號括起來。SQL標準定義的語法如下:
type [ (p) ] 'value'
對於time、timestamp和 interval型別的資料可以指定精度p,p的取值範圍上一節已經講過。如果沒有定義p,預設是輸入的時間常量的精度。 表6-9、6-10和6-11列出了日期/時間資料在輸入和輸出時使用的關鍵字。
表6-9. 表示月的關鍵字
月 |
縮寫 |
January |
Jan |
February |
Feb |
March |
Mar |
April |
Apr |
May |
|
June |
Jun |
July |
Jul |
August |
Aug |
September |
Sep, Sept |
October |
Oct |
November |
Nov |
December |
Dec |
表6-10. 表示天的關鍵字
天 |
縮寫 |
Sunday |
Sun |
Monday |
Mon |
Tuesday |
Tue, Tues |
Wednesday |
Wed, Weds |
Thursday |
Thu, Thur, Thurs |
Friday |
Fri |
Saturday |
Sat |
表6-11. 日期/時間域修飾符
識別符號 |
描述 |
ABSTIME |
忽略 |
AM |
12:00以前的時間 |
AT |
忽略 |
JULIAN, JD, J |
下一個域用儒略日表示(Julian Day) |
ON |
忽略 |
PM |
12:00以後的時間 |
T |
下一個域是時間 |
6.5.1.1 日期
表6-12 顯示了date 型別可能的輸入格式。
表6-12. 日期格式
例子 |
描述 |
January 8, 1999 |
無論引數datestyle取任何值,都沒有歧義 |
1999-01-08 |
ISO-8601 格式,任何模式下都是1999年1月8號(推薦使用該格式) |
1/8/1999 |
有歧義,在MDY下是1月8日;在 DMY模式下是做8月1日 |
1/18/1999 |
在MDY模式下是1月18日,其它模式下被拒絕 |
01/02/03 |
MDY模式下的2003年一月2日; DMY模式下的 2003 年 2月 1日; YMD模式下的2001年二月三日 |
1999-Jan-08 |
任何模式下都是1月8日 |
Jan-08-1999 |
任何模式下都是1月8日 |
08-Jan-1999 |
任何模式下都是1月8日 |
99-Jan-08 |
在 YMD模式下是1月8日,其它模式報錯 |
08-Jan-99 |
1月8日,YMD模式下會報錯 |
Jan-08-99 |
1月8日,YMD模式下會報錯 |
19990108 |
ISO-8601; 任何模式下都是1999年1月8日 |
990108 |
ISO-8601; 任何模式下都是1999年1月8日 |