开发者社区> 问答> 正文

PostgreSQL unnest(),元素编号

当我有一个带有单独值的列时,可以使用以下unnest()函数:

myTable id | elements ---+------------ 1 |ab,cd,efg,hi 2 |jk,lm,no,pq 3 |rstuv,wxyz

select id, unnest(string_to_array(elements, ',')) AS elem from myTable

id | elem ---+----- 1 | ab 1 | cd 1 | efg 1 | hi 2 | jk ... 如何包含元素编号?即:

id | elem | nr ---+------+--- 1 | ab | 1 1 | cd | 2 1 | efg | 3 1 | hi | 4 2 | jk | 1 ... 我想要源字符串中每个元素的原始位置。我试着窗口函数(row_number(),rank()等等),但我总是得到1。也许是因为它们在源表的同一行中?

我知道这是一个不好的表设计。不是我的,我只是想解决它。 问题来源于stack overflow

展开
收起
保持可爱mmm 2020-02-08 21:41:10 1484 0
2 条回答
写回答
取消 提交回答
  • SRF函数的行号 可以通过WITH ORDINALITY 语法得到

    2020-03-05 16:30:48
    赞同 展开评论 打赏
  • Postgres 9.4或更高版本 使用WITH ORDINALITY了一组返回功能:

    当FROM子句中的函数后缀为时WITH ORDINALITY,bigint会在输出后附加一列,该 列从1开始,对于函数输出的每一行以1递增。这对于设置返回函数(例如)最有用UNNEST()。

    结合LATERALpg 9.3+中的功能,并根据pgsql-hackers上的该线程,上述查询现在可以写成:

    SELECT t.id, a.elem, a.nr FROM tbl AS t LEFT JOIN LATERAL unnest(string_to_array(t.elements, ',')) WITH ORDINALITY AS a(elem, nr) ON TRUE; LEFT JOIN ... ON TRUE保留左侧表中的所有行,即使右侧的表表达式不返回任何行。如果这无关紧要,则可以使用这种等效的,不太冗长的形式并带有一个隐式CROSS JOIN LATERAL:

    SELECT t.id, a.elem, a.nr FROM tbl t, unnest(string_to_array(t.elements, ',')) WITH ORDINALITY a(elem, nr); 如果基于实际数组(arr是数组列),则更简单:

    SELECT t.id, a.elem, a.nr FROM tbl t, unnest(t.arr) WITH ORDINALITY a(elem, nr); 甚至使用最少的语法:

    SELECT id, a, ordinality FROM tbl, unnest(arr) WITH ORDINALITY a; a自动为表和列的别名。添加的序数列的默认名称为ordinality。但是最好添加(更安全,更干净)显式的列别名和表限定列。

    PostgreSQL 8.4-9.3 这样,row_number() OVER (PARTITION BY id ORDER BY elem)您将获得根据排序顺序排列的数字,而不是字符串中原始顺序位置的顺序编号。

    您可以简单地省略ORDER BY:

    SELECT *, row_number() OVER (PARTITION by id) AS nr FROM (SELECT id, regexp_split_to_table(elements, ',') AS elem FROM tbl) t; 尽管这通常可以正常工作,但我从未见过它会在简单查询中中断,但是PostgreSQL断言了没有的行的顺序没有任何关系ORDER BY。由于实现细节,它碰巧可以工作。

    为了保证用空格分隔的字符串中元素的序号:

    SELECT id, arr[nr] AS elem, nr FROM ( SELECT *, generate_subscripts(arr, 1) AS nr FROM (SELECT id, string_to_array(elements, ' ') AS arr FROM tbl) t ) sub; 如果基于实际数组,则更简单:

    SELECT id, arr[nr] AS elem, nr FROM (SELECT *, generate_subscripts(arr, 1) AS nr FROM tbl) t; dba.SE的相关答案:

    如何在未嵌套的数组中保留元素的原始顺序? Postgres 8.1-8.4 这些功能都不是可用的,但:RETURNS TABLE,generate_subscripts(),unnest(),array_length()。但这有效:

    CREATE FUNCTION f_unnest_ord(anyarray, OUT val anyelement, OUT ordinality integer) RETURNS SETOF record LANGUAGE sql IMMUTABLE AS 'SELECT $1[i], i - array_lower($1,1) + 1 FROM generate_series(array_lower($1,1), array_upper($1,1)) i'; 特别要注意的是,数组索引可以与元素的顺序位置不同。考虑具有扩展功能的此演示:

    CREATE FUNCTION f_unnest_ord_idx(anyarray, OUT val anyelement, OUT ordinality int, OUT idx int) RETURNS SETOF record LANGUAGE sql IMMUTABLE AS 'SELECT $1[i], i - array_lower($1,1) + 1, i FROM generate_series(array_lower($1,1), array_upper($1,1)) i';

    SELECT id, arr, (rec).* FROM ( SELECT *, f_unnest_ord_idx(arr) AS rec FROM (VALUES (1, '{a,b,c}'::text[]) -- short for: '[1:3]={a,b,c}' , (2, '[5:7]={a,b,c}') , (3, '[-9:-7]={a,b,c}') ) t(id, arr) ) sub;

    id | arr | val | ordinality | idx ----+-----------------+-----+------------+----- 1 | {a,b,c} | a | 1 | 1 1 | {a,b,c} | b | 2 | 2 1 | {a,b,c} | c | 3 | 3 2 | [5:7]={a,b,c} | a | 1 | 5 2 | [5:7]={a,b,c} | b | 2 | 6 2 | [5:7]={a,b,c} | c | 3 | 7 3 | [-9:-7]={a,b,c} | a | 1 | -9 3 | [-9:-7]={a,b,c} | b | 2 | -8 3 | [-9:-7]={a,b,c} | c | 3 | -7

    2020-02-08 21:41:29
    赞同 展开评论 打赏
问答排行榜
最热
最新

相关电子书

更多
金融级 PostgreSQL监控及优化 立即下载
PostgreSQL在哈啰的实践-周飞 立即下载
PostgreSQL高并发数据库应用数据 立即下载

相关镜像