PostgreSQL中的範圍型別
範圍型別是表達某種元素型別的一個值的範圍的資料型別。範圍型別可以表達一種單一範圍值中的多個元素值,並且可以很清晰地表達諸如範圍重疊等概念。本文將對範圍型別進行簡單介紹。
PostgreSQL帶有以下幾種內建範圍型別:
1) int4range (integer範圍)
2) int8range (bigint範圍)
3) numrange (numeric範圍)
4) tsrange (不帶時區的timestamp範圍)
5) tstzrange (帶時區的timestamp範圍)
6) daterange (date範圍)
此外,可以使用自定義的範圍型別。
有邊界的範圍
每一個非空範圍都有兩個界限,下界和上界。這些值之間的所有點都被包括在範圍內。一個包含界限意味著邊界點本身也被包括在範圍內,而一個排除邊界意味著邊界點不被包括在範圍內。
在一個範圍的文字形式中,一個包含下界被表達為“[”而一個排除下界被表達為“(”。同樣,一個包含上界被表達為“]”而一個排除上界被表達為“)”。
函式lower_inc和upper_inc分別測試一個範圍值的上下界。
一個範圍值的輸入必須遵循下列模式之一:
(lower-bound,upper-bound) (lower-bound,upper-bound] [lower-bound,upper-bound) [lower-bound,upper-bound] empty
無邊界的範圍
一個範圍的下界可以被忽略,這意味著所有小於上界的點都被包括在範圍中。同樣,如果範圍的上界被忽略,那麼所有比上界大的的都被包括在範圍中。如果上下界都被忽略,該元素型別的所有值都被認為在該範圍中。
函式lower_inf和upper_inf分別測試一個範圍的無限上下界。
構建範圍
每一種範圍型別都有一個與其同名的構造器函式。構造器函式接受兩個或三個引數。兩個引數的形式以標準的形式構造一個範圍(下界是包含的,上界是排除的),而三個引數的形式按照第三個引數指定的界限形式構造一個範圍。第三個引數必須是下列字串之一:“()”、 “(]”、 “[)”或者 “[]”。
舉幾個例子來說明構建範圍的方法:
1) 完整的形式:包括下界、上界以及指示界限包含性/排除性的文字引數。
postgres=# select tsrange('2018-10-31 12:00:00','2018-11-11 00:00:00','[]');
tsrange
-----------------------------------------------
["2018-10-31 12:00:00","2018-11-11 00:00:00"]
(1 row)
2) 如果第三個引數被忽略,則預設為“[)”。
postgres=# select numrange(2.5,12.0);
numrange
------------
[2.5,12.0)
(1 row)
3) 為一個界限使用null導致範圍在該邊界是無界的。
postgres=# select numrange(null,3.0);
numrange
----------
(,3.0)
(1 row)
範圍索引
可以為範圍型別的表列建立GiST和SP-GiST索引。一個GiST或SP-GiST索引可以加速涉及以下範圍操作符的查詢:
=
&&
<@
@>
<<
>>
-|-
&<
&>
此外,B-樹和雜湊索引可以在範圍型別的表列上建立。
範圍上的約束
唯一約束通常不適合於範圍型別。作為替代,排除約束是更加適合的方式。例如:
postgres=# create table orders(order_time tsrange,exclude using gist(order_time with &&));
CREATE TABLE
該約束將阻止任何重疊值同時存在於表中,例如:
postgres=# insert into orders values('[2018-10-31 12:00,2018-10-31 17:00)');
INSERT 0 1
postgres=# insert into orders values('[2018-10-31 15:00,2018-10-31 18:00)');
2018-10-31 17:21:37.280 CST [2119] ERROR: conflicting key value violates exclusion constraint "orders_order_time_excl"
2018-10-31 17:21:37.280 CST [2119] DETAIL: Key (order_time)=(["2018-10-31 15:00:00","2018-10-31 18:00:00")) conflicts with existing key (order_time)=(["2018-10-31 12:00:00","2018-10-31 17:00:00")).
2018-10-31 17:21:37.280 CST [2119] STATEMENT: insert into orders values('[2018-10-31 15:00,2018-10-31 18:00)');
ERROR: conflicting key value violates exclusion constraint "orders_order_time_excl"
DETAIL: Key (order_time)=(["2018-10-31 15:00:00","2018-10-31 18:00:00")) conflicts with existing key (order_time)=(["2018-10-31 12:00:00","2018-10-31 17:00:00")).
By Kalath