postgresql 使用 order by 和 default 参数创建聚合
postgresql create aggregate with order by and default parameter
在 Postgres 中 9.x 我可以这样做
select dept_id, string_agg(user_id, ':' order by user_id)
from dept_user
group by dept_id;
+---------+------------+
| dept_id | string_agg |
+---------+------------+
| d1 | u1:u2:u3 |
| d2 | u3:u4 |
+---------+------------+
但是我的公司使用 Postgres 8.3,所以我发现聚合函数可以像 string_agg
create schema WMSYS;
create or replace function WMSYS.sf_concat(text,text) returns text as $$
select case when coalesce(, '') <> '' then ||','|| else end;
$$ language sql called on null input;
create aggregate WMSYS.wm_concat (text) (sfunc=WMSYS.sf_concat,stype=text);
结果是:
select dept_id, WMSYS.wm_concat(user_id)
from dept_user
group by dept_id;
+---------+-----------+
| dept_id | wm_concat |
+---------+-----------+
| d1 | u3,u1,u2 |
| d2 | u3,u4 |
+---------+-----------+
但是结果没有排序(u3,u1,u2
应该是u1,u2,u3
)并且join string(,
)不是参数。
我想要这样的用法:
WMSYS.wm_concat(user_id) ## join by ',' and don't sort
WMSYS.wm_concat(user_id, ':') ## join by ':' and don't sort
WMSYS.wm_concat(user_id, ':', true) ## join by ':' and order by user_id
怎么做?
请尝试:
SELECT dept_id, replace(WMSYS.wm_concat(user_id, ',', ':')
FROM (
SELECT dept_id, user_id
FROM dept_user
ORDER BY 1, 2
) AS A
GROUP BY dept_id;
试试这个:
正在准备数据样本:
t=# create table a1 (i int, t text);
CREATE TABLE
t=# insert into a1 select 1,'u'||g from generate_series(1,9,1) g;
INSERT 0 9
t=# update a1 set i =2 where ctid > '(0,4)';
UPDATE 5
t=# select i,WMSYS.wm_concat(t) from a1 group by i;
i | wm_concat
---+----------------
1 | u1,u2,u3,u4
2 | u5,u6,u7,u8,u9
(2 rows)
只需添加另一个参数:
create or replace function WMSYS.sf_concat(text,text,text) returns text as $$
select case when coalesce(, '') <> '' then |||| else end;
$$ language sql called on null input;
create aggregate WMSYS.wm_concat (text,text) (sfunc=WMSYS.sf_concat,stype=text);
t=# select i,WMSYS.wm_concat(t,':') from a1 group by i;
i | wm_concat
---+----------------
1 | u1:u2:u3:u4
2 | u5:u6:u7:u8:u9
(2 rows)
现在,我不知道 window 函数在 8.3 中的运行情况如何,我没有环境可以尝试这样是否可行:
t=# select i, max(t) from (select i,WMSYS.wm_concat(t,':') over (partition by i order by t desc) t from a1) a group by i;
i | max
---+----------------
1 | u4:u3:u2:u1
2 | u9:u8:u7:u6:u5
(2 rows)
但正如 Roman 所建议的,这应该:
t=# select i,WMSYS.wm_concat(t,':') from (select * from a1 order by i asc,t desc) a group by i;
i | wm_concat
---+----------------
1 | u4:u3:u2:u1
2 | u9:u8:u7:u6:u5
(2 rows)
所以你控制排序不是作为聚合函数的参数,而是通过你向它呈现数据的方式
在 Postgres 中 9.x 我可以这样做
select dept_id, string_agg(user_id, ':' order by user_id)
from dept_user
group by dept_id;
+---------+------------+
| dept_id | string_agg |
+---------+------------+
| d1 | u1:u2:u3 |
| d2 | u3:u4 |
+---------+------------+
但是我的公司使用 Postgres 8.3,所以我发现聚合函数可以像 string_agg
create schema WMSYS;
create or replace function WMSYS.sf_concat(text,text) returns text as $$
select case when coalesce(, '') <> '' then ||','|| else end;
$$ language sql called on null input;
create aggregate WMSYS.wm_concat (text) (sfunc=WMSYS.sf_concat,stype=text);
结果是:
select dept_id, WMSYS.wm_concat(user_id)
from dept_user
group by dept_id;
+---------+-----------+
| dept_id | wm_concat |
+---------+-----------+
| d1 | u3,u1,u2 |
| d2 | u3,u4 |
+---------+-----------+
但是结果没有排序(u3,u1,u2
应该是u1,u2,u3
)并且join string(,
)不是参数。
我想要这样的用法:
WMSYS.wm_concat(user_id) ## join by ',' and don't sort
WMSYS.wm_concat(user_id, ':') ## join by ':' and don't sort
WMSYS.wm_concat(user_id, ':', true) ## join by ':' and order by user_id
怎么做?
请尝试:
SELECT dept_id, replace(WMSYS.wm_concat(user_id, ',', ':')
FROM (
SELECT dept_id, user_id
FROM dept_user
ORDER BY 1, 2
) AS A
GROUP BY dept_id;
试试这个:
正在准备数据样本:
t=# create table a1 (i int, t text);
CREATE TABLE
t=# insert into a1 select 1,'u'||g from generate_series(1,9,1) g;
INSERT 0 9
t=# update a1 set i =2 where ctid > '(0,4)';
UPDATE 5
t=# select i,WMSYS.wm_concat(t) from a1 group by i;
i | wm_concat
---+----------------
1 | u1,u2,u3,u4
2 | u5,u6,u7,u8,u9
(2 rows)
只需添加另一个参数:
create or replace function WMSYS.sf_concat(text,text,text) returns text as $$
select case when coalesce(, '') <> '' then |||| else end;
$$ language sql called on null input;
create aggregate WMSYS.wm_concat (text,text) (sfunc=WMSYS.sf_concat,stype=text);
t=# select i,WMSYS.wm_concat(t,':') from a1 group by i;
i | wm_concat
---+----------------
1 | u1:u2:u3:u4
2 | u5:u6:u7:u8:u9
(2 rows)
现在,我不知道 window 函数在 8.3 中的运行情况如何,我没有环境可以尝试这样是否可行:
t=# select i, max(t) from (select i,WMSYS.wm_concat(t,':') over (partition by i order by t desc) t from a1) a group by i;
i | max
---+----------------
1 | u4:u3:u2:u1
2 | u9:u8:u7:u6:u5
(2 rows)
但正如 Roman 所建议的,这应该:
t=# select i,WMSYS.wm_concat(t,':') from (select * from a1 order by i asc,t desc) a group by i;
i | wm_concat
---+----------------
1 | u4:u3:u2:u1
2 | u9:u8:u7:u6:u5
(2 rows)
所以你控制排序不是作为聚合函数的参数,而是通过你向它呈现数据的方式