在 redshift 中撤消 LISTAGG
Undo a LISTAGG in redshift
我有一个 table 可能是由 listagg 产生的,类似于:
# select * from s;
s
-----------
a,c,b,d,a
b,e,c,d,f
(2 rows)
如何将其更改为这组行:
a
c
b
d
a
b
e
c
d
f
Oracle 11g R2 架构设置:
create table s(
col varchar2(20) );
insert into s values('a,c,b,d,a');
insert into s values('b,e,c,d,f');
查询 1:
SELECT REGEXP_SUBSTR(t1.col, '([^,])+', 1, t2.COLUMN_VALUE )
FROM s t1 CROSS JOIN
TABLE
(
CAST
(
MULTISET
(
SELECT LEVEL
FROM DUAL
CONNECT BY LEVEL <= REGEXP_COUNT(t1.col, '([^,])+')
)
AS SYS.odciNumberList
)
) t2
| REGEXP_SUBSTR(T1.COL,'([^,])+',1,T2.COLUMN_VALUE) |
|---------------------------------------------------|
| a |
| c |
| b |
| d |
| a |
| b |
| e |
| c |
| d |
| f |
在 redshift 中,您可以加入 table 个数字,并将其用作拆分索引:
--with recursive Numbers as (
-- select 1 as i
-- union all
-- select i + 1 as i from Numbers where i <= 5
--)
with Numbers(i) as (
select 1 union
select 2 union
select 3 union
select 4 union
select 5
)
select split_part(s,',', i) from Numbers, s ORDER by s,i;
编辑:redshift 似乎不支持递归子查询,只支持 postgres。 :(
由于这被标记为 Redshift,并且到目前为止还没有关于在 Redshift 中正确撤消 LISTAGG 的完整概述的答案,这里是解决其所有用例的代码:
CREATE TEMPORARY TABLE s (
s varchar(255)
);
INSERT INTO s VALUES('a,c,b,d,a');
INSERT INTO s VALUES('b,e,c,d,f');
SELECT
TRIM(split_part(s.s,',',R::smallint)) AS s
FROM s
LEFT JOIN (
SELECT
ROW_NUMBER() OVER (PARTITION BY 1) AS R
FROM any_large_table
LIMIT 1000
) extend_number
ON (SELECT MAX(regexp_count(s.s,',')+1) FROM s) >= extend_number.R
AND NULLIF(TRIM(split_part(s.s,',',extend_number.R::smallint)),'') IS NOT NULL;
DROP TABLE s;
其中“any_large_table”是任何 table 你已经在 redshift 中有足够的记录来满足你的目的,这取决于每条记录的列表将包含的元素数量(即在上面案例,我确保它最多有一千条记录)。不幸的是,据我所知,generate_series 函数在 Redshift 中无法正常工作,这是唯一的方法。
另一点建议是检查您是否可以尽可能在 list_agg 之前获取值。从上面的代码可以看出,它看起来很复杂,如果保持简单(即,只要有机会),就可以节省大量代码维护时间。
我有一个 table 可能是由 listagg 产生的,类似于:
# select * from s;
s
-----------
a,c,b,d,a
b,e,c,d,f
(2 rows)
如何将其更改为这组行:
a
c
b
d
a
b
e
c
d
f
Oracle 11g R2 架构设置:
create table s(
col varchar2(20) );
insert into s values('a,c,b,d,a');
insert into s values('b,e,c,d,f');
查询 1:
SELECT REGEXP_SUBSTR(t1.col, '([^,])+', 1, t2.COLUMN_VALUE )
FROM s t1 CROSS JOIN
TABLE
(
CAST
(
MULTISET
(
SELECT LEVEL
FROM DUAL
CONNECT BY LEVEL <= REGEXP_COUNT(t1.col, '([^,])+')
)
AS SYS.odciNumberList
)
) t2
| REGEXP_SUBSTR(T1.COL,'([^,])+',1,T2.COLUMN_VALUE) |
|---------------------------------------------------|
| a |
| c |
| b |
| d |
| a |
| b |
| e |
| c |
| d |
| f |
在 redshift 中,您可以加入 table 个数字,并将其用作拆分索引:
--with recursive Numbers as (
-- select 1 as i
-- union all
-- select i + 1 as i from Numbers where i <= 5
--)
with Numbers(i) as (
select 1 union
select 2 union
select 3 union
select 4 union
select 5
)
select split_part(s,',', i) from Numbers, s ORDER by s,i;
编辑:redshift 似乎不支持递归子查询,只支持 postgres。 :(
由于这被标记为 Redshift,并且到目前为止还没有关于在 Redshift 中正确撤消 LISTAGG 的完整概述的答案,这里是解决其所有用例的代码:
CREATE TEMPORARY TABLE s (
s varchar(255)
);
INSERT INTO s VALUES('a,c,b,d,a');
INSERT INTO s VALUES('b,e,c,d,f');
SELECT
TRIM(split_part(s.s,',',R::smallint)) AS s
FROM s
LEFT JOIN (
SELECT
ROW_NUMBER() OVER (PARTITION BY 1) AS R
FROM any_large_table
LIMIT 1000
) extend_number
ON (SELECT MAX(regexp_count(s.s,',')+1) FROM s) >= extend_number.R
AND NULLIF(TRIM(split_part(s.s,',',extend_number.R::smallint)),'') IS NOT NULL;
DROP TABLE s;
其中“any_large_table”是任何 table 你已经在 redshift 中有足够的记录来满足你的目的,这取决于每条记录的列表将包含的元素数量(即在上面案例,我确保它最多有一千条记录)。不幸的是,据我所知,generate_series 函数在 Redshift 中无法正常工作,这是唯一的方法。
另一点建议是检查您是否可以尽可能在 list_agg 之前获取值。从上面的代码可以看出,它看起来很复杂,如果保持简单(即,只要有机会),就可以节省大量代码维护时间。