PostgreSQL 資料型別

PostgreSQL 資料型別

本章節,我們將討論 PostgreSQL 的資料型別,資料型別是我們在建立表的時候為每個欄位設定的。

設定資料型別的好處:

PostgreSQL提 供了豐富的資料型別。使用者可以使用 CREATE TYPE 命令在資料庫中建立新的資料型別。PostgreSQL 的資料型別有很多種,下面我們具體來說明。


數值型別

數值型別由 2 位元組、4 位元組或 8 位元組的整數以及 4 位元組或 8 位元組的浮點數和可選精度的十進位制陣列成。

下表列出了可用的數值型別。

名字儲存長度描述範圍
smallint2 位元組小範圍整數-32768 到 +32767
integer4 位元組常用的整數-2147483648 到 +2147483647
bigint8 位元組大範圍整數-9223372036854775808 到 +9223372036854775807
decimal可變長使用者指定的精度,精確小數點前 131072 位;小數點後 16383 位
numeric可變長使用者指定的精度,精確小數點前 131072 位;小數點後 16383 位
real4 位元組可變精度,不精確6 位十進位制數字精度
double precision8 位元組可變精度,不精確15 位十進位制數字精度
smallserial2 位元組自增的小範圍整數1 到 32767
serial4 位元組自增整數1 到 2147483647
bigserial8 位元組自增的大範圍整數1 到 9223372036854775807

貨幣型別

money 型別儲存帶有固定小數精度的貨幣金額。

numeric、int 和 bigint 型別的值可以轉換為 money,不建議使用浮點數來處理處理貨幣型別,因為存在舍入錯誤的可能性。

名字儲存容量描述範圍
money8 位元組貨幣金額-92233720368547758.08 到 +92233720368547758.07

字元型別

下表列出了 PostgreSQL 所支援的字元型別:

序號 名字 & 描述
1

character varying(n), varchar(n)

變長,有長度限制

2

character(n), char(n)

f定長,不足補空白

3

text

變長,無長度限制


日期/時間型別

下表列出了 PostgreSQL 支援的日期和時間型別。

名字儲存空間描述最低值最高值解析度
timestamp [ (p) ] [ without time zone ]8 位元組日期和時間(無時區)4713 BC294276 AD1 毫秒 / 14 位
timestamp [ (p) ] with time zone8 位元組日期和時間,有時區4713 BC294276 AD1 毫秒 / 14 位
date4 位元組只用於日期4713 BC5874897 AD1 天
time [ (p) ] [ without time zone ]8 位元組只用於一日內時間00:00:0024:00:001 毫秒 / 14 位
time [ (p) ] with time zone12 位元組只用於一日內時間,帶時區00:00:00+145924:00:00-14591 毫秒 / 14 位
interval [ fields ] [ (p) ]12 位元組時間間隔-178000000 年178000000 年1 毫秒 / 14 位

布林型別

PostgreSQL 支援標準的 boolean 資料型別。

boolean 有"true"(真)或"false"(假)兩個狀態, 第三種"unknown"(未知)狀態,用 NULL 表示。

名稱儲存格式描述
boolean1 位元組true/false

列舉型別

列舉型別是一個包含靜態和值的有序集合的資料型別。

PostgtesSQL中的列舉型別類似於 C 語言中的 enum 型別。

與其他型別不同的是列舉型別需要使用 CREATE TYPE 命令建立。

CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy');

建立一週中的幾天,如下所示:

CREATE TYPE week AS ENUM ('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun');

就像其他型別一樣,一旦建立,列舉型別可以用於表和函式定義。

CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy');
CREATE TABLE person (
    name text,
    current_mood mood
);
INSERT INTO person VALUES ('Moe', 'happy');
SELECT * FROM person WHERE current_mood = 'happy';
 name | current_mood 
------+--------------
 Moe  | happy
(1 row)

幾何型別

幾何資料型別表示二維的平面物體。

下表列出了 PostgreSQL 支援的幾何型別。

最基本的型別:點。它是其它型別的基礎。

名字儲存空間說明表現形式
point16 位元組平面中的點(x,y)
line32 位元組(無窮)直線(未完全實現)((x1,y1),(x2,y2))
lseg32 位元組(有限)線段((x1,y1),(x2,y2))
box32 位元組矩形((x1,y1),(x2,y2))
path16+16n 位元組閉合路徑(與多邊形類似)((x1,y1),...)
path16+16n 位元組開放路徑[(x1,y1),...]
polygon40+16n 位元組多邊形(與閉合路徑相似)((x1,y1),...)
circle24 位元組<(x,y),r> (圓心和半徑)

網路地址型別

PostgreSQL 提供用於儲存 IPv4 、IPv6 、MAC 地址的資料型別。

用這些資料型別儲存網路地址比用純文字型別好, 因為這些型別提供輸入錯誤檢查和特殊的操作和功能。

名字儲存空間描述
cidr7 或 19 位元組IPv4 或 IPv6 網路
inet7 或 19 位元組IPv4 或 IPv6 主機和網路
macaddr6 位元組MAC 地址

在對 inet 或 cidr 資料型別進行排序的時候, IPv4 地址總是排在 IPv6 地址前面,包括那些封裝或者是對映在 IPv6 地址裡的 IPv4 地址, 比如 ::10.2.3.4 或 ::ffff:10.4.3.2。


位串型別

位串就是一串 1 和 0 的字串。它們可以用於儲存和直觀化位掩碼。 我們有兩種 SQL 位型別:bit(n) 和bit varying(n), 這裡的n是一個正整數。

bit 型別的資料必須準確匹配長度 n, 試圖儲存短些或者長一些的資料都是錯誤的。bit varying 型別資料是最長 n 的變長型別;更長的串會被拒絕。 寫一個沒有長度的bit 等效於 bit(1), 沒有長度的 bit varying 意思是沒有長度限制。


文字搜尋型別

全文檢索即通過自然語言文件的集合來找到那些匹配一個查詢的檢索。

PostgreSQL 提供了兩種資料型別用於支援全文檢索:

序號 名字 & 描述
1

tsvector

tsvector 的值是一個無重複值的 lexemes 排序列表, 即一些同一個詞的不同變種的標準化。

2

tsquery

tsquery 儲存用於檢索的詞彙,並且使用布林操作符 &(AND),|(OR)和!(NOT) 來組合它們,括號用來強調操作符的分組。


UUID 型別

uuid 資料型別用來儲存 RFC 4122,ISO/IEF 9834-8:2005 以及相關標準定義的通用唯一識別符號(UUID)。 (一些系統認為這個資料型別為全球唯一識別符號,或GUID。) 這個識別符號是一個由演算法產生的 128 位識別符號,使它不可能在已知使用相同演算法的模組中和其他方式產生的識別符號相同。 因此,對分散式系統而言,這種識別符號比序列能更好的提供唯一性保證,因為序列只能在單一資料庫中保證唯一。

UUID 被寫成一個小寫十六進位制數字的序列,由分字元分成幾組, 特別是一組8位數字+3組4位數字+一組12位數字,總共 32 個數字代表 128 位, 一個這種標準的 UUID 例子如下:

a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11

XML 型別

xml 資料型別可以用於儲存XML資料。 將 XML 資料存到 text 型別中的優勢在於它能夠為結構良好性來檢查輸入值, 並且還支援函式對其進行型別安全性檢查。 要使用這個資料型別,編譯時必須使用 configure --with-libxml

xml 可以儲存由XML標準定義的格式良好的"文件", 以及由 XML 標準中的 XMLDecl? content 定義的"內容"片段, 大致上,這意味著內容片段可以有多個頂級元素或字元節點。 xmlvalue IS DOCUMENT 表示式可以用來判斷一個特定的 xml 值是一個完整的檔案還是內容片段。

建立XML值

使用函式 xmlparse: 來從字元資料產生 xml 型別的值:

XMLPARSE (DOCUMENT '<?xml version="1.0"?><book><title>Manual</title><chapter>...</chapter></book>')
XMLPARSE (CONTENT 'abc<foo>bar</foo><bar>foo</bar>')

JSON 型別

json 資料型別可以用來儲存 JSON(JavaScript Object Notation)資料, 這樣的資料也可以儲存為 text,但是 json 資料型別更有利於檢查每個儲存的數值是可用的 JSON 值。

此外還有相關的函式來處理 json 資料:

例項 例項結果
array_to_json('{{1,5},{99,100}}'::int[]) [[1,5],[99,100]]
row_to_json(row(1,'foo')) {"f1":1,"f2":"foo"}

陣列型別

PostgreSQL 允許將欄位定義成變長的多維陣列。

陣列型別可以是任何基本型別或使用者定義型別,列舉型別或複合型別。

宣告陣列

建立表的時候,我們可以宣告陣列,方式如下:

CREATE TABLE sal_emp (
    name            text,
    pay_by_quarter  integer[],
    schedule        text[][]
);

pay_by_quarter 為一維整型陣列、schedule 為二維文字型別陣列。

我們也可以使用 "ARRAY" 關鍵字,如下所示:

CREATE TABLE sal_emp (
   name text,
   pay_by_quarter integer ARRAY[4],
   schedule text[][]
);

插入值

插入值使用花括號 {},元素在 {} 使用逗號隔開:

INSERT INTO sal_emp
    VALUES ('Bill',
    '{10000, 10000, 10000, 10000}',
    '{{"meeting", "lunch"}, {"training", "presentation"}}');

INSERT INTO sal_emp
    VALUES ('Carol',
    '{20000, 25000, 25000, 25000}',
    '{{"breakfast", "consulting"}, {"meeting", "lunch"}}');

訪問陣列

現在我們可以在這個表上執行一些查詢。

首先,我們演示如何訪問陣列的一個元素。 這個查詢檢索在第二季度薪水變化的僱員名:

SELECT name FROM sal_emp WHERE pay_by_quarter[1] <> pay_by_quarter[2];

 name
-------
 Carol
(1 row)

陣列的下標數字是寫在方括弧內的。

修改陣列

我們可以對陣列的值進行修改:

UPDATE sal_emp SET pay_by_quarter = '{25000,25000,27000,27000}'
    WHERE name = 'Carol';

或者使用 ARRAY 構造器語法:

UPDATE sal_emp SET pay_by_quarter = ARRAY[25000,25000,27000,27000]
    WHERE name = 'Carol';

陣列中檢索

要搜尋一個數組中的數值,你必須檢查該陣列的每一個值。

比如:

SELECT * FROM sal_emp WHERE pay_by_quarter[1] = 10000 OR
                            pay_by_quarter[2] = 10000 OR
                            pay_by_quarter[3] = 10000 OR
                            pay_by_quarter[4] = 10000;

另外,你可以用下面的語句找出陣列中所有元素值都等於 10000 的行:

SELECT * FROM sal_emp WHERE 10000 = ALL (pay_by_quarter);

或者,可以使用 generate_subscripts 函式。例如:

SELECT * FROM
   (SELECT pay_by_quarter,
           generate_subscripts(pay_by_quarter, 1) AS s
      FROM sal_emp) AS foo
 WHERE pay_by_quarter[s] = 10000;

複合型別

複合型別表示一行或者一條記錄的結構; 它實際上只是一個欄位名和它們的資料型別的列表。PostgreSQL 允許像簡單資料型別那樣使用複合型別。比如,一個表的某個欄位可以宣告為一個複合型別。

聲明覆合型別

下面是兩個定義複合型別的簡單例子:

CREATE TYPE complex AS (
    r       double precision,
    i       double precision
);

CREATE TYPE inventory_item AS (
    name            text,
    supplier_id     integer,
    price           numeric
);

語法類似於 CREATE TABLE,只是這裡只可以宣告欄位名字和型別。

定義了型別,我們就可以用它建立表:

CREATE TABLE on_hand (
    item      inventory_item,
    count     integer
);

INSERT INTO on_hand VALUES (ROW('fuzzy dice', 42, 1.99), 1000);

複合型別值輸入

要以文字常量書寫複合型別值,在圓括弧裡包圍欄位值並且用逗號分隔他們。 你可以在任何欄位值周圍放上雙引號,如果值本身包含逗號或者圓括弧, 你必須用雙引號括起。

複合型別常量的一般格式如下:

'( val1 , val2 , ... )'

一個例子是:

'("fuzzy dice",42,1.99)'

訪問複合型別

要訪問複合型別欄位的一個域,我們寫出一個點以及域的名字, 非常類似從一個表名字裡選出一個欄位。實際上,因為實在太像從表名字中選取欄位, 所以我們經常需要用圓括弧來避免分析器混淆。比如,你可能需要從on_hand 例子表中選取一些子域,像下面這樣:

SELECT item.name FROM on_hand WHERE item.price > 9.99;

這樣將不能工作,因為根據 SQL 語法,item是從一個表名字選取的, 而不是一個欄位名字。你必須像下面這樣寫:

SELECT (item).name FROM on_hand WHERE (item).price > 9.99;

或者如果你也需要使用表名字(比如,在一個多表查詢裡),那麼這麼寫:

SELECT (on_hand.item).name FROM on_hand WHERE (on_hand.item).price > 9.99;

現在圓括弧物件正確地解析為一個指向item欄位的引用,然後就可以從中選取子域。


範圍型別

範圍資料型別代表著某一元素型別在一定範圍內的值。

例如,timestamp 範圍可能被用於代表一間會議室被預定的時間範圍。

PostgreSQL 內建的範圍型別有:

  • int4range — integer的範圍

  • int8range —bigint的範圍

  • numrange —numeric的範圍

  • tsrange —timestamp without time zone的範圍

  • tstzrange —timestamp with time zone的範圍

  • daterange —date的範圍

此外,你可以定義你自己的範圍型別。

CREATE TABLE reservation (room int, during tsrange);
INSERT INTO reservation VALUES
    (1108, '[2010-01-01 14:30, 2010-01-01 15:30)');

-- 包含
SELECT int4range(10, 20) @> 3;

-- 重疊
SELECT numrange(11.1, 22.2) && numrange(20.0, 30.0);

-- 提取上邊界
SELECT upper(int8range(15, 25));

-- 計算交叉
SELECT int4range(10, 20) * int4range(15, 25);

-- 範圍是否為空
SELECT isempty(numrange(1, 5));

範圍值的輸入必須遵循下面的格式:

(下邊界,上邊界)
(下邊界,上邊界]
[下邊界,上邊界)
[下邊界,上邊界]
空

圓括號或者方括號顯示下邊界和上邊界是不包含的還是包含的。注意最後的格式是 空,代表著一個空的範圍(一個不含有值的範圍)。

-- 包括3,不包括7,並且包括二者之間的所有點
SELECT '[3,7)'::int4range;

-- 不包括3和7,但是包括二者之間所有點
SELECT '(3,7)'::int4range;

-- 只包括單一值4
SELECT '[4,4]'::int4range;

-- 不包括點(被標準化為‘空’)
SELECT '[4,4)'::int4range;

物件識別符號型別

PostgreSQL 在內部使用物件識別符號(OID)作為各種系統表的主鍵。

同時,系統不會給使用者建立的表增加一個 OID 系統欄位(除非在建表時聲明瞭WITH OIDS 或者配置引數default_with_oids設定為開啟)。oid 型別代表一個物件識別符號。除此以外 oid 還有幾個別名:regproc, regprocedure, regoper, regoperator, regclass, regtype, regconfig, 和regdictionary。

名字引用描述數值例子
oid任意數字化的物件識別符號564182
regprocpg_proc函式名字sum
regprocedurepg_proc帶引數型別的函式sum(int4)
regoperpg_operator操作符名+
regoperatorpg_operator帶引數型別的操作符*(integer,integer) 或 -(NONE,integer)
regclasspg_class關係名pg_type
regtypepg_type資料型別名integer
regconfigpg_ts_config文字搜尋配置english
regdictionarypg_ts_dict文字搜尋字典simple

偽型別

PostgreSQL型別系統包含一系列特殊用途的條目, 它們按照類別來說叫做偽型別。偽型別不能作為欄位的資料型別, 但是它可以用於宣告一個函式的引數或者結果型別。 偽型別在一個函式不只是簡單地接受並返回某種SQL 資料型別的情況下很有用。

下表列出了所有的偽型別:

名字描述
any表示一個函式接受任何輸入資料型別。
anyelement表示一個函式接受任何資料型別。
anyarray表示一個函式接受任意陣列資料型別。
anynonarray表示一個函式接受任意非陣列資料型別。
anyenum表示一個函式接受任意列舉資料型別。
anyrange表示一個函式接受任意範圍資料型別。
cstring表示一個函式接受或者返回一個空結尾的 C 字串。
internal表示一個函式接受或者返回一種伺服器內部的資料型別。
language_handler一個過程語言呼叫處理器宣告為返回language_handler。
fdw_handler一個外部資料封裝器宣告為返回fdw_handler。
record標識一個函式返回一個未宣告的行型別。
trigger一個觸發器函式宣告為返回trigger。
void表示一個函式不返回數值。
opaque一個已經過時的型別,以前用於所有上面這些用途。

更多內容參考:PostgreSQL 資料型別