是否可以在PostgreSQL中对数组元素进行分组?
示例,我有2个这样的相关数组(我说是相关的,因为第一个数组表示动作而第二个数组代表那些动作的时间:
col0 = 'any_value'
col1 = array1['a','b','b','c','c','a','a','a','c']
col2 = array2[1,2,3,4,5,6,7,8,9]
我想输出以下结果:
col0 = 'any_value'
array_result1['a','b','c','a','c']
array_result2[1,2,4,6,9]
数组可以被取消的方法是使用normalality,这是一个示例查询,但它返回一个不同的数组元素选择,删除重复的数组:
select col0,
array_agg(x order by rn) as unique_array1
from (
select
distinct on (col0, a.x) col0,
a.x,
a.rn
from table_a,
unnest(array1) with ordinality as a (x,rn)
order by 1,2,3
) unnested_ordered
group by col0;
所以结果就是:
col0 = 'any_value'
array_result1['a','b','c']
但是你可以看到它缺少很多元素。
修改
要描述更多我的问题,最后我想知道最初完成每个array_result1操作的时间。 所以对于示例结果
array_result1['a','b','c','a','c']
*array_result2[1,2,4,6,9]
*我说数组的位置从1开始而不是0,我也修复了最后一个元素,它应该是9而不是7
会帮助我知道,第一次采取行动的时间是什么?'发生了,第二次行动是什么时候发生的?' a'发生这样我就可以计算出行动的时间' a'回到我正在建设的道路上。 所以第一次采取行动' a'发生了= 1 第二次发生的事情是= 6
所以行动' a'在路径(数组)中出现两次,重新出现需要5个时间单位。这就是为什么我需要第二个数组,其中包含动作发生的时间(每个动作第一次发生)
答案 0 :(得分:1)
您可以使用LATERAL
并使用ROW_NUMBER
计算群组:
DROP TABLE IF EXISTS table_a;
CREATE TABLE table_a(col0 VARCHAR(10), col1 text[],col2 int[]);
INSERT INTO table_a(col0, col1, col2)
VALUES ('any_value',array['a','b','b','c','c','a','a','a','c'],
array[1,2,3,4,5,6,7,8,9]);
主要查询:
SELECT col0,
col1,
unique_col1
FROM table_a,
LATERAL (SELECT ARRAY_AGG(x ORDER BY grp) AS unique_col1
FROM ( SELECT DISTINCT x,
rn - ROW_NUMBER() OVER(PARTITION BY x ORDER BY rn) AS grp
FROM unnest(col1) WITH ORDINALITY AS a(x,rn)
) AS sub
) AS lat1
输出:
修改强>
计算第二个数组:
SELECT col0,
col1,
unique_col1,
col2,
unique_col2
FROM table_a,
LATERAL (SELECT ARRAY_AGG(x ORDER BY grp) AS unique_col1
FROM ( SELECT DISTINCT x,
rn - ROW_NUMBER() OVER(PARTITION BY x ORDER BY rn) AS grp
FROM unnest(col1) WITH ORDINALITY AS a(x,rn)
) AS sub
) AS lat1,
LATERAL (
SELECT array_agg(x ORDER BY rn) AS unique_col2
FROM unnest(col2) WITH ORDINALITY AS b(x,rn)
WHERE rn IN (
SELECT SUM(c) OVER(ORDER BY grp) - (c-1) AS result
FROM (SELECT grp, COUNT(*) AS c
FROM ( SELECT x,
rn - ROW_NUMBER() OVER(PARTITION BY x ORDER BY rn) AS grp
FROM unnest(col1) WITH ORDINALITY AS a(x,rn)
) AS sub
GROUP BY grp) AS s
)
) AS lat2
注:
它从值生成第二个数组,而不是它的位置,所以当你有:
col2 = array[9,8,7,6,5,4,3,2,1]
你会得到:
[9,8,6,4,1]
如果您只想要使用的职位:
...
LATERAL (
SELECT array_agg(result ORDER BY result) AS unique_col2
FROM (
SELECT SUM(c) OVER(ORDER BY grp) - (c-1) AS result
FROM (SELECT grp, COUNT(*) AS c
FROM ( SELECT x,
rn - ROW_NUMBER() OVER(PARTITION BY x ORDER BY rn) AS grp
FROM unnest(col1) WITH ORDINALITY AS a(x,rn)
) AS sub
GROUP BY grp) AS s
) AS s1
) AS lat2
结果将是:
[1,2,4,6,9]
在上面的版本中有一个小错误。 ARRAY_AGG
应按rn
而不是grp
订购:
DROP TABLE IF EXISTS table_a;
CREATE TABLE table_a(col0 VARCHAR(10), col1 text[],col2 int[]);
INSERT INTO table_a(col0, col1, col2)
VALUES ('any_value',array['a','b','b','c','c','a','a','a','c'],
array[1,2,3,4,5,6,7,8,9]);
INSERT INTO table_a(col0, col1, col2)
VALUES ('any_value2',array['a','b','a','a','c','a'],array[1,2,3,4,5,6]);
SELECT *
FROM table_a,
LATERAL (SELECT ARRAY_AGG(x ORDER BY rn) AS unique_col1
FROM
(SELECT x, grp, MIN(rn) AS rn
FROM (SELECT x,
rn - ROW_NUMBER() OVER(PARTITION BY x ORDER BY rn) AS grp,
rn
FROM unnest(col1) WITH ORDINALITY AS a(x,rn)
) AS sub
GROUP BY x, grp) AS s
) AS lat1;