PostgreSQL SQL 語言:數據類型
本文檔為PostgreSQL 9.6.0文檔,本轉載已得到原譯者彭煜瑋授權。
數字類型由2、4或8字節的整數以及4或8字節的浮點數和可選精度小數組成。Table 8-2列出了所有可用類型。
Table 8-2. 數字類型
下麵的幾節詳細描述這些類型。
1.1. 整數類型
類型smallint、integer和bigint存儲各種範圍的全部是數字的數,也就是沒有小數部分的數字。試圖存儲超出範圍以外的值將導致一個錯誤。
常用的類型是integer,因為它提供了在範圍、存儲空間和性能之間的最佳平衡。一般隻有在磁盤空間緊張的時候才使用 smallint類型。而隻有在integer的範圍不夠的時候才使用bigint。
SQL隻聲明了整數類型integer(或int)、smallint和bigint。類型int2、int4和int8都是擴展,也在許多其它SQL數據庫係統中使用。
1.2. 任意精度數字
類型numeric可以存儲非常多位的數字。我們特別建議將它用於貨幣金額和其它要求計算準確的數量。numeric值的計算在可能的情況下會得到準確的結果,例如加法、減法、乘法。不過,numeric類型上的算術運算比整數類型或者下一節描述的浮點數類型要慢很多。
在隨後的內容裏,我們使用了下述術語:一個numeric的比例是到小數部分的位數,numeric的精度是整個數字裏全部位的數目,也就是小數點兩邊的位數目。因此數字 23.5141 的精度為6而比例為4。你可以認為整數的比例為零。
numeric列的最大精度和最大比例都是可以配置的。要聲明一個類型為numeric的列,你可以用下麵的語法:
NUMERIC(precision, scale)
精度必須為正數,比例可以為零或者正數。另外:
NUMERIC(precision)
選擇比例為 0 。如果使用
NUMERIC
創建一個列時不使用精度或比例,則該列可以存儲任何精度和比例的數字值,並且值的範圍最多可以到實現精度的上限。一個這種列將不會把輸入值轉化成任何特定的比例,而帶有比例聲明的numeric列將把輸入值轉化為該比例(SQL標準要求缺省的比例是 0,即轉化成整數精度。我們覺得這樣做有點沒用。如果你關心移植性,那你最好總是顯式聲明精度和比例)。
Note:
顯式指定類型精度時的最大允許精度為 1000,沒有指定精度的NUMERIC受到Table 8-2中描述的限製所控製。
如果一個要存儲的值的比例比列聲明的比例高,那麼係統將嚐試圓整(四舍五入)該值到指定的分數位數。 然後,如果小數點左邊的位數超過了聲明的精度減去聲明的比例,那麼拋出一個錯誤。
數字值在物理上是以不帶任何前導或者後綴零的形式存儲。 因此,列上聲明的精度和比例都是最大值,而不是固定分配的 (在這個方麵,numeric類型更類似於varchar(n), 而不像char(n))。 實際存儲要求是每四個十進製位組用兩個字節, plus three to eight bytes overhead.
除了普通的數字值之外,numeric類型允許特殊值NaN, 表示"不是一個數字"。任何在 NaN上麵的操作都生成另外一個NaN。 如果在 SQL 命令裏把這些值當作一個常量寫,你必須在其周圍放上單引號,例如UPDATE table SET x = 'NaN'。在輸入時,字串NaN被識別為大小寫無關。
Note: 在"不是一個數字"概念的大部分實現中,NaN被認為不等於任何其他數字值(包括NaN)。為了允許numeric值可以被排序和使用基於樹的索引,PostgreSQL把NaN值視為相等,並且比所有非NaN值都要大。
類型decimal和numeric是等效的。兩種類型都是SQL標準的一部分。
在對值進行圓整時,numeric類型會圓到遠離零的整數,而(在大部分機器上)real和double precision類型會圓到最近的偶數上。例如:
SELECT x,
round(x::numeric) AS num_round,
round(x::double precision) AS dbl_round
FROM generate_series(-3.5, 3.5, 1) as x;
x | num_round | dbl_round
------+-----------+-----------
-3.5 | -4 | -4
-2.5 | -3 | -2
-1.5 | -2 | -2
-0.5 | -1 | -0
0.5 | 1 | 0
1.5 | 2 | 2
2.5 | 3 | 2
3.5 | 4 | 4
(8 rows)
1.3. 浮點類型
數據類型real和double precision是不準確的、變精度的數字類型。實際上,這些類型是IEEE標準 754 二進製浮點算術(分別對應單精度和雙精度)的一般實現, 一直到下層處理器、操作係統和編譯器對它的支持。
不準確意味著一些值不能準確地轉換成內部格式並且是以近似的形式存儲的,因此存儲和檢索一個值可能出現一些缺失。 處理這些錯誤以及這些錯誤是如何在計算中傳播的主題屬於數學和計算機科學的一個完整的分支, 我們不會在這裏進一步討論它,這裏的討論僅限於如下幾點:
如果你要求準確的存儲和計算(例如計算貨幣金額),應使用numeric類型。
如果你想用這些類型做任何重要的複雜計算,尤其是那些你對範圍情況(無窮、下溢)嚴重依賴的事情,那你應該仔細評詁你的實現。
用兩個浮點數值進行等值比較不可能總是按照期望地進行。
在大部分平台上,real類型的範圍是至少 -1E+37 到 +1E+37,精度至少是 6 位小數。double precision類型通常有 -1E+308 到 +1E+308 的範圍,精度是至少 15 位數字。太大或者太小的值都會導致錯誤。 如果輸入數字的精度太高,那麼可能發生園整。太接近零的數字,如果無法與零值的表現形式相區分就會產生下溢錯誤。
Note:
extra_float_digits設置控製當一個浮點值被轉換為文本輸出時要包括的額外有效數字的數目。其默認值為0,在每一個PostgreSQL支持的平台上輸出都相同。增加該設置將產生能更精確表示存儲值的輸出,但是可能無法移植。
除了普通的數字值之外,浮點類型還有幾個特殊值:
- Infinity
- -Infinity
- NaN
這些值分別表示 IEEE 754 特殊值"正無窮大"、"負無窮大"以及"不是一個數字"(在不遵循 IEEE 754 浮點算術的機器上,這些值的含義可能不是預期的)。如果在 SQL 命令裏把這些數值當作常量寫,你必須在它們周圍放上單引號,例如UPDATE table SET x = 'Infinity'。 在輸入時,這些串是以大小寫無關的方式識別的。
Note:
IEEE754指定NaN不應該與任何其他浮點值(包括NaN)相等。為了允許浮點值被排序或者在基於樹的索引中使用,PostgreSQL將NaN值視為相等,並且比所有非NaN值要更大。
PostgreSQL還支持 SQL 標準表示法float和float(p)用於聲明非精確的數字類型。在這裏,p指定以二進製位表示的最低可接受精度。 在選取real類型的時候,PostgreSQL接受float(1)到float(24),在選取double precision的時候,接受float(25)到float(53)。在允許範圍之外的p值將導致一個錯誤。沒有指定精度的float將被當作是double precision。
Note: 認為real和double precision分別有 24 和 53 個二進製位的假設對 IEEE 標準的浮點實現來說是正確的。在非 IEEE 平台上,這個數值可能略有偏差,但是為了簡化,我們在所有平台上都用了同樣的p值範圍。
1.4. 序數類型
smallserial、serial和bigserial類型不是真正的類型,它們隻是為了創建唯一標識符列而存在的方便符號(類似其它一些數據庫中支持的AUTO_INCREMENT屬性)。 在目前的實現中,下麵一個語句:
CREATE TABLE tablename (
colname SERIAL
);
等價於以下語句:
CREATE SEQUENCE tablename_colname_seq;
CREATE TABLE tablename (
colname integer NOT NULL DEFAULT nextval('tablename_colname_seq')
);
ALTER SEQUENCE tablename_colname_seq OWNED BY tablename.colname;
因此,我們就創建了一個整數列並且把它的缺省值安排為從一個序列發生器取值。應用了一個NOT NULL約束以確保空值不會被插入(在大多數情況下你可能還希望附加一個UNIQUE或者PRIMARY KEY約束避免意外地插入重複的值,但這個不是自動發生的)。最後,該序列被標記為"屬於"該列,這樣當列或表被刪除時該序列也會被刪除。
Note: 因為smallserial、serial和bigserial是用序列實現的,所以即使沒有刪除過行,在出現在列中的序列值可能有“空洞”或者間隙。如果一個從序列中分配的值被用在一行中,即使該行最終沒有被成功地插入到表中,該值也被“用掉”了。例如,當插入事務回滾時就會發生這種情況。更多信息參見Section 9.16中的nextval()。
要使用serial列插入序列的下一個數值到表中, 請指定serial列應該被賦予其缺省值。我們可以通過在INSERT語句中把該列排除在列列表之外來實現,也可以通過使用DEFAULT關鍵字來實現。
類型名serial和serial4是等效的: 兩個都創建integer列。類型名bigserial和serial8也一樣,隻不過它們創建一個 bigint列。如果你預計在表的生存期中使用的標識符數目超過 231 個,那麼你應該使用bigserial。類型名smallserial和serial2也以相同方式工作,隻不過它們創建一個smallint列。
為一個serial列創建的序列在所屬的列被刪除的時候自動刪除。你可以在不刪除列的情況下刪除序列,但是這會強製刪除該列的默認值表達式。
money類型存儲固定小數精度的貨幣數字,參閱Table 8-3。小數的精度由數據庫的lc_monetary設置決定。表中展示的範圍假設有兩個小數位。可接受的輸入格式很多,包括整數和浮點數文字,以及常用的貨幣格式,如'$1,000.00'。 輸出通常是最後一種形式,但和區域相關。
由於這種數據類型的輸出是區域敏感的,因此將money數據裝入到一個具有不同lc_monetary設置的數據庫是不起作用的。為了避免這種問題,在恢複一個轉儲到一個新數據庫中之前,應確保新數據庫的lc_monetary設置和被轉儲數據庫的相同或者具有等效值。
數據類型numeric、int和bigint的值可以被造型成money。從數據類型real和double precision的轉換可以通過先造型成numeric來實現,例如:
SELECT '12.34'::float8::numeric::money;
但是,我們不推薦這樣做。浮點數不應該被用來處理貨幣,因為浮點數可能會有圓整錯誤。
一個money值可以在不損失精度的情況下被造型成numeric。轉換到其他類型可能會丟失精度,並且必須采用兩個階段完成:
SELECT '52093.89'::money::numeric::float8;
當一個money值被另一個money值除時,結果是double precision(即一個純數字,而不是金額),在除法中貨幣單位被約掉了。
Table 8-4. 字符類型
Table 8-4顯示了在PostgreSQL裏可用的一般用途的字符類型。
SQL定義了兩種基本的字符類型: character varying(n)和character(n), 其中n是一個正整數。兩種類型都可以存儲最多n個字符長的串。試圖存儲更長的串到這些類型的列裏會產生一個錯誤, 除非超出長度的字符都是空白,這種情況下該串將被截斷為最大長度(這個看上去有點怪異的例外是SQL標準要求的)。 如果要存儲的串比聲明的長度短,類型為character的值將會用空白填滿;而類型為character varying的值將隻是存儲短些的串。
如果我們明確地把一個值造型成character varying(n)或者character(n), 那麼超長的值將被截斷成n個字符,而不會拋出錯誤(這也是SQL標準的要求)。
varchar(n)和char(n)的概念分別是character varying(n)和character(n)的別名。沒有長度聲明詞的character等效於character(1)。如果不帶長度說明詞使用character varying,那麼該類型接受任何長度的串。後者是一個PostgreSQL的擴展。
另外,PostgreSQL提供text類型,它可以存儲任何長度的串。盡管類型text不是SQL標準,但是許多其它 SQL 數據庫係統也有它。
類型character的值物理上都用空白填充到指定的長度n, 並且以這種方式存儲和顯示。不過,拖尾的空白被當作是沒有意義的,並且在比較兩個 character類型值時不會考慮它們。在空白有意義的排序規則中,這種行為可能會 產生意料之外的結果,例如SELECT 'a '::CHAR(2) collate "C" < E'a\n'::CHAR(2)會返回真(即便C區域會認為一個空格比新行更大)。當把一個character值轉換成其他 字符串類型之一時,拖尾的空白會被移除。請注意,在character varying和text值裏, 結尾的空白語意上是有含義的,並且在使用模式匹配(如LIKE和正則表達式)時也會被考慮。
這些類型的存儲需求是 4 字節加上實際的字串,如果是 character 的話再加上填充的字節。長的字串將會自動被係統壓縮, 因此在磁盤上的物理需求可能會更少些。長的數值也會存儲在後台表裏麵,這樣它們就不會幹擾對短字段值的快速訪問。 不管怎樣,允許存儲的最長字串大概是 1 GB。 (允許在數據類型聲明中出現的的 n 的最大值比這還小。 修改這個行為沒有甚麼意義,因為在多字節編碼下字符和字節的數目可能差別很大。 如果你想存儲沒有特定上限的長字串,那麼使用 text 或者沒有長度聲明詞的 character varying, 而不要選擇一個任意長度限製。) 一個短串(最長126字節)的存儲要求是1個字節外加實際的串,該串在character情況下包含填充的空白。長一些的串在前麵需要4個字節而不是1個字節。長串會被係統自動壓縮,這樣在磁盤上的物理需求可能會更少。非常長的值也會被存儲在背景表中,這樣它們不會幹擾對較短的列值的快速訪問。在任何情況下,能被存儲的最長的字符串是1GB(數據類型定義中n能允許的最大值比這個值要小。修改它沒有用處,因為對於多字節字符編碼來說,字符的數量和字節數可能完全不同。如果你想要存儲沒有指定上限的長串,使用text或沒有長度聲明的character varying,而不是給出一個任意長度限製)。
Tip: 這三種類型之間沒有性能差別,隻不過是在使用填充空白的類型的時候需要更多存儲尺寸,以及在存儲到一個有長度約束的列時需要少量額外CPU周期來檢查長度。雖然在某些其它的數據庫係統裏,character(n)有一定的性能優勢,但在PostgreSQL裏沒有。事實上,character(n)通常是這三種類型之中最慢的一個,因為它需要額外的存儲開銷。在大多數情況下,應該使用text或者character varying。
Example 8-1. 使用字符類型
CREATE TABLE test1 (a character(4));
INSERT INTO test1 VALUES ('ok');
SELECT a, char_length(a) FROM test1; -- (1)
a | char_length
------+-------------
ok | 2
CREATE TABLE test2 (b varchar(5));
INSERT INTO test2 VALUES ('ok');
INSERT INTO test2 VALUES ('good ');
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
(1)
在PostgreSQL裏另外還有兩種定長字符類型,在Table 8-5裏顯示。 name類型隻用於在內部係統目錄中存儲標識符並且不是給一般用戶使用的。該類型長度當前定為 64 字節(63 可用字符加結束符)但在C源代碼應該使用常量 NAMEDATALEN引用。這個長度是在編譯的時候設置的(因而可以為特殊用途調整),缺省的最大長度在以後的版本可能會改變。類型"char"(注意引號)和 char(1)是不一樣的,它隻用了一個字節的存儲空間。它在係統內部用於係統目錄當做簡化的枚舉類型用。
bytea數據類型允許存儲二進製串,參見Table 8-6。
二進製串是一個八位位組(或字節)的序列。 二進製串和字符串的區別有兩個: 首先,二進製串明確允許存儲零值的字節以及其它"不可打印的"字節(通常是位於範圍 32 到 126 之外的字節)。 字符串不允許零字節,並且也不允許那些對於數據庫的選定字符集編碼是非法的任何其它字節值或者字節值序列。 第二,對二進製串的操作會處理實際上的字節,而字符串的處理和取決於區域設置。 簡單說,二進製字串適用於存儲那些程序員認為是"裸字節"的數據,而字符串適合存儲文本。
bytea類型支持兩種用於輸入和輸出的外部格式:PostgreSQL的曆史的"逃逸"格式和"十六進製"格式。在輸入時這兩種格式總是會被接受。輸出格式則取決於配置參數bytea_output,其默認值為十六進製(注意十六進製格式是在PostgreSQL 9.0中被引入的,早期的版本和某些工具無法理解它)。
SQL標準定義了一種不同的二進製串類型, 叫做BLOB或者BINARY LARGE OBJECT。其輸入格式和bytea不同,但是提供的函數和操作符大多一樣。
8.4.1. bytea的十六進製格式
"十六進製"格式將二進製數據編碼為每個字節2個十六進製位,最高有效位在前。整個串以序列\x開頭(用以和逃逸格式區分)。在某些情景中,開頭的反斜線可能需要通過雙寫來逃逸,在相同的情況中逃逸格式必須要雙寫反斜線,下文描述了細節。十六進製位可以是大寫也可以是小寫,在位對之間可以有空白(但是在位對內部以及開頭的\x序列中不能有空白)。十六進製格式和很多外部應用及協議相兼容,並且其轉換速度要比逃逸格式更快,因此人們更願意用它。
例子:
SELECT E'\\xDEADBEEF';
8.4.2. bytea的逃逸格式
"逃逸"格式是bytea類型的傳統PostgreSQL格式。它采用將二進製串表示成ASCII字符序列的方法,而將那些無法用ASCII字符表示的字節轉換成特殊的逃逸語句。從應用的角度來看,如果將字節表示為字符有意義,那麼這種表示將很方便。但是在實際中,這常常是令人困擾的,因為它使二進製串和字符串之間的區別變得模煳,並且這種特別的逃逸機製也有點難於處理。因此這種格式可能會在大部分新應用中避免使用。
在逃逸模式下輸入bytea值時,某些值的字節必須被逃逸,而所有的字節值都可以被逃逸。通常,要逃逸一個字節,需要把它轉換成與它的三位八進製值, 並且前導一個反斜線(或者兩個反斜線,如果使用逃逸串語法將值寫成一個字麵含義)。反斜線本身(字節值92)也可以用雙寫的反斜線表示。Table 8-7顯示了必須被逃逸的字符,並給出了可以使用的替代逃逸序列。
Table 8-7. bytea文字逃逸字節
逃逸"不可打印的"字節的要求取決於區域設置。在某些實例中,你可以不理睬它們,讓它們保持未逃逸的狀態。注意在Table 8-7的每一個例子中的結果的長度正好是一個字節,即使其輸出表示有時超過一個字符。
如Table 8-7中所示,要求多個反斜線的原因是寫成一個串文字的輸入串在PostgreSQL服務器中必須經過兩個分析階段。每一對中的第一個反斜線被串文字分析器(假設使用了逃逸串語法)解釋為一個逃逸字符並且因此被消耗,隻留下該對中的第二個反斜線(美元符號包圍的串可以被用於防止這一層的逃逸)。剩下的反斜線接著被bytea輸入函數識別為開始一個三位八進製值或逃逸另一個反斜線。例如,一個傳遞給服務器的串文字是E'\001',它在通過逃逸串分析器後變成\001。\001接著被送給bytea輸入函數,這裏它被轉換成一個十進製值為1的單字節。注意單引號字符串不會被bytea特殊對待,因此它遵循串文字的正常規則。
Bytea字節有時在輸出時被逃逸。通常,每一個"不可打印的"字節會被轉換成與之等效的三位八進製值並且前置一個反斜線。大部分"可打印的"字節被表示為它們在客戶端字符集中的標準表示形式。十進製值為92(反斜線)的字節在輸出時被雙寫。詳情請見Table 8-8。
Table 8-8. bytea輸出逃逸字節
根據你使用的PostgreSQL前端,你在逃逸和未逃逸bytea串方麵可能需要做額外的工作。例如,如果你的接口自動翻譯換行和回車,你可能也不得不逃逸它們。
PostgreSQL支持SQL中所有的日期和時間類型,如Table 8-9所示。這些數據類型上可用的操作如Section 9.9所述。日期根據公曆來計算,即使對於該曆法被引入之前的年份也一樣(見Section B.4)。
Note: SQL要求隻寫timestamp等效於timestamp without time zone,並且PostgreSQL鼓勵這種行為。timestamptz被接受為timestamp with time zone的一種簡寫,這是一種PostgreSQL的擴展。
time、timestamp和interval接受一個可選的精度值 p,這個精度值聲明在秒域中小數點之後保留的位數。缺省情況下,在精度上沒有明確的邊界,p允許的範圍對timestamp和interval類型是從 0 到 6。
Note: 當timestamp值被存儲為八字節整數(目前是默認情況)時,在整個值的範圍上微秒精度是可用的。當timestamp值被存儲為雙精度浮點數(一個已被啟用的編譯時選項)時,那麼精度的有效限製會小於 6。timestamp值是以 2000-01-01 午夜之前或之後以來的秒數存儲的。當timestamp值被用浮點數實現時,在2000-01-01前後幾年的日期可以達到微秒的精度,但是對於遠一些的日子,精度會下降。注意使用浮點日期時間允許顯示比上文所述更大範圍的timestamp值:從 4713 BC 到 5874897 AD。
同一個編譯時選項也決定了time和interval值被存儲為浮點數或八字節整數。在浮點數的情況中,當間隔的尺寸增長時,大interval值在精度上會下降。
對於time類型,如果使用了八字節的整數存儲,允許的p的範圍是從 0 到 6,如果使用的是浮點數存儲,那麼這個範圍是 0 到 10。
interval類型有一個附加選項,它可以通過寫下麵之一的短語來限製存儲的fields的集合:
YEAR
MONTH
DAY
HOUR
MINUTE
SECOND
YEAR TO MONTH
DAY TO HOUR
DAY TO MINUTE
DAY TO SECOND
HOUR TO MINUTE
HOUR TO SECOND
MINUTE TO SECOND
注意如果fields和p被指定,fields必須包括SECOND,因為精度隻應用於秒。
類型time with time zone是 SQL 標準定義的,但是該定義顯示出了一些會影響可用性的性質。在大多數情況下, date、time、timestamp without time zone和timestamp with time zone的組合就應該能提供任何應用所需的全範圍的日期/時間功能。
類型abstime和reltime是低精度類型,它們被用於係統內部。 我們不鼓勵你在應用裏麵使用這些類型,這些內部類型可能會在未來的版本裏消失。
5.1. 日期/時間輸入
日期和時間的輸入可以接受幾乎任何合理的格式,包括 ISO 8601、SQL-兼容的、傳統POSTGRES的和其他的形式。 對於一些格式,日期輸入裏的日、月和年的順序會讓人混淆, 並且支持指定所預期的這些域的順序。把DateStyle參數設置為MDY,就是選擇“月-日-年”的解釋,設置為DMY就是 “日-月-年”,而YMD是 “年-月-日”。
PostgreSQL在處理日期/時間輸入上比SQL標準要求的更靈活。
請記住任何日期或者時間的文字輸入需要由單引號包圍,就象一個文本字符串一樣。SQL要求下麵的語法
type [ (p) ] 'value'
其中p是一個可選的精度聲明,它給出了在秒域中的小數位數目。精度可以被指定給time、timestamp和interval類型。這允許前文所述的值。如果在一個常數聲明中沒有指定任何精度,它將默認取文字值的精度。
5.1.1. 日期
Table 8-10顯示了date類型可能的輸入方式。
Table 8-10. 日期輸入
5.1.2. 時間
當日時間類型是time [ (p) ] without time zone和time [ (p) ] with time zone。 隻寫time等效於time without time zone。
這些類型的有效輸入由當日時間後麵跟著可選的時區組成(參閱Table 8-11和Table 8-12)。 如果在time without time zone的輸入中指定了時區,那麼它會被無聲地忽略。你也可以指定一個日期但是它會被忽略,除非你使用了一個涉及到夏令時規則的時區,例如America/New_York。在這種情況下,為了判斷是應用了標準時間還是夏令時時間,要求指定該日期。適當的時區偏移被記錄在time with time zone值中。
Table 8-11. 時間輸入
Table 8-12. 時區輸入
1.3. 時間戳
時間戳類型的有效輸入由一個日期和時間的串接組成,後麵跟著一個可選的時區,一個可選的AD或者BC(另外,AD/BC可以出現在時區前麵,但這個順序並非最佳)。 因此:
1999-01-08 04:05:06
和:
1999-01-08 04:05:06 -8:00
都是有效的值,它遵循ISO 8601 標準。另外,使用廣泛的格式:
January 8 04:05:06 1999 PST
也被支持。
SQL標準通過"+"或者"-"符號的存在以及時間後麵的時區偏移來區分timestamp without time zone和timestamp with time zone文字。因此,根據標準,
TIMESTAMP '2004-10-19 10:23:54'
是一個timestamp without time zone, 而
TIMESTAMP '2004-10-19 10:23:54+02'
是一個timestamp with time zone。PostgreSQL從來不會在確定文字串的類型之前檢查其內容,因此會把上麵兩個都看做是 timestamp without time zone。因此要保證把上麵的文字當作timestamp with time zone看待, 就要給它正確的顯式類型:
TIMESTAMP WITH TIME ZONE '2004-10-19 10:23:54+02'
如果一個文字已被確定是timestamp without time zone,PostgreSQL將不聲不響忽略任何其中指出的時區。 即,結果值是從輸入值的日期/時間域衍生出來的,並且沒有就時區進行調整。
對於timestamp with time zone,內部存儲的值總是 UTC (全球統一時間,以前也叫格林威治時間GMT)。如果一個輸入值有明確的時區聲明, 那麼它將用該時區合適的偏移量轉換成 UTC。如果在輸入串裏沒有時區聲明, 那麼它就被假設是在係統的TimeZone參數裏的那個時區,然後使用這個 timezone時區的偏移轉換成 UTC。
如果一個timestamp with time zone值被輸出,那麼它總是從 UTC 轉換成當前的timezone時區,並且顯示為該時區的本地時間。要看其它時區的時間,要麼修改timezone,要麼使用AT TIME ZONE構造。
在timestamp without time zone和timestamp with time zone之間的轉換通常假設timestamp without time zone值應該以timezone本地時間的形式接受或者寫出。為該轉換指定一個不同的可以用AT TIME ZONE。
5.1.4. 特殊值
為了方便,PostgreSQL支持一些特殊日期/時間輸入值,如Table 8-13所示。這些值中infinity和-infinity被在係統內部以特殊方式表示並且將被原封不動地顯示。但是其他的僅僅隻是概念上的速寫,當被讀到的時候會被轉換為正常的日期/時間值(特殊地,now及相關串在被讀到時立刻被轉換到一個指定的時間值)。在作為常量在SQL命令中使用時,所有這些值需要被包括在單引號內。
Table 8-13. 特殊日期/時間輸入
下列SQL-兼容的函數可以被用來為相應的數據類型獲得當前時間值: CURRENT_DATE、CURRENT_TIME、 CURRENT_TIMESTAMP、LOCALTIME、 LOCALTIMESTAMP。後四種接受一個可選的亞秒精度聲明(參見Section 9.9.4)。注意這些是SQL函數並且在數據輸入串中不被識別。
5.2. 日期/時間輸出
時間/日期類型的輸出格式可以設成四種風格之一: ISO 8601、SQL(Ingres)、傳統的POSTGRES(Unix的date格式)或 German 。缺省是ISO格式(ISO標準要求使用 ISO 8601 格式。ISO輸出格式的名字是曆史偶然)。Table 8-14顯示了每種輸出風格的例子。date和time類型的 輸出通常隻有日期或時間部分和例子中一致。不過,POSTGRES風格輸出的是ISO格式的隻有日期的值。
Table 8-14. 日期/時間輸出風格
Note: ISO 8601指定使用大寫字母T來分隔日期和時間。PostgreSQL在輸入上接受這種格式,但是在輸出時它采用一個空格而不是T,如上所示。和一些其他數據庫係統一樣,這是為了可讀性以及與RFC 3339的一致性。
SQL和POSTGRES風格中,如果DMY域順序被指定,“日”將出現在“月”之前,否則“月”出現在“日”之前。Table 8-15給出了例子。
Table 8-15. 日期順序習慣
日期/時間風格可以由用戶使用SET datestyle命令選取,在postgresql.conf配置文件裏的參數DateStyle設置或者在服務器或客戶端的PGDATESTYLE環境變量裏設置。
格式化函數to_char(見Section 9.8)也可以作為一個更靈活的方式來格式化日期/時間輸出。
5.3. 時區
時區和時區習慣不僅僅受地球幾何形狀的影響,還受到政治決定的影響。 到了19世紀,全球的時區變得稍微標準化了些,但是還是易於遭受隨意的修改,部分是因為夏時製規 則。PostgreSQL使用廣泛使用的 IANA (Olson) 時區數據庫來得到有關曆史時區規則的信息。對於未來的時間,我們假設關於一個給定時區的最新已知 規則將會一直持續到無窮遠的未來。
PostgreSQL努力在典型使用中與SQL標準的定義相兼容。但SQL標準在日期和時間類型和功能上有一些奇怪的混淆。兩個顯而易見的問題是:
- 盡管date類型與時區沒有聯係,而time類型卻可以有。 然而,現實世界的時區隻有在與時間和日期都關聯時才有意義, 因為偏移(時差)可能因為實行類似夏時製這樣的製度而在一年裏有所變化。
- 缺省的時區會指定一個到UTC的數字常量偏移(時差)。因此,當跨DST邊界做日期/時間算術時, 我們根本不可能適應於夏時製時間。
為了克服這些困難,我們建議在使用時區的時候,使用那些同時包含日期和時間的日期/時間類型。我們不建議使用類型 time with time zone (盡管PostgreSQL出於遺留應用以及與SQL標準兼容性的考慮支持這個類型)。 PostgreSQL假設你用於任何類型的本地時區都隻包含日期或時間。
在係統內部,所有時區相關的日期和時間都用UTC存儲。它們在被顯示給客戶端之前會被轉換成由TimeZone配置參數指定的本地時間。
PostgreSQL允許你使用三種不同形式指定時區:
- 一個完整的時區名字,例如America/New_York。能被識別的時區名字被列在pg_timezone_names視圖中。PostgreSQL用廣泛使用的 IANA 時區數據來實現該目的,因此相同的時區名字也可以在很多其他軟件中被識別。
- 一個時區縮寫,例如PST。這樣一種聲明僅僅定義了到UTC的一個特定偏移,而不像完整時區名那樣指出整套夏令時轉換日期規則。能被識別的縮寫被列在pg_timezone_abbrevs視圖中。你不能將配置參數TimeZone或log_timezone設置成一個時區縮寫,但是你可以在日期/時間輸入值和AT TIME ZONE操作符中使用時區縮寫。
- 除了時區名和縮寫,PostgreSQL將接受POSIX-風格的 時區聲明,形式為STDoffset或 STDoffsetDST, 其中STD是一個區域縮寫、offset是從UTC西 起的以小時計的數字偏移量、DST是一個可選的夏令時區域縮 寫(被假定為給定偏移量提前一小時)。例如,如果EST5EDT還不是一 個被識別的區域名,它可以被接受並且可能和美國東海岸時間的功效相同。在這種語法中, 一個時區縮寫可以是一個字母的字符串或者由尖括號(<>)包圍 的任意字符串。當一個夏令時區域縮寫出現時,會假定根據 IANA 時區數據庫的 posixrules條目中使用的同一個夏令時轉換規則使用它。 在一個標準的PostgreSQL安裝中, posixrules和US/Eastern相同, 因此POSIX-風格的時區聲明遵循美國的夏令時規則。如果需要,你可以通過替換 posixrules文件來調整這種行為。
簡而言之,在縮寫和全稱之間是有不同的:縮寫表示從UTC開始的一個特定偏移量, 而很多全稱表示一個本地夏令時規則並且因此具有兩種可能的UTC偏移量。例如, 2014-06-04 12:00 America/New_York表示紐約本地時間的中午, 這個特殊的日期是東部夏令時間(UTC-4)。因此2014-06-04 12:00 EDT 指定的是同一個時間點。但是2014-06-04 12:00 EST指定東部標準時間的 中午(UTC-5),不管在那個日期夏令時是否生效。
更要命的是,某些行政區已經使用相同的時區縮寫在不同的時間表示不同的 UTC 偏移量。例如, 在莫斯科MSK在某些年份表示 UTC+3 而在另一些年份表示 UTC+4。 PostgreSQL 會根據在指定的日期它們到底表示什麼(或者最近表示什麼) 來解釋這種縮寫。但是,正如上麵的EST例子所示,這並不是必須和那一天的本地 標準時間相同。
你應該注意到POSIX-風格的時區特性可能導致偽造的輸入被接受,因為它沒有對區域縮寫合理性的檢查。例如SET TIMEZONE TO FOOBAR0將會正常工作,讓係統實際使用一個相當奇怪的UTC縮寫。另一個需要記住的問題是在POSIX時區名中,正值的偏移量被用於格林威治以西的位置。在其他情況下,PostgreSQL將遵循 ISO-8601 慣例,認為正值的時區偏移量是格林威治以東。
在所有情況下,時區名及其縮寫都是大小寫不敏感的(這是對PostgreSQL 8.2之前版本的一個修改,在這些版本中某些環境下時區名是大小寫敏感的而在另外一些環境中卻是大小寫不敏感的)。
時區名和縮寫都不是硬寫在服務器中的,它們是從存儲在安裝目錄下的.../share/timezone/和.../share/timezonesets/子目錄中獲取的。
TimeZone配置參數可以在文件postgresql.conf中被設置,或者使用Chapter 19中描述的任何一種標準方法設置。同時也有一些特殊的方法來設置它:
- SQL命令SET TIME ZONE為會話設置時區。它是SET TIMEZONE TO的另一種拚寫,它更加符合SQL的語法。
- libpq客戶端使用PGTZ環境變量來通過連接發送一個SET TIME ZONE命令給服務器。
5.4. 間隔輸入
interval值可以使用下列語法書寫:
[@] quantity unit [quantity unit...] [direction]
其中quantity是一個數字(很可能是有符號的); unit是毫秒、 millisecond、second、 minute、hour、day、 week、month、year、 decade、century、millennium 或者縮寫或者這些單位的複數; direction可以是ago或者為空。At符號(@)是一個可選的噪聲。不同單位的數量通過合適的符號計數被隱式地添加。ago對所有域求反。如果IntervalStyle被設置為postgres_verbose,該語法也被用於間隔輸出。
日、小時、分鍾和秒的數量可以不適用顯式的單位標記指定。例如,'1 12:59:10'被讀作'1 day 12 hours 59 min 10 sec'。同樣,一個年和月的組合可以使用一個橫線指定,例如'200-10'被讀作'200年10個月'(這些較短的形式事實上是SQL標準唯一許可的形式,並且在IntervalStyle被設置為sql_standard時用於輸出)。
間隔值也可以被寫成 ISO 8601 時間間隔,使用該標準4.4.3.2小節的"帶標誌符的格式"或者4.4.3.3小節的"替代格式"。帶標誌符的格式看起來像這樣:
P quantity unit [ quantity unit ...] [ T [ quantity unit ...]]
該串必須以一個P開始,並且可以包括一個引入當日時間單位的T。可用的單位縮寫在Table 8-16中給出。單位可以被忽略,並且可以以任何順序指定,但是小於一天的單位必須出現在T之後。特別地,M的含義取決於它出現在T之前還是之後。
Table 8-16. ISO 8601 間隔單位縮寫
如果使用替代格式:
P [ years-months-days ] [ T hours:minutes:seconds ]
串必須以P開始,並且一個T分隔間隔的日期和時間部分。其值按照類似於 ISO 8601日期的數字給出。
在用一個域聲明書寫一個間隔常量時,或者為一個用域聲明定義的間隔列賦予一個串時,對於為標記的量的解釋依賴於域。例如INTERVAL '1' YEAR被解讀成1年,而INTERVAL '1'表示1秒。同樣,域聲明允許的最後一個有效域"右邊"的域值會被無聲地丟棄掉。例如書寫INTERVAL '1 day 2:03:04' HOUR TO MINUTE將會導致丟棄秒域,而不是日域。
根據SQL標準,一個間隔值的所有域都必須由相同的符號,這樣一個領頭的負號將會應用到所有域;例如在間隔文字'-1 2:03:04'中的負號會被應用於日、小時、分鍾和秒部分。PostgreSQL允許域具有不同的符號,並且在習慣上認為以文本表示的每個域具有獨立的符號,因此在這個例子中小時、分鍾和秒部分被認為是正值。如果IntervalStyle被設置為sql_standard,則一個領頭的符號將被認為是應用於所有域(但是僅當沒有額外符號出現)。否則將使用傳統的PostgreSQL解釋。為了避免混淆,我們推薦在任何域為負值時為每一個域都附加一個顯式的符號。
內部的interval值被存儲為月、日和秒。這是因為一個月中的天數是變化的,並且在涉及到夏令時調整時一天可以有23或25小時。月和日域是整數,而秒域可以存儲分數。因為間隔通常都是從常數字符串或timestamp減法創建而來,這種存儲方法在大部分情況都工作良好。函數justify_days和justify_hours可用於調整超過其常見範圍的日數和小時數。
在冗長的輸入格式中,以及在更緊湊輸入格式的某些域中,域值可以有分數部分;例如'1.5 week'或'01:02:03.45'。這樣的輸入被轉換為合適的月數、日數和秒數用於存儲。當這樣會導致月和日中的分數時,分數被加到低序域中,使用的轉換因子是1月=30日和1日=24小時。例如,'1.5 month'會變成1月和15日。隻有秒總是在輸出時被顯示為分數。
Table 8-17展示了一些有效interval輸入的例子。
Table 8-17. 間隔輸入
5.5. 間隔輸出
間隔類型的輸出格式可以被設置為四種風格之一:sql_standard、postgres、postgres_verbose或iso_8601,設置方法使用SET intervalstyle命令。默認值為postgres格式。Table 8-18展示了每種輸出風格的例子。
如果間隔值符合SQL標準的限製(僅年-月或僅日-時間,沒有正負值部分的混合),sql_standard風格為間隔文字串產生符合SQL標準規範的輸出。否則輸出將看起來像一個標準的年-月文字串跟著一個日-時間文字串,並且帶有顯式添加的符號以區分混合符號的間隔。
當DateStyle參數被設置為ISO時,postgres風格的輸出匹配PostgreSQL 8.4版本以前的輸出。
當DateStyle參數被設置為非ISO輸出時,postgres_verbose風格的輸出匹配PostgreSQL 8.4版本以前的輸出。
iso_8601風格的輸出匹配在ISO 8601標準的4.4.3.2小節中描述的"帶標誌符的格式"。
PostgreSQL提供標準的SQL類型boolean,參見Table 8-19。boolean可以有多個狀態:"true(真)"、"false(假)"和第三種狀態"unknown(未知)",未知狀態由SQL空值表示。
"真"狀態的有效文字值是:
TRUE
't'
'true'
'y'
'yes'
'on'
'1'
而對於"假"狀態,你可以使用下麵這些值:
FALSE
'f'
'false'
'n'
'no'
'off'
'0'
前導或者末尾的空白將被忽略,並且大小寫也無關緊要。使用TRUE和FALSE這樣的關鍵詞比較好(SQL兼容)。
Example 8-2顯示了使用字母t和f輸出boolean值的例子。
Example 8-2. 使用boolean類型
CREATE TABLE test1 (a boolean, b text);
INSERT INTO test1 VALUES (TRUE, 'sic est');
INSERT INTO test1 VALUES (FALSE, 'non est');
SELECT * FROM test1;
a | b
---+---------
t | sic est
f | non est
SELECT * FROM test1 WHERE a;
a | b
---+---------
t | sic est
枚舉(enum)類型是由一個靜態、值的有序集合構成的數據類型。它們等效於很多編程語言所支持的enum類型。枚舉類型的一個例子可以是一周中的日期,或者一個數據的狀態值集合。
7.1. 枚舉類型的聲明
枚舉類型可以使用CREATE TYPE命令創建,例如:
CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy');
一旦被創建,枚舉類型可以像很多其他類型一樣在表和函數定義中使用:
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)
7.2. 排序
一個枚舉類型的值的排序是該類型被創建時所列出的值的順序。枚舉類型的所有標準的比較操作符以及相關聚集函數都被支持。例如:
INSERT INTO person VALUES ('Larry', 'sad');
INSERT INTO person VALUES ('Curly', 'ok');
SELECT * FROM person WHERE current_mood > 'sad';
name | current_mood
-------+--------------
Moe | happy
Curly | ok
(2 rows)
SELECT * FROM person WHERE current_mood > 'sad' ORDER BY current_mood;
name | current_mood
-------+--------------
Curly | ok
Moe | happy
(2 rows)
SELECT name
FROM person
WHERE current_mood = (SELECT MIN(current_mood) FROM person);
name
-------
Larry
(1 row)
7.3. 類型安全性
每一種枚舉數據類型都是獨立的並且不能和其他枚舉類型相比較。看這樣一個例子:
CREATE TYPE happiness AS ENUM ('happy', 'very happy', 'ecstatic');
CREATE TABLE holidays (
num_weeks integer,
happiness happiness
);
INSERT INTO holidays(num_weeks,happiness) VALUES (4, 'happy');
INSERT INTO holidays(num_weeks,happiness) VALUES (6, 'very happy');
INSERT INTO holidays(num_weeks,happiness) VALUES (8, 'ecstatic');
INSERT INTO holidays(num_weeks,happiness) VALUES (2, 'sad');
ERROR: invalid input value for enum happiness: "sad"
SELECT person.name, holidays.num_weeks FROM person, holidays
WHERE person.current_mood = holidays.happiness;
ERROR: operator does not exist: mood = happiness
如果你確實需要做這樣的事情,你可以寫一個自定義的操作符或者在查詢中加上顯式造型:
SELECT person.name, holidays.num_weeks FROM person, holidays
WHERE person.current_mood::text = holidays.happiness::text;
name | num_weeks
------+-----------
Moe | 4
(1 row)
7.4. 實現細節
一個枚舉值在磁盤上占據4個字節。一個枚舉值的文本標簽的長度受限於NAMEDATALEN設置,該設置被編譯在PostgreSQL中,在標準編譯下它表示最多63字節。
枚舉標簽是大小寫敏感的,因此'happy'是不同於'HAPPY'的。標簽內的空白也是有效的。
從內部枚舉值到文本標簽的翻譯被保存在係統目錄pg_enum中。可以直接查詢該目錄。
幾何數據類型表示二維的空間物體。Table 8-20展示了PostgreSQL中可以用的幾何類型。
我們有一係列豐富的函數和操作符可用來進行各種幾何操作, 如縮放、平移、旋轉和計算相交等 。
8.1. 點
點是幾何類型的基本二維構造塊。用下麵的語法描述point類型的值:
( x , y )
x , y
其中x和y分別是坐標,都是浮點數。
點使用第一種語法輸出。
8.2. 線
線由線性方程Ax + By + C = 0 表示,其中A和B都不為零。類型line 的值采用以下形式輸入和輸出:
{ A, B, C }
另外,還可以用下列任一形式輸入:
[ ( x1 , y1 ) , ( x2 , y2 ) ]
( ( x1 , y1 ) , ( x2 , y2 ) )
( x1 , y1 ) , ( x2 , y2 )
x1 , y1 , x2 , y2
其中 (x1,y1) 和 (x2,y2) 是線上不同的兩點。
8.3. 線段
線段用一對線段的端點來表示。lseg類型的值用下麵的語法聲明:
[ ( x1 , y1 ) , ( x2 , y2 ) ]
( ( x1 , y1 ) , ( x2 , y2 ) )
( x1 , y1 ) , ( x2 , y2 )
x1 , y1 , x2 , y2
其中(x1,y1) 和 (x2,y2) 是線段的端點。
線段使用第一種語法輸出。
8.4. 方框
方框用其對角的點對表示。box類型的值使用下麵的語法指定:
( ( x1 , y1 ) , ( x2 , y2 ) )
( x1 , y1 ) , ( x2 , y2 )
x1 , y1 , x2 , y2
其中(x1,y1) 和 (x2,y2) 是方框的對角點。
方框使用第二種語法輸出。
在輸入時可以提供任意兩個對角,但是值將根據需要被按順序記錄為右上角和左下角。
8.5. 路徑
路徑由一係列連接的點組成。路徑可能是開放的,也就是認為列表中第一個點和最後一個點沒有被連接起來;也可能是封閉的,這時認為第一個和最後一個點被連接起來。
path類型的值用下麵的語法聲明:
[ ( x1 , y1 ) , ... , ( xn , yn ) ]
( ( x1 , y1 ) , ... , ( xn , yn ) )
( x1 , y1 ) , ... , ( xn , yn )
( x1 , y1 , ... , xn , yn )
x1 , y1 , ... , xn , yn
其中的點是組成路徑的線段的端點。方括弧([])表示一個開放的路徑,圓括弧(())表示一個封閉的路徑。如第三種到第五種語法所示,當最外麵的圓括號被忽略時,路徑將被假定為封閉。
路徑的輸出使用第一種或第二種語法。
8.6. 多邊形
多邊形由一係列點代表(多邊形的頂點)。多邊形和封閉路徑很像,但是存儲方式不一樣而且有自己的一套支持例程。
polygon類型的值用下列語法聲明:
( ( x1 , y1 ) , ... , ( xn , yn ) )
( x1 , y1 ) , ... , ( xn , yn )
( x1 , y1 , ... , xn , yn )
x1 , y1 , ... , xn , yn
其中的點是組成多邊形邊界的線段的端點。
多邊形的輸出使用第一種語法。
8.7. 圓
圓由一個圓心和一個半徑代表。circle類型的值用下麵的語法指定:
< ( x , y ) , r >
( ( x , y ) , r )
( x , y ) , r
x , y , r
其中(x,y)是圓心,而r是圓的半徑。
圓的輸出用第一種語法。
PostgreSQL提供用於存儲 IPv4、IPv6 和 MAC 地址的數據類型,如Table 8-21所示。 用這些數據類型存儲網絡地址比用純文本類型好,因為這些類型提供輸入錯誤檢查以及特殊的操作符和函數.
在對inet或者cidr數據類型進行排序的時候, IPv4 地址將總是排在 IPv6 地址前麵,包括那些封裝或者是映射在 IPv6 地址裏 的 IPv4 地址,例如 ::10.2.3.4 或者 ::ffff::10.4.3.2。
9.1. inet
inet在一個數據域裏保存一個 IPv4 或 IPv6 主機地址,以及一個可選的它的子網。 子網由主機地址中表示的網絡地址位數表示("網絡掩碼")。 如果網絡掩碼為 32 並且地址是 IPv4 ,那麼該值不表示任何子網,隻是一台主機。在 IPv6 中地址長度是 128 位,因此 128 位指定一個唯一的主機地址。 請注意如果你想隻接受網絡地址,你應該使用cidr類型而不是inet。
該類型的輸入格式是地址/y,其中地址是一個 IPv4 或者 IPv6 地址,y是網絡掩碼的位數。如果/y部分缺失, 則網絡掩碼對 IPv4 而言是 32,對 IPv6 而言是 128,所以該值表示隻有一台主機。在顯示時,如果/y部分指定一個單台主機,它將不會被顯示出來。
9.2. cidr
cidr類型保存一個 IPv4 或 IPv6 網絡地址聲明。其輸入和輸出遵循無類的互聯網域路由(Classless Internet Domain Routing)習慣。聲明一個網絡的格式是地址/y,其中address是 IPv4 或 IPv6 網絡地址而y是網絡掩碼的位數。如果省略y, 那麼掩碼部分用舊的有類的網絡編號係統進行計算,否則它將至少大到足以包括寫在輸入中的所有字節。聲明一個在其指定的掩碼右邊置了位的網絡地址會導致錯誤。
Table 8-22展示了一些例子。
9.3. inet vs. cidr
inet和cidr類型之間的本質區別是inet接受右邊有非零位的網絡掩碼, 而cidr不接受。
Tip: 如果你不喜歡inet或cidr值的輸出格式,可以嚐試函數host、text和abbrev。
9.4. macaddr
macaddr類型存儲 MAC 地址,也就是以太網卡硬件地址 (盡管 MAC 地址還用於其它用途)。可以接受下列格式的輸入:
'08:00:2b:01:02:03'
'08-00-2b-01-02-03'
'08002b:010203'
'08002b-010203'
'0800.2b01.0203'
'0800-2b01-0203'
'08002b010203'
這些例子指定的都是同一個地址。對於位a到f,大小寫都可以接受。輸出總是使用展示的第一種形式。
IEEE Std 802-2001 指定第二種展示的形式(帶有連字符)作為MAC地址的標準形式,並且指定第一種形式(帶有分號)作為位翻轉的記號,因此 08-00-2b-01-02-03 = 01:00:4D:08:04:0C。這種習慣目前已經被廣泛地忽略,並且它隻與廢棄的網絡協議(如令牌環)相關。PostgreSQL 沒有對位翻轉做任何規定,並且所有可接受的格式都使用標準的LSB順序。
剩下的五種輸入格式不屬於任何標準。
位串就是一串 1 和 0 的串。它們可以用於存儲和可視化位掩碼。我們有兩種類型的 SQL 位類型:bit(n)和bit varying(n),其中 n是一個正整數。
bit類型的數據必須準確匹配長度n; 試圖存儲短些或者長一些的位串都是錯誤的。bit varying數據是最長n的變長類型,更長的串會被拒絕。寫一個沒有長度的bit等效於 bit(1),沒有長度的bit varying意味著沒有長度限製。
Note:
如果我們顯式地把一個位串值轉換成bit(n), 那麼它的右邊將被截斷或者在右邊補齊零,直到剛好n位, 而且不會拋出任何錯誤。類似地,如果我們顯式地把一個位串數值轉換成bit varying(n),如果它超過了n位, 那麼它的右邊將被截斷。
請參考Section 4.1.2.5獲取有關位串常量的語法的信息。還有一些位邏輯操作符和串操作函數可用。
Example 8-3. 使用位串類型
CREATE TABLE test (a BIT(3), b BIT VARYING(5));
INSERT INTO test VALUES (B'101', B'00');
INSERT INTO test VALUES (B'10', B'101');
ERROR: bit string length 2 does not match type bit(3)
INSERT INTO test VALUES (B'10'::bit(3), B'101');
SELECT * FROM test;
a | b
-----+-----
101 | 00
100 | 101
一個位串值對於每8位的組需要一個字節,外加總共5個或8個字節,這取決於串的長度(但是長值可能被壓縮或者移到線外)。
PostgreSQL提供兩種數據類型,它們被設計用來支持全文搜索,全文搜索是一種在自然語言的文檔集合中搜索以定位那些最匹配一個查詢的文檔的活動。tsvector類型表示一個為文本搜索優化的形式下的文檔,tsquery類型表示一個文本查詢。
11.1. tsvector
一個tsvector值是一個排序的可區分詞位的列表,詞位是被正規化合並了同一個詞的不同變種的詞。排序和去重是在輸入期間自動完成的,如下例所示:
SELECT 'a fat cat sat on a mat and ate a fat rat'::tsvector;
tsvector
----------------------------------------------------
'a' 'and' 'ate' 'cat' 'fat' 'mat' 'on' 'rat' 'sat'
要表示包含空白或標點的詞位,將它們用引號包圍:
SELECT $$the lexeme ' ' contains spaces$$::tsvector;
tsvector
-------------------------------------------
' ' 'contains' 'lexeme' 'spaces' 'the'
(我們在這個例子中使用美元符號包圍的串文字並且下一個用來避免在文字中包含雙引號記號產生的混淆)。嵌入的引號和反斜線必須被雙寫:
SELECT $$the lexeme 'Joe''s' contains a quote$$::tsvector;
tsvector
------------------------------------------------
'Joe''s' 'a' 'contains' 'lexeme' 'quote' 'the'
可選的,整數位置可以被附加給詞位:
SELECT 'a:1 fat:2 cat:3 sat:4 on:5 a:6 mat:7 and:8 ate:9 a:10 fat:11 rat:12'::tsvector;
tsvector
-------------------------------------------------------------------------------
'a':1,6,10 'and':8 'ate':9 'cat':3 'fat':2,11 'mat':7 'on':5 'rat':12 'sat':4
一個位置通常表示源詞在文檔中的定位。位置信息可以被用於鄰近排名。位置值可以從 1 到 16383,更大的數字會被 16383。對於相同的詞位出現的重複位置將被丟棄。
具有位置的詞位可以進一步地被標注一個權重,它可以是A、 B、C或D。 D是默認值並且因此在輸出中不會顯示:
SELECT 'a:1A fat:2B,4C cat:5D'::tsvector;
tsvector
----------------------------
'a':1A 'cat':5 'fat':2B,4C
權重通常被用來反映文檔結構,例如將主題詞標記成與正文詞不同。文本搜索排名函數可以為不同的權重標記器分配不同的優先級。
了解tsvector類型本身並不執行任何詞正規化這一點很重要,它假定給它的詞已經被恰當地為應用正規化過。例如,
SELECT 'The Fat Rats'::tsvector;
tsvector
--------------------
'Fat' 'Rats' 'The'
對於大部分英語文本搜索應用,上麵的詞將會被認為是非正規化的,但是tsvector並不在乎這一點。原始文檔文本通常應該經過to_tsvector以恰當地為搜索正規化其中的詞:
SELECT to_tsvector('english', 'The Fat Rats');
to_tsvector
-----------------
'fat':2 'rat':3
11.2. tsquery
一個tsquery值存儲要用於搜索的詞位,並且使用布爾操作符&(AND)、|(OR)和!(NOT)來組合它們,還有短語搜索操作符<->(FOLLOWED BY)。也有一種 FOLLOWED BY 操作符的變體<N>,其中N是一個整數常量,它指定要搜索的兩個詞位之間的距離。<->等效於<1>。
圓括號可以被用來強製對操作符分組。如果沒有圓括號,!(NOT)的優先級最高,其次是< ->(FOLLOWED BY),然後是&(AND),最後是|(OR)。
這裏有一些例子:
SELECT 'fat & rat'::tsquery;
tsquery
---------------
'fat' & 'rat'
SELECT 'fat & (rat | cat)'::tsquery;
tsquery
---------------------------
'fat' & ( 'rat' | 'cat' )
SELECT 'fat & rat & ! cat'::tsquery;
tsquery
------------------------
'fat' & 'rat' & !'cat'
SELECT '(fat | rat) <-> cat'::tsquery;
tsquery
-----------------------------------
'fat' <-> 'cat' | 'rat' <-> 'cat'
最後一個例子說明tsquery有時候會把嵌套的操作符重新組織成一個邏輯上等價的公式。
可選地,一個tsque
最後更新:2017-08-17 16:32:32