本文介绍postgresql的部分基本数据类型和基本操作,包括时间类型,字符串操作,数组操作等
postgresql下载地址:https://www.postgresql.org/download/
一、字符串操作
lpad
字符和字符串lpad(要补齐的字符串,总长度,补上的字符串)
1 | select lpad('ab',4,'0') as ab_lpad, |
split_part
postgresql分隔字符串,split_part
语法:split_part(string text, delimiter text, column integer)
1 | select split_part('abc.123.z45', '.', 2); |
string_to_array(text, text)
string_to_array(text, text)可以将一个字符串 拆分成为一个数组
1 | select a[1] from string_to_array('abc_123_z45', '_') as a; |
将字符串展开为若干记录
"unnest"(anyarray) string_to_array 和 unnest
结合使用, 可以将字符串展开为若干记录
1 | select a[1] from string_to_array('abc_123_z45', '_') as a; |
二、postgresql正则表达式和模式匹配
模式匹配
\1 和 \2是模式匹配表达式中的元素.
\(
是特殊字符 ( 的转义
1 | select regexp_replace( |
将文本中的电话号码作为单独的行返回
1 | select unnest(regexp_matches('Cell (619)852-5083. Casa 619-730-6254. Besame mucho.', |
~ 运算符
除了正则表达式专用的那些函数外,正则表达式还和 ~ 运算符 一起使用,
如下:查出所有内嵌了电话号码的字符串
1 | select description from mytable |
三、postgresql时间类型
最先进的,最全的时间类型
时间加减法:一个小时前
1 | select current_timestamp - interval '1 hour'; |
提取当前小时
1 | select extract(hour from current_timestamp); |
获取当前时间戳
1 | select current_timestamp; |
1. date
该类型仅存储 月,日,年,没有失去 , 小时 , 分 和 秒 的信息
2. time
该类型仅存储 小时,分,秒 信息, 不带日期 和 时区信息
3. timestamp
该数据类型存储了日期(年月日) 和 时间(时分秒)
4. timestamptz
存储了日期 和 时间 以及时区
5. timetz
携带了时区信息 没有日期信息
6. interval
该类型描述了时间段的长度,单位可以是小时,天, 月, 分钟, 或者 其他粒度.该类型适用于数学运算场景
7. tsrange
开区间闭区间限定符,定义了一个 从14:00 开始 到 15:00之前结束的一个时间段 timestamp
1 | select '[2012-01-01 14:00 2012-01-01 15:00)'::tsrange; |
8. tstzrange
定义 timestamptz 的开区间和闭区间
9. daterange
定义日期的开区间和闭区间
1 | select '2016-05-26 3:43:00 PM'::timestamp - interval '1 hour'; |
重叠运算
对时间戳和日期类型:使用 OVERLAPS overlaps 时间区域重叠运算符
1 | select ('2012-10-25 10:00 AM'::timestamp ,'2012-10-25 2:00 PM'::timestamp) overlaps |
生成整数序列
使用可选的步长形参,来生成整数序列
1 | select x from generate_series(1,51,13) as x; |
抽取时间类型的一部分
date_part
或者 to_char
从日期类型和时间类型的数据值中抽取一部分
1 | select dt, date_part('hour',dt) as mh,to_char(dt,'HH12:MI:AM') as tm |
generate_series
函数默认生成的是timestamptz
类型数据,需要显示转换为timestamp类型
更多时间计算问题请见:PostgreSQL的时间/日期函数使用
四 数组类型
1.数组构造函数
array(子查询,或者 数组)
1 | select array[2001,2002,2003] as yrs; |
字符串数组转化为数组
可以直接把一个字符串格式书写的数组转化为真正的数组,语法如下
1 | select '{Alex,Sonia}'::text[] as name, '{43,40}'::smallint[] as age; |
string_to_array(text, text)
string_to_array(text, text) 将一个用固定分隔符分隔的字符串转化为数组
1 | select string_to_array('ca.ma.tx','.') as estados; |
array_agg
array_agg是一种变型聚合函数,它可以使用一组任何类型的数据并将其转换为数组
1 | select array_agg(log_ts order by log_ts) as x from logs |
2.引用数组中的元素
1 | select a[1] from string_to_array('abc_123_z45_12s_12_we', '_') as a; |
3.数组拆分与连接
第一个和第5个元素 a[1:5]
1 | select a[1:5] from string_to_array('abc_123_z45_12s_12_we', '_') as a; |
将数组元素展开为记录行 unnest
1 | select unnest('{xox,oxo,xox}'::char(3)[]) as tic_tac_toe |
你可以在一个 SELECT 语句中使用多个 unnest 函数,
但如果每个 unnest 展开后的记录行数不一致,或者说“对不齐”,
那么得到的最终结果将是这些结果集之间的笛卡儿积,看起来不太好理解。
1 | SELECT |
如果你从上述一个数组中拿掉一个元素,那么两个数组的元素就无法对齐了,此时展开得到的结果如示例下
1 | SELECT |
多实参 unnest 函数,只能在from 子句中出现
使用多实参 unnest 取消不平衡数组的嵌套
1 | SELECT * FROM unnest('{blind,mouse}'::text[], '{1,2,3}'::int[]) As f(t,i); |
五、区间类型
1 | select int4range(1,5) = '[1,4]'::int4range; |
区间操作和集合操作
1 | select '[2011-01-01,2011-03-01)'::tsrange @> '2011-01-10'::timestamp; |
离散区间
int4range、int8range: 这是整数型离散区间,其定义符合前闭后开的规范化要求。
1 | select '[-2,2]'::int4range; --[-2,3) |
错误: 操作符不存在: numeric <@ int4range
没有匹配指定名称和参数类型的操作符. 您也许需要增加明确的类型转换.
numrange
这是连续区间,可以用于描述小数、浮点数、或者双精度数字的区间。
1 | select '[-2,2]'::numrange; --[-2,2] |
daterange
这是不带时区信息的日期离散区间。
1 | select '[2011-01-01,2011-03-01)'::daterange --[2011-01-01,2011-03-01) |
tsrange、tstzrange
这是时间戳(日期加时间)类型的连续区间,秒值部分支持小数。tsrange 不带时区信息,tstzrange 带时区信息。
定义含区间类型字段的表
时间类型区间是很常用的,假设你有一张 employment 表,表中存储了公司聘请雇员的历史记录。
你可以像示例 5-20 那样用时间区间来定义一个员工在公司的服务年限,
而不需要用起始时间和结束时间两个字段来表示。在本例中,
我们给 period 列添加了一个索引以使用我们的区间列加速查询。
1 | CREATE TABLE employment (id serial PRIMARY KEY, employee varchar(20), period daterange); |
适用于区间类型的运算符
区间类型上用得最多的两个运算符是重叠运算符(&&)和包含运算符(@>)。
要了解区间运算符的完整列表,请参考 PostgreSQL 官方手册中的“区间类型运算符”一节
1. 重叠运算符
顾名思义,重叠运算符 && 的作用就是判定两个区间是否有重叠部分,如果有则返回 true,否则返回 false。
示例 :查询谁与谁曾经同时在公司工作过
1 | SELECT e1.employee, string_agg(DISTINCT e2.employee, ', ' ORDER BY e2.employee) As |
2. 包含与被包含关系运算符
1 | SELECT employee FROM employment WHERE period @> CURRENT_DATE GROUP BY employee; |
六、JSON数据类型
JSON类型
形如:{key:value}
1 | CREATE TABLE families_j (id serial PRIMARY KEY, profile json); |
json_extract_path、json_array_elements 以及 json_extract_path_text
这三个函数来读取表中所有家庭成员的信息。
1 | SELECT json_extract_path_text(profile, 'name') As family, |
运算符 ->> 和 #>> 是 json_extract_path_text 的简写。#>> 取用某个路径数组。
示例使用这些符号运算符对上面进行了重写。
输出JSON数据
1 | SELECT row_to_json(f) As x |
七、构建自定义数据类型
所有表都有一个对应的自定义数据类型
尽管仅仅通过建表就可以轻松创建复合数据类型,
但有时候我们仍会需要从头开始构建自己的数据类型。
例如,使用以下语句可以构建一个复杂数字数据类型:
1 | CREATE TYPE complex_number AS (r double precision, i double precision); |
为自定义数据类型构建运算符和函数
创建运算符的第一步是创建其底层实现函数
示例 :为 complex_number 创建底层实现函数
1 | CREATE OR REPLACE FUNCTION add(complex_number, complex_number) RETURNS complex_number AS |
接下来要创建一个运算符来代表此函数
示例:为 complex_number 类型定义 + 运算符
1 | CREATE OPERATOR +( |
- 虽然我们在此处没有举例说明,但你可以对函数和运算符进行重载,
- 以使其可以接受多种不同类型的输入。例如,你可以创建一个支持 complex_number
- 和 integer 相加的 add 函数和相应的 + 计算符,这就实现了对原逻辑的扩展。
- 支持自定义数据类型和运算符让 PostgreSQL 从机制上具有了自我演进的能力,
- 开源社区无数开发人员利用此能力为 PostgreSQL 平台添砖加瓦,
- 随着这个开发平台的羽翼日渐丰满,我们离“一切皆以表驱动”的理想境界也越来越近。
在 PostgreSQL 官方手册的“创建运算符”这一节中你可以看到系统允许使用哪些字符来定义新的运算符。
参考官方手册中“运算符的优化信息”