1. 程式人生 > 實用技巧 >PostgreSQL的資料型別

PostgreSQL的資料型別

1.1 資料型別

PostgreSQL有著豐富的資料型別可用。 使用者可以使用CREATE TYPE命令為PostgreSQL增加新的資料型別。

Table1-1顯示了所有內建的普通資料型別。 在"別名"列裡列出的大多數可選名字都是因歷史原因PostgreSQL在內部使用的名字。

另外,還有一些內部使用的或者廢棄的型別也可以用,但沒有在這裡列出。

Table1-1: 資料型別

名字別名描述
bigint int8 有符號 8 位元組整數
bigserial serial8 自增八位元組整數
bit [ (n) ] 定長位串
bit varying [ (n) ] varbit
變長位串
boolean bool 邏輯布林量 (真/假)
box 平面中的長方形
bytea 二進位制資料("位元組陣列")
character varying [ (n) ] varchar [ (n) ] 變長字串
character [ (n) ] char [ (n) ] 定長字串
cidr IPv4 或者 IPv6 網路地址
circle 平面中的圓
date 日曆日期(年,月,日)
double precision float8 雙精度浮點數字
inet IPv4 或者 IPv6 網路地址
integer intint4 四位元組長有符號整數
interval [ (p) ] 時間間隔
line 平面中的無限長直線
lseg 平面中的線段
macaddr MAC 地址
money 貨幣金額
numeric [ (p,s) ] decimal [ (p,s) ] 可選精度的準確數字
path 平面中的幾何路徑
point 平面中的點
polygon 平面中的封閉幾何路徑
real float4 單精度浮點數
smallint int2 有符號兩位元組整數
serial serial4 自增四位元組整數
text 變長字串
time [ (p) ] [ without time zone ]
一天裡的時間
time [ (p) ] with time zone timetz 一天裡的時間,包括時區
timestamp [ (p) ] [ without time zone ] 日期和時間
timestamp [ (p) ] with time zone timestamptz 日期和時間

相容性:下列型別(或者那樣拼寫的)是SQL宣告的:bitbit varyingbooleancharcharactercharacter varyingvarchardatedouble precisionintegerintervalnumericdecimalrealsmallinttime(包括有時區和無時區的),timestamp(包括有時區和無時區的)。

每種資料型別都有一個由其輸入和輸出函式決定的外部表現形式。 許多內建的型別有明顯的格式。不過,許多型別要麼是PostgreSQL所特有的,比如幾何路徑,要麼可能是有幾種不同的格式,比如日期和時間型別。 有些輸入和輸出函式是不可逆的。也就是說,輸出函式的輸出結果和原始的輸入比較的時候可能丟失精度。

1.2 數值型別

數值型別由2、4或8位元組的整數以及4或8位元組的浮點數和可選精度小陣列成。Table 1-2列出了所有可用型別。

Table 1-2. 數值型別

名字儲存空間描述範圍
smallint 2 位元組 小範圍整數 -32768 到 +32767
integer 4 位元組 常用的整數 -2147483648 到 +2147483647
bigint 8 位元組 大範圍的整數 -9223372036854775808 到 9223372036854775807
decimal 變長 使用者宣告精度,精確 無限制
numeric 變長 使用者宣告精度,精確 無限制
real 4 位元組 變精度,不精確 6 位十進位制數字精度
double precision 8 位元組 變精度,不精確 15 位十進位制數字精度
serial 4 位元組 自增整數 1 到 +2147483647
bigserial 8 位元組 大範圍的自增整數 1 到 9223372036854775807

1.2.1. 整數型別

型別smallintinteger,和bigint儲存各種範圍的全部是數字的數,也就是沒有小數部分的數字。 試圖儲存超出範圍以外的數值將導致一個錯誤。

常用的型別是integer,因為它提供了在範圍,儲存空間, 和效能之間的最佳平衡。一般只有在磁碟空間緊張的時候才使用smallint。而只有在integer的範圍不夠的時候才使用bigint,因為前者絕對快得多。

bigint型別可能不是在所有平臺上都運轉正確, 因為它依賴編譯器對八位元組整數的支援。在那些沒有這樣支援的機器上,bigint的作用和integer一樣(但是仍然佔據八位元組儲存)。

SQL只聲明瞭整數型別integer(或int)和smallint。型別bigint,和型別名int2int4,和int8都是擴充套件, 也在許多其它SQL資料庫系統中使用。

1.2.2. 任意精度數值

型別numeric可以儲存最多1000位精度的數字並且準確地進行計算。 我們特別建議將它用於貨幣金額和其它要求計算準確的數量。不過,numeric型別上的算術運算比整數型別或者我們下一節描述的浮點數型別要慢很多。

在隨後的內容裡,我們使用了下述術語: 一個numeric比例是到小數點右邊為止小數部分的位數,numeric精度是整個數字裡全部資料位的數目,也就是小數點兩邊的資料數目。 因此數字 23.5141 的精度為6而比例為4。你可以認為整數的比例為零。

numeric欄位的最大精度和最大比例都是可以配置的。要宣告一個型別為numeric的欄位,你可以用下面的語法

NUMERIC(precision, scale)

精度必須為正數,比例可以為零或者正數。 另外,

NUMERIC(precision)

選擇了 0 為比例。不帶任何精度或者比例宣告

NUMERIC

則建立一個可以儲存一個直到實現精度上限的任意精度和比例的數值, 一個這樣型別的欄位將不會把輸入數值轉化成任何特定的比例, 而帶有比例宣告的numeric欄位將把輸入值轉化為該比例。 (SQL標準要求預設的比例是 0。也就是轉化成整數精度。 我們覺得這樣做有點沒用。如果你關心移植性,那你最好總是明確宣告精度和比例。)

如果一個要儲存的數值的比例比欄位宣告的比例高, 那麼系統將嘗試圓整(四捨五入)該數值到指定的小數位。 然後,如果小數點左邊的資料位數超過了宣告的精度減去宣告的比例, 那麼丟擲一個錯誤。

數值資料值物理上是不帶任何前導或者字尾零的形式儲存的。 因此,欄位上宣告的精度和比例都是最大值,而不是固定分配的。 (在這個方面,numeric型別更類似於varchar(n), 而不像char(n)。) 實際儲存是每四個十進位制位兩個位元組,然後在整個資料上加上八個位元組的額外開銷。

除了普通的數字值之外,numeric型別允許特殊值NaN, 表示"不是一個數字"。任何在NaN上面的操作都生成另外一個NaN。 如果在 SQL 命令裡把這些值當作一個常量寫,你必須在其周圍放上單引號,比如UPDATE table SET x = 'NaN'。在輸入時,字串NaN當作大小寫無關看待。

型別decimalnumeric是等效的。 兩種型別都是SQL標準。

1.2.3. 浮點數型別

資料型別realdouble precision是不準確的,變精度的數字型別。 實際上,這些型別是IEEE標準 754 二進位制浮點數算術(分別對應單和雙精度)的一般實現, 外加下層處理器,作業系統和編譯器對它的支援。

不準確意味著一些數值不能準確地轉換成內部格式並且是以近似的形式儲存的,因此儲存然後把資料再打印出來可能顯示一些缺失。 處理這些錯誤以及這些錯誤是如何在計算中傳播的屬於數學和電腦科學的一個完整的分支, 這裡的討論僅限於如下幾點:

  • 如果你要求準確的計算(比如計算貨幣金額),應使用numeric型別。

  • 如果你想用這些型別做任何重要的複雜計算,尤其是那些你對範圍情況(無窮,下溢)嚴重依賴的事情,那你應該仔細評詁你的實現。

  • 拿兩個浮點數值進行相等性比較可能象,也可能不象想像那樣運轉。

通常,real型別的範圍是至少 -1E+37 到 +1E+37, 精度至少是 6 位小數。double precision型別通常有 -1E+308 到 +1E+308 的範圍,精度是至少 15 位數字。太大或者太小的數值都會導致錯誤。 如果輸入資料太高,那麼可能發生園整。太接近零的數字,如果無法與零值的表現形式相區分就會產生下溢錯。

除了普通的數字值之外,浮點型別還有幾個特殊值:

Infinity
-Infinity
NaN
這些值分別表示 IEEE 754 特殊值"正無窮大","負無窮大", 以及"不是一個數字"。(在不遵循 IEEE 754 浮點算術的機器上,這些值的含義可能不是預期的。) 如果在 SQL 命令裡把這些數值當作常量寫,你必須在它們周圍放上單引號, 像這樣UPDATE table SET x = 'Infinity'。 輸入時,這些值是以大小寫無關的方式識別的。

PostgreSQL還支援 SQL 標準表示法floatfloat(p)用於宣告非精確的數值型別。 在這裡,p宣告以二進位制位表示的最低可接受精度。 在選取real型別的時候,PostgreSQL接受float(1)float(24),在選取double precision的時候,接受float(25)float(53)。在允許範圍之外的p值將導致一個錯誤。 沒有宣告精度的float將被當作是double precision

注意:PostgreSQL7.4 以前,在float(p)裡面的精度會被當作是這麼多位數的十進位制位。到 7.4 已經被修改成與 SQL 標準匹配,標準宣告這個精度是以二進位制位度量的。假設realdouble precision分別有 24 和 53 個二進位制位的位數對 IEEE 標準的浮點實現來說是正確的。 在非 IEEE 平臺上,這個數值可能略有偏差,但是為了簡化,我們在所有平臺上都用了同樣的p值範圍。

1.2.4. Serial(序號)型別

serialbigserial型別不是真正的型別, 只是為在表中設定唯一標識做的概念上的便利。(類似其它一些資料庫中的AUTO_INCREMENT屬性)。 在目前的實現中,下面一句話:

CREATE TABLE tablename (
    colname SERIAL
);

等價於宣告下面幾句話:

CREATE SEQUENCE tablename_colname_seq;
CREATE TABLE tablename(
    colname integer DEFAULT nextval('tablename_colname_seq') NOT NULL
);

因此,我們就建立了一個整數字段並且把它的預設數值安排為從一個序列發生器取值。 應用了一個NOT NULL約束以確保空值不會被明確地插入。 在大多數情況下你可能還希望附加一個UNIQUE或者PRIMARY KEY約束避免意外地插入重複的數值,但這個不是自動發生的。

注意:PostgreSQL7.3 以前,serial隱含UNIQUE。但現在不再如此。 如果你希望一個序列欄位有一個唯一約束或者一個主鍵,那麼你現在必須宣告,就像其它資料型別一樣。

要使用serial欄位插入序列的下一個數值到表中, 主要是要注意serial應該賦予預設值。 我們可以通過在INSERT語句中把該欄位排除在欄位列表之外來實現, 也可以通過使用DEFAULT關鍵字來實現。

型別名serialserial4是等效的: 兩個都建立integer欄位。型別名bigserialserial8也一樣,只不過它建立一個bigint欄位。 如果你預計在表的生存期中使用的標識數目超過 231個,那麼你應該使用bigserial

一個serial型別建立的序列在所屬的欄位被刪除的時候自動刪除,其它情況下是不會被刪除的。 (這一點在PostgreSQL版本 7.3 之前可不是真的。請注意,這種自動刪除的關聯在通過過載 7.3 以前的資料庫轉儲的時候可不會自動發生; 那樣的轉儲檔案不包含需要建立這種關聯關係的資訊。) 另外,這樣的序列和欄位之間的依賴性只在serial欄位本身上有; 如果任何其它欄位引用了序列(可能是手工呼叫nextval函式), 那麼,如果這個序列被刪除了,它們就會被破壞。我們認為這樣使用serial欄位是一種不好的形式;如果你想用同一個序列發生器給幾個欄位喂資料,那麼還是把序列發生器作為獨立物件建立。