使用此帖子中的示例:https://blogs.oracle.com/datawarehousing/entry/managing_overflows_in_listagg
以下声明:
SELECT
deptno,
LISTAGG(ename, ';') WITHIN GROUP (ORDER BY empno) AS namelist
FROM emp
GROUP BY deptno;
将生成以下输出:
DEPTNO NAMELIST
---------- ----------------------------------------
10 CLARK;KING;MILLER
20 SMITH;JONES;SCOTT;ADAMS;FORD
30 ALLEN;WARD;MARTIN;BLAKE;TURNER;JAMES
假设上面的语句没有运行,并且我们的LISTAGG函数中的每一行都可以返回15个字符的限制。在Amazon Redshift上实际上是65535。
我们希望在这种情况下返回以下内容:
DEPTNO NAMELIST
---------- ----------------------------------------
10 CLARK;KING
10 MILLER
20 SMITH;JONES
20 SCOTT;ADAMS
20 FORD
30 ALLEN;WARD
30 MARTIN;BLAKE
30 TURNER;JAMES
在Amazon Redshift中重建此结果的最佳方法是什么,以避免任何数据丢失并考虑速度?
答案 0 :(得分:2)
可以通过2个子查询来实现:
第一:
SELECT id, field,
sum(length(field) + 1) over
(partition by id order by RANDOM() rows unbounded preceding) as total_length_now
from my_schema.my_table)
最初,我们要计算表中每个ID的字符数。我们可以使用窗口函数为每一行递增地计算它。在“ order by”语句中,您可以使用任何唯一字段。如果您没有,则可以简单地使用随机函数或哈希函数,但是必须强制该字段唯一,否则,该函数将无法正常运行。
长度的+1表示我们将在listagg函数中使用的分号。
第二:
SELECT id, field, total_length_now / 65535 as sub_id
FROM (sub_query_1)
现在,我们根据之前计算出的长度创建一个sub_id。如果total_length_now超过了限制大小(在这种情况下为65535),则该部门的其余人员将返回一个新的sub_id。
最后一步
SELECT id, sub_id, listagg(field, ';') as namelist
FROM (sub_query_2)
GROUP BY id, sub_id
ORDER BY id, sub_id
现在,我们可以简单地通过id和sub_id调用listagg函数分组,因为每个组不能超过大小限制。
完整查询
SELECT id, sub_id, listagg(field, ';') as namelist
FROM (
SELECT id, field, total_length_now / 65535 as sub_id
FROM (SELECT id,
field,
sum(length(field) + 1) over
(partition by id order by field rows unbounded preceding) as total_length_now
from support.test))
GROUP BY id, sub_id
order by id, sub_id
数据示例(大小限制为10)
第一和第二个查询输出:
id, field, total_length_now, sub_id
10,KING,5,0
10,CLARK,11,1
10,MILLER,18,1
20,ADAMS,6,0
20,SMITH,12,1
20,JONES,18,1
20,FORD,23,2
20,SCOTT,29,2
30,JAMES,6,0
30,BLAKE,12,1
30,WARD,17,1
30,MARTIN,24,2
30,TURNER,31,3
30,ALLEN,37,3
最终查询输出:
id,sub_id,namelist
10,0,KING
10,1,CLARK;MILLER
20,0,ADAMS
20,1,SMITH;JONES
20,2,FORD;SCOTT
30,0,JAMES
30,1,BLAKE;WARD
30,2,MARTIN
30,3,TURNER;ALLEN
答案 1 :(得分:-1)
可以创建一个部分列表,然后将其余值作为单独的行一次性运行,但如果行数不受约束,则确实需要一个循环语句然后将其转换为列表,并且行剩下的等等。
所以这对Apache Spark(或任何其他map-reduce技术)来说真是一项任务。