Postgres的特色语法

Postgres号称世界上最好的开源数据库,我们自己的产品也在使用,于是乎我特地去学习了一下Postgres的特色语法,这里从书上摘抄了一些语句,忘记的时候可以翻一下。

DISTINCT ON

指定字段值去重

1
2
3
4
5
6
7
8
select distinct on (left(tract_id, 5))

left(tract_id, 5) as country, tract_id,tract_name

from census.lu_tracts

order by country, tract_id;

delete using

using可以将需要借助的一个或者多个中间表纳入到一个delete语句中

1
2
3
4
5
delete from census.facts

using census.lu_fact_types as ft

where fatcs.fact_type_id = ft.fact_type_id and ft.short_name = 's01';
将修改影响到的记录行返回给用户

delete,insert,update操作得记录行可以返回给用户

1
2
3
4
5
6
7
8
update census.lu_fact_types as f

set short_name = replace(replace(lower(f.fact_subcats[4], ' ', '_', ':', '')))

where f.fact_subcats[3] = 'Hispanic or latino:' and f.fact_subcats[4] > ''

RETURNING fact_type_id, short_name;

直接将查询结果转换为json格式
1
2
3
4
5
6
7
8
9
10
11
12
select array_to_json(array_agg(f)) as cat from(

select max(fact_type_id) as max_type, category

from census.lu_fact_types

group by category

)as f;

select json_agg(f) as cats from table as f;

窗口函数

基本窗口函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
select tract_id, val, avg(val) OVER() as val_avg 

from census.facts

where fact_type_id=86;

partition by子句

select tract_id, val, avg(val), over(partition by left(tract_id, 5)) as val_avg_contry

from census.facts

where fact_type_id=2 order by tract_id;

order by 子句

1
2
3
4
5
6
select row_number() over(order by tract_name) as rnum, tract_name

from census.lu_tracts

order by rnum limit 4;

联用partition by和order by

1
2
3
4
5
6
7
8
9
10
select tract_id, val,

sum(val) over(partition by left(tract_id, 5) order by val) as sum_country_ordered

from census.facts

where fact_type_id =2

order by left(tract_id, 5), val;

可以看出上面输出的合计值是逐行累加的,这就是在over子句中使用order by的效果,即窗口可见域是从排序后的记录集的头条记录开始,到order by字段值与当前记录值匹配的那行记录为止,因此最终呈现为动态累加的效果。

还可以通过range或者rows关键字来显示执行窗口的可见记录域。例如rows between row and 5 following

命名窗口,lead,lag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
select * from(

select

row_number() over(wt) as rnum,

substring(tract_id,1,5) as country_code,

tract_id,

lag(tract_id, 2) over wt as tract_2_before,

lead(tract_id) over wt as tract_after,

from census.lu_tracts

window wt as (partition by substring(tract_id, 1,5) order by tract_id) --将窗口命名为wt

) as x

where rnum between 2 and 3 and country_code in ('25007', '25025')

order by coutry_code, rnum;

cte表达式(公用表达式)
 cte的分类:基本CTE,可写CTE,递归CTE

  cte的 基本用法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
with cte as(

select tract_id,substring(tract_id,1,5) as country_code,

count(*) over(partition by substring(tract_id, 1,5)) as cnt_tracts

from census.lu_tracts

)

select max(tract_id) as last_tract, coutry_code, cnt_tracts

from cte

where cnt_tracts >100

group by coutry_code, cnt_tracts;

多个cte对的用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
with

cte1 as (

select

tract_id,

substring(tract_id, 1,5) as country_code,

count(*) over(partition by substring(tract_id,1,5)) as cnt_tracts

from census.lu_tracts

),

cte2 as (

select

max(tract_id) as last_tract,

country_code,

cnt_tracts

from cte1

where cnt_tracts < 8 group by country_code, cnt_tracts

)

select c.last_tract, f.fact_type_id,f.val

from census.facts as f inner join cte2 on f.tact_id = c.last_tract;

参考书籍:《PostgreSQL即学即用》