介绍PostgreSQL中的范围类型特性
PostgreSQL9.2的一项新特性就是范围类型rangetypes,通过这个名字你可以轻松猜出该类型的用途,它可让你为某列数据定义数值范围。
这个简单的特性可以让我们不需要定义两个字段来描述数值的开始值和结束值,一个最直观的例子就是:
postgres#CREATETABLEsalary_grid(idint,position_nametext,start_salaryint,end_salaryint); CREATETABLE postgres#INSERTINTOsalary_gridVALUES(1,'juniordevelopper',20000,30000); INSERT01 postgres#INSERTINTOsalary_gridVALUES(2,'seniordevelopper',28000,35000); INSERT01 postgres#INSERTINTOsalary_gridVALUES(3,'postgresdevelopper',50000,70000); INSERT01
这个简单的关系用于存储一个给定的职位和待遇的范围(你还需要确定工资的货币单位),重要的是你必须实现一些系统函数或者外部程序API来执行例如范围的交叉或者联合。
Postgres9.2允许你的应用直接在数据库端实现范围值,范围类型包括:
- 4位整数范围,int4range
- 8位整数范围,int8range
- 数值范围,numrange
- 无时区的时间戳范围,tsrange
- 带时间戳的时间范围,tstzrange
- 日期范围,daterange
你也可以定义自己的范围类型,Postgre官网文档给出了float的示例:
postgres#CREATETYPEfloatrangeASRANGE( postgres#subtype=float8, postgres#subtype_diff=float8mi);
有了这样一个功能,我们前面提到的工资表格例子就可以改为:
postgres=#createtablesalary_grid(idint,position_nametext,salary_rangeint4range); CREATETABLE postgres=#INSERTINTOsalary_gridVALUES(1,'juniordevelopper','[20000,30000]'); INSERT01 postgres=#INSERTINTOsalary_gridVALUES(2,'seniordevelopper','[28000,35000]'); INSERT01 postgres=#INSERTINTOsalary_gridVALUES(3,'postgresdevelopper','[50000,70000]'); INSERT01 postgres=#select*fromsalary_grid; id|position_name|salary_range ----+---------------------+--------------- 1|juniordevelopper|[20000,30001) 2|seniordevelopper|[28000,35001) 3|postgresdevelopper|[50000,70001) (3rows)
很重要的一点是,如果使用的是括号(),元组数据的上界是排除在外的,而中括号[]则上界包含其中。
数据库本身也包含不同的用于处理范围类型的函数。
你可直接获取一个给定范围的最低和最高值:
postgres=#SELECTupper(salary_range),lower(salary_range)FROMsalary_grid; upper|lower -------+------- 30001|20000 35001|28000 70001|50000 (3rows)
你可以检查某个值是否包含在给定范围内:
postgres=#SELECTsalary_range@>4000ascheck postgres=#FROMsalary_grid postgres=#WHEREposition_name='juniordevelopper'; check ------- f (1row)
这里显示4000并不包含在初级职位的待遇里[20000,30000].
这里稍微复杂了一些,你还可以检查两个范围之间的重叠的部分,这里的salary_range使用的是int4,因此int4range函数可用于此操作:
postgres=#WITHjunior_salaryAS( SELECTsalary_rangeasjunior FROMsalary_grid WHEREposition_name='juniordevelopper'), senior_salaryAS( SELECTsalary_rangeassenior FROMsalary_grid WHEREposition_name='seniordevelopper') SELECTint4range(junior)&&int4range(senior)ascheck FROMjunior_salary,senior_salary; check ------- t (1row)
这里显示的是初级和高级职位之间的工资重叠部分。
你还可以设定无上下限的范围类型,或者是只有上限或者下限的范围类型,让我们来看一个非常现实的例子:
postgres#UPDATEsalary_gridSETsalary_range='[50000,)'WHEREposition_name='postgresdevelopper'; UPDATE01 postgres=#SELECTsalary_range@>60000000ascheck postgres-#FROMsalary_gridWHEREposition_name='postgresdevelopper'; check ------- t (1row)
你可以使用lower_inf或者upper_inf来检查范围的无限值。
Postgres还有其他一些内嵌的函数(如isempty),这个可以直接从官方文档中获取详细信息。
你还可以阅读《PostgreSQL的数组》