Postgresql学习笔记之——数据类型之Range类型

一、Range类型介绍

Range类型是PG 9.2之后开始出现的一种特有的类型,用于表现范围,如一个整数的范围、一个时间的范围,而范围底下的基本类型(如整数、时间)则被成为Range类型的subtype。
Range数据类型可以更快的在范围条件查询中检索到数据。
例如:
某个IP地址库记录了每个地区的IP地址的范围,现在需要查询指定IP地址在那个地区,IP库记录表为如下结构:
create table tb_ip_range(
begin_ip inet,
end_ip inet,
area text,
sp text);
现在查询IP地址192.188.17.120在那个地区,对应的查询语句如下:
select * from tb_ip_range where begin_ip <= ‘192.188.17.120’::inet and end_id >= ‘192.188.17.120’::inet
虽然在表上的begin_ip和end_ip列都创建了索引,但是在Postgresql中,虽然SQL语句会走索引,但是查询方式时分别扫描两个索引建位图,然后通过位图进行and操作,对比SQL语句的执行计划,索引的范围扫描还不是最高效的。
Range类型时通过创建空间索引的方式执行SQL语句,例如:
创建类似的IP地址库表:

1.创建Range类型:
create type inetrange as Range (subtype=inet);

2.创建IP范围表:
create table tb_ip_range(
ip_range inetrange,
area text,
sp text);

3.在ip_range列上创建索引,然后通过包含运算符 ”@>“ 查找对应的数据:
select * from tb_ip_range where ip_range @> ‘192.188.17.120’::inet

查看对应的SQL语句的执行计划可以明显看到性能提高很多。

二、Range类型的创建

在Postgresql中已经内置了一些常用的Range类型,可以不用执行create type xxx as range来创建:
int4range : 4字节整数的范围类型
int8range : 8字节大整数的范围类型
numrange : numeric的范围类型
tsrange : 无时区的时间戳范围类型
tstzrange : 带时区的时间戳范围类型
daterange : 日期的范围类型

示例:

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

# 整数是否包含在范围内
postgres=# select int4range(10,20) @> 3;
 ?column? 
----------
 f
(1 row)

postgres=# select int4range(10,20) @> 11;
 ?column? 
----------
 t
(1 row)

# 判断两个范围是否有交集,有true,没有false
postgres=# select numrange(11.1,22.2) && numrange(20.0,30.0);
 ?column? 
----------
 t
(1 row)

postgres=# select numrange(11.1,22.2) && numrange(23.0,30.0);
 ?column? 
----------
 f
(1 row)

# 使用uper提取范围的最大边界
postgres=# select upper(int8range(15,30));
 upper 
-------
    30
(1 row)

postgres=# select upper(int8range(15,35));
 upper 
-------
    35
(1 row)

# 提取两个范围共同的交集
postgres=# select int4range(10, 20) * int4range(15, 25);
 ?column? 
----------
 [15,20)
(1 row)

postgres=# select int4range(10, 30) * int4range(15, 25);
 ?column? 
----------
 [15,25)
(1 row)


postgres=# select isempty(numrange(1,5));
 isempty 
---------
 f
(1 row)

如果以上内置的range类型不符合你的要求,可以使用CREATE TYPE来创建自定义的Range类型,语法如下:
CREATE TYPE name AS RANGE(
SUBTYPE = subtype
[ , SUBYTPE_OPCLASS = subtype_operator_class ]
[ , CLLATION = collation ]
[ , CANONICAL = canonical_function ]
[ , SUBTYPE_DIFF = subtype_diff_function ]

说明:
1.SUBTYPE = subtype:指定子类型
2.SUBYTPE_OPCLASS = subtype_operator_class:指定子类型的操作符
3.CLLATION = collation:指定排序规则
4.CANONICAL = canonical_function:如果要创建一个稀疏的Range类型,而不是一个连续的Range类型,那就定义此函数
5.SUBTYPE_DIFF = subtype_diff_function:定义子类型的差别函数

示例:
CREATE TYPE floatrange AS RANGE(
SUBTYPE=float8;
SUBTYPE_DIFF=float8mi
);

三、Range类型的输入

Range类型的输入格式:
’(lower-bound,upper-bound)‘
‘(lower-bound,upper-bound]’
’[lower-bound,upper-bound)‘
‘[lower-bound,upper-bound]’
’empty‘

其中,”(“ 和 ”)“ 表示定义的范围不包括此元素,”[“ 和 ”]“ 表示定义的范围包括此元素,’empty‘ 表示空,空表示范围内不包含任何东西。
示例:

-- includes 3, does not include 7, and does include all points in between
SELECT '[3,7)'::int4range;

-- does not include either 3 or 7, but includes all points in between
SELECT '(3,7)'::int4range;

-- includes only the single point 4
SELECT '[4,4]'::int4range;

-- includes no points (and will be normalized to 'empty')
SELECT '[4,4)'::int4range;

每个范围类型都有一个与范围类型同名的构造函数。使用构造函数通常比编写范围文字常量更方便,因为它避免了对绑定值的额外引用。构造函数接受两个或三个参数。两个参数的形式以标准形式构造一个范围(下界包括,上界排除),而三个参数的形式构造一个范围,其边界由第三个参数指定。第三个参数必须是字符串“()”、“()”、“()”或“[]”中的一个。例如:

-- The full form is: lower bound, upper bound, and text argument indicating inclusivity/exclusivity of bounds.
postgres=# select numrange(1.0, 14.0, '(]');
  numrange  
------------
 (1.0,14.0]
(1 row)

-- If the third argument is omitted, '[)' is assumed.
postgres=# select numrange(1.0, 14.0);
  numrange  
------------
 [1.0,14.0)
(1 row)

-- Although '(]' is specified here, on display the value will be converted to
-- canonical form, since int8range is a discrete range type (see below).
postgres=# select int8range(1, 14, '(]');
 int8range 
-----------
 [2,15)
(1 row)

Range类型还可以表示极值的区间,例如:

1.表示从1开始到int4可以表示的最大值:

postgres=# select '[1,)'::int4range;
 int4range 
-----------
 [1,)
(1 row)

2.表示从int4可以表示的最小值到1的范围:

postgres=# select '[,1)'::int4range;
 int4range 
-----------
 (,1)
(1 row)

3.对于numrange范围,可以表示无穷大或者无穷小,例如,从1到无穷大与负无穷到1:

postgres=# select '[1,)'::numrange;
 numrange 
----------
 [1,)
(1 row)

postgres=# select '[,1)'::numrange;
 numrange 
----------
 (,1)
(1 row)

注意:与numrange不同的是,int4range里不是无穷大或者负无穷,因为int4有具体的范围。

四、Range类型的操作符和函数

1.Range类型支持的操作符:

操作符描述例子结果
=等于select int4range’[1,5)’ = ‘[1,4]’::int4range;t
<>不等于select numrange(1.1,1.2) <> numrange(1.1,1.3);t
<小于select int4range ‘[1,10)’ < int4range’[2,3)’;t
>大于select int4range ‘[2,3)’ > int4range’[1,100)’;t
<=小于等于select int4range’[2,3)’<= int4range’[1,2)’;f
>=大于等于select int4range’[2,3)’>= int4range’[1,2)’;t
@>包含(左边包含了右边)select int4range’[1,3)’ @> int4range’[1,2)’;t
<@被包含(右边包含左边)select int4range’[1,2)’ <@ int4range’[1,4)’;t
&&重叠(两个范围有交集)select int4range’[1,2)’ && int4range’[1,4)’;t
<<严格在左(没有重叠值)select int4range’[1,2)’ << int4range’[2,4)’;t
>>严格在右select int4range’[2,4)’ >> int4range’[1,2)’;t
&<没有扩展到右边select int4range’[1,2)’ &< int4range’[1,4)’;t
&>没有扩展到左边select int4range’[1,2)’ &> int4range’[1,4)’;t
-l-链接在一起(值没有交集)select int4range’[1,2)’ -- int4range’[2,4)’;
+union(将两个范围合并在一起)select int4range’[1,2)’ + int4range’[2,4)’;[1,4)
*intersectionselect int4range’[1,4)’ * int4range’[2,5)’;[2,4)
-differenceselect int4range’[1,4)’ - int4range’[2,5)’;[1,2)

2.Range类型的函数:

1.lower(anyrange) : 获得范围的起始值

postgres=# select lower(int4range '[11,22)');
 lower 
-------
    11
(1 row)

postgres=# select lower(int4range '[11,22)') is null;;
 ?column? 
----------
 f
(1 row)

postgres=# select lower(int4range '[11,22)') is not null;
 ?column? 
----------
 t
(1 row)

2.upper(anyrange):获得范围的结束值

postgres=# select upper(int4range '[11,22)');
 upper 
-------
    22
(1 row)

postgres=# select upper(int4range '[11,34]');
 upper 
-------
    35
(1 row)

注意:获取的范围结束值是不包含在范围内的最大值!

3.isempty(anyrange):是否是空范围

postgres=# select isempty(int4range'empty');
 isempty 
---------
 t
(1 row)

postgres=# select isempty(int4range'(,)');
 isempty 
---------
 f
(1 row)

postgres=# select isempty(int4range'(1,1)');
 isempty 
---------
 t
(1 row)

postgres=# select isempty(int4range'[1,2)');
 isempty 
---------
 f
(1 row)

4.lower_inc(anyrange):起始值是否在范围内

postgres=# select lower_inc(int4range'(1,2)');
 lower_inc 
-----------
 f
(1 row)

postgres=# select lower_inc(int4range'[1,2)');
 lower_inc 
-----------
 t
(1 row)

postgres=# select lower_inc(int4range'(1,4]');
 lower_inc 
-----------
 t
(1 row)

5.upper_inc(anyrange):结束值是否在范围内

postgres=# select upper_inc(int4range'(1,2)');
 upper_inc 
-----------
 f
(1 row)

postgres=# select upper_inc(int4range'(1,3]');
 upper_inc 
-----------
 f
(1 row)

6.lower_inf(anyrange):起始值是否是一个无穷值
7.upper_inf(anyrange):结束值是否是一个无穷值

五、Range类型的索引和约束

1.索引:

可以为范围类型的表列创建GiST和SP-GiST索引。例如,创建一个GiST索引:

CREATE INDEX reservation_idx ON reservation USING GIST (during);

索引创建后可以在SQL语句中使用Range类型的操作符来进行索引数据检索。

此外,可以为范围类型的表列创建B-tree和hash索引。对于这些索引类型,基本上惟一有用的范围操作是相等操作。有一个为范围值定义的B-tree排序,具有相应的<和>操作符,但是排序是相当随意的,在现实世界中通常没有用处。Range类型的b -树和散列支持主要是为了允许在查询内部进行排序和散列,而不是创建实际的索引。

2.约束

在Range类型的列上一般创建排除约束,让其范围总是不重叠的,例如:

CREATE TABLE reservation (
    during tsrange,
    EXCLUDE USING GIST (during WITH &&)
);

INSERT INTO reservation VALUES
    ('[2010-01-01 11:30, 2010-01-01 15:00)');
INSERT 0 1

INSERT INTO reservation VALUES
    ('[2010-01-01 14:45, 2010-01-01 15:45)');
ERROR:  conflicting key value violates exclusion constraint "reservation_during_excl"
DETAIL:  Key (during)=(["2010-01-01 14:45:00","2010-01-01 15:45:00")) conflicts
with existing key (during)=(["2010-01-01 11:30:00","2010-01-01 15:00:00")).

由以上例子看出,列上创建了排他约束,插入数据时,如果与原有数据范围有重叠时就会报错。

如果有一个两个列的表,第一个列时普通类型是 id ,第二个时Range类型是 during ,插入数据时判断,如果 id 值相等时,如果Range列范围有重叠,插入报错,如果 id 值不相等,那么Range列即使范围重叠也不报错,可以进行数据插入。这时就需要Postgresql的扩展模块 btree_gist 来实现:

CREATE EXTENSION btree_gist;
CREATE TABLE room_reservation (
    id intege,
    during tsrange,
    EXCLUDE USING GIST (room WITH =, during WITH &&)
);

INSERT INTO room_reservation VALUES
    (1, '[2010-01-01 14:00, 2010-01-01 15:00)');
INSERT 0 1

INSERT INTO room_reservation VALUES
    (1, '[2010-01-01 14:30, 2010-01-01 15:30)');
ERROR:  conflicting key value violates exclusion constraint "room_reservation_room_during_excl"
DETAIL:  Key (room, during)=(123A, ["2010-01-01 14:30:00","2010-01-01 15:30:00")) conflicts
with existing key (room, during)=(123A, ["2010-01-01 14:00:00","2010-01-01 15:00:00")).

INSERT INTO room_reservation VALUES
    (2, '[2010-01-01 14:30, 2010-01-01 15:30)');
INSERT 0 1
好的,我可以和你分享一些关于 PostgreSQL学习笔记。 1. PostgreSQL 是什么? PostgreSQL 是一种开源的关系型数据库管理系统,它支持 SQL 语言和 ACID 事务处理,并且具有丰富的特性和扩展性,可用于大型企业应用、Web 应用和嵌入式应用。 2. PostgreSQL 的特点 PostgreSQL 具有以下特点: - 开源免费 - 支持 ACID 事务处理 - 支持 SQL 语言 - 支持复杂查询和数据类型 - 支持存储过程和触发器 - 可以扩展和定制 - 可以跨平台运行 3. PostgreSQL 的安装 在 Windows 平台下,可以从官网下载 Windows 安装程序进行安装。在 Linux 平台下,可以使用包管理器安装,例如 Ubuntu 可以使用以下命令进行安装: ``` sudo apt-get install postgresql ``` 4. PostgreSQL 的基本操作 创建数据库: ``` CREATE DATABASE databasename; ``` 创建表: ``` CREATE TABLE tablename ( column1 datatype, column2 datatype, column3 datatype, .... ); ``` 插入数据: ``` INSERT INTO tablename (column1, column2, column3, ...) VALUES (value1, value2, value3, ...); ``` 查询数据: ``` SELECT column1, column2, ... FROM tablename WHERE condition; ``` 更新数据: ``` UPDATE tablename SET column1 = value1, column2 = value2, ... WHERE condition; ``` 删除数据: ``` DELETE FROM tablename WHERE condition; ``` 5. PostgreSQL 的扩展 PostgreSQL 可以通过扩展来增强其功能,例如: - PostGIS:空间数据处理扩展 - PL/Python:Python 语言扩展 - pgAdmin:可视化管理工具 - pgpool-II:连接池和负载均衡工具 以上就是一些关于 PostgreSQL 的基本学习笔记,希望对你有所帮助。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Major_ZYH

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值