将数组元素组合成不同的数组

时间:2016-05-27 00:12:12

标签: sql arrays postgresql unnest

我需要在数组中拆分文本元素,并将索引元素(array_agg)组合成不同的行

例如,输入

'{cat$ball$x... , dog$bat$y...}'::text[]

我需要将每个元素拆分为'$',所需的输出为:

{cat,dog} - row 1
{ball,bat} - row 2
{x,y} - row 3
...

很抱歉第一次不清楚。我已经编辑了我的问题。我尝试了类似的选项,但无法弄清楚如何使用'$'sysmbol

分隔的多个文本元素

2 个答案:

答案 0 :(得分:1)

每个数组元素正好两个部分(原始问题)

使用unnest()split_part()array_agg()

SELECT array_agg(split_part(t, '$', 1)) AS col1
     , array_agg(split_part(t, '$', 2)) AS col2
FROM   unnest('{cat$ball, dog$bat}'::text[]) t;

相关:

一般解决方案(更新的问题)

对于任何数量的数组,任何数量的元素包含任何部件数。

表格tbl的演示:

CREATE TABLE tbl (tbl_id int PRIMARY KEY, arr text[]);

INSERT INTO tbl VALUES
  (1, '{cat1$ball1, dog2$bat2}')  -- 2 parts per array element, 2 elements
, (2, '{cat$ball$x, dog$bat$y}')  -- 3 parts ...
, (3, '{a1$b1$c1$d1, a2$b2$c2$d2, a3$b3$c3$d3}');  -- 4 parts, 3 elements

查询:

SELECT tbl_id, idx, array_agg(elem ORDER BY ord) AS pivoted_array
FROM   tbl t
     , unnest(t.arr) WITH ORDINALITY a1(string, ord)
     , unnest(string_to_array(a1.string, '$')) WITH ORDINALITY a2(elem, idx)
GROUP  BY tbl_id, idx
ORDER  BY tbl_id, idx;

我们在这里看两个(嵌套的)LATERAL联接。 LATERAL需要Postgres 9.3。详细说明:

第一个WITH ORDINALITY

unnest()即将进行辩论。更简单的查询通常也适用。它不能保证按照SQL标准工作:

SELECT tbl_id, idx, array_agg(elem) AS pivoted_array
FROM   tbl t
     , unnest(t.arr) string
     , unnest(string_to_array(string, '$')) WITH ORDINALITY a2(elem, idx)
GROUP  BY tbl_id, idx
ORDER  BY tbl_id, idx;

详细说明:

WITH ORDINALITY需要Postgres 9.4或更高版本。与Postgres 9.3相同的补丁:

SELECT tbl_id, idx, array_agg(arr2[idx]) AS pivoted_array
FROM   tbl t
     , LATERAL (
         SELECT string_to_array(string, '$') AS arr2  -- convert string to array
         FROM   unnest(t.arr) string  -- unnest org. array
         ) x
     , generate_subscripts(arr2, 1) AS idx  -- unnest 2nd array with ord. numbers
GROUP  BY tbl_id, idx
ORDER  BY tbl_id, idx;

每个查询返回:

 tbl_id | idx | pivoted_array
--------+-----+---------------
      1 |   1 | {cat,dog}
      1 |   2 | {bat,ball}
      1 |   3 | {y,x}
      2 |   1 | {cat2,dog2}
      2 |   2 | {ball2,bat2}
      3 |   1 | {a3,a1,a2}
      3 |   2 | {b1,b2,b3}
      3 |   3 | {c2,c1,c3}
      3 |   4 | {d2,d3,d1}

SQL Fiddle(仍然停留在第9.3页)。

这些查询的 唯一要求 是同一数组元素中的部分数是常量。我们甚至可以使用带有两个参数的crosstab()使不同数量的零件工作,以填充缺失零件的NULL值,但这超出了这个问题的范围:

答案 1 :(得分:0)

有点乱,但你可以不用数组,使用正则表达式来分隔文本,然后再次聚合备份:

with a as (select unnest('{cat$ball, dog$bat}'::_text) some_text),
b as (select regexp_matches(a.some_text, '(^[a-z]*)\$([a-z]*$)') animal_object from a)
select array_agg(animal_object[1]) animal, array_agg(animal_object[2]) a_object
from b

如果您一次处理多个记录,您可能希望在取消之前使用类似行号的内容,以便您有一个group by聚合回最终select语句中的数组。