[英]REDSHIFT : SIZE below 65K BUT "error: Result size exceeds LISTAGG limit code: 8001"
[英]Using LISTAGG function in SQL causes error: Result size exceeds LISTAGG limit
我试图在 SQL 中使用LISTAGG
函数,但LISTAGG
以下错误:
无效操作:结果大小超过 LISTAGG 限制详细信息:
----------- 错误:结果大小超过 LISTAGG 限制代码:8 ...
我如何摆脱这个错误?
请参阅https://docs.aws.amazon.com/redshift/latest/dg/r_LISTAGG.html 上的ListAgg 功能文档
返回数据类型为 varchar(max),即 64K varchar 大小
您描述的错误在官方文档中完全有提及
您可以考虑将 ListAgg() 函数与 Distinct 结合使用,以减少要连接的项目
select listagg(distinct sellerid, ', ') within group (order by sellerid) from sales
where eventid = 4337;
这就是我们遇到的问题的原因。
这是我尝试执行的 SQL 查询,
SELECT DISTINCT "year_level", LISTAGG("value", ', ') WITHIN GROUP (ORDER BY "year_level") OVER (PARTITION BY "year_level")
FROM "school_1__acara_db"."acara_data_set";
这是我得到的错误。
ERROR: Result size exceeds LISTAGG limit Detail: ----------------------------------------------- error: Result size exceeds LISTAGG limit code: 8001 context: LISTAGG limit: 65535 query: 4360256 location: string_ops.cpp:116 process: query1_127_4360256 [pid=1793] -----------------------------------------------
让我们把这个问题分成几个小部分。 所以正如他们提到的,我已经超过了LISTAGG
的最大限制。 我们可以通过下面的 SQL 查询找到根据"year_level"
在"value"
列中超出的"value"
。
SELECT "year_level", SUM(OCTET_LENGTH("value")) as total_bytes
FROM "school_1__acara_db"."acara_data_set"
GROUP BY "year_level"
ORDER BY total_bytes;
这是输出。
OCTET_LENGTH以字节(八位字节)为单位返回字符串的长度。
如您所见,与Primary Ungraded
相关的值的总字节数为50329
, Secondary Ungraded
总字节数为61178
字节。 两者都没有超过VARCHAR(MAX)
,即65535
限制。 至少我可以获得以上两条记录的LISTAGG
值吗? 这是我要执行的查询,
SELECT DISTINCT "year_level", LISTAGG("value", ', ') WITHIN GROUP (ORDER BY "year_level") OVER (PARTITION BY "year_level")
FROM "school_1__acara_db"."acara_data_set"
WHERE "year_level" IN ('Primary Ungraded', 'Secondary Ungraded');
我遇到了同样的错误, Result size exceeds LISTAGG limit Detail: -----------
。 正如我们在上面的结果中看到的那样,它没有超过VARCHAR(MAX)
,即65535
限制。 但为什么? 让我们通过以下查询查看与"year_level"
相关的"value"
列数。
SELECT "year_level", COUNT("value") as total_counts
FROM "school_1__acara_db"."acara_data_set"
GROUP BY "year_level"
ORDER BY total_counts;
这是输出。
在进一步解释之前,让我们看看LISTAGG
是如何工作的。
在 Redshift 中, LISTAGG
可用作 聚合函数或窗口函数,它将多行中的数据转换为由指定分隔符分隔的单个值列表。 对于下面的示例,分隔符是,
(带空格的逗号)。
下图取自Oracle的Listagg函数-使用和重复删除文章,它与Oracle相关,但可以获得LISTAGG
函数的基本概念。
这就是数据与分隔符合并的方式。
甚至我们的查询也使用分隔符作为,
(带空格的逗号)。 我们以下图中的第一条记录为例。
"Primary Ungraded"
有3412
条记录,总字节数为50329
。 所以这意味着我们要将3412
条记录合并到一个列中。 当我们合并时,它的总字节数应该为50329
。 但是我们不是直接合并,而是与分隔符合并。 所以在3412
条记录之间有3411
分隔符。
delimiter_count = no_of_records - 1
如果不明白,请查看Example #1
图像,了解如何合并数据。 因此,根据这一点,当我们在没有分隔符的情况下运行上次失败的查询时,它应该可以工作。
SELECT DISTINCT "year_level", LISTAGG("value", '') WITHIN GROUP (ORDER BY "year_level") OVER (PARTITION BY "year_level")
FROM "school_1__acara_db"."acara_data_set"
WHERE "year_level" IN ('Primary Ungraded', 'Secondary Ungraded')
是的,它工作正常。 但这对其他记录不起作用,因为没有做任何事情,它们已经超过了VARCHAR(MAX)
,即65535
限制。
很多人建议在LISTAGG
函数中使用DISTINCT
关键字。 Aggregate 函数和Window 函数都支持DISTINCT
关键字作为可选。
LISTAGG( [DISTINCT] aggregate_expression [, 'delimiter' ] )
[ WITHIN GROUP (ORDER BY order_list) ]
LISTAGG( [DISTINCT] expression [, 'delimiter' ] )
[ WITHIN GROUP (ORDER BY order_list) ]
OVER ( [PARTITION BY partition_expression] )
没有重复,我有超过VARCHAR(MAX)
65535
限制的数据。 所以我不能在我的情况下使用它。
我们不能把数据切成更小的部分吗? 是的,我们可以使用下面的查询来完成,不要混淆,下面的解决方案是由我的一位队友的名字 Isuru 找到的。
SELECT year_level, num_of_parts, listagg(value,',') AS listagg_data FROM (
SELECT year_level, value, total_bytes / 60000 AS num_of_parts FROM (
SELECT year_level, value, SUM(OCTET_LENGTH(value)) OVER (PARTION BY year_level ORDER BY value ROWS UNBOUNDED PRECEDING) AS total_bytes
FROM "school_1__acara_db"."acara_data_set"
)
)
GROUP BY year_level, num_of_parts
ORDER BY year_level, num_of_parts;
这是输出。
使用它,您可以获取所需的所有信息。 在这里,我们将total_bytes
切片60000
,可以看到num_of_parts
列中有多少碎片被破坏。 'Primary Ungraded'
没有分成任何部分,而 'Secondary Ungraded' 已经被分成 2 部分,正如我们之前调查的那样,同样它被60000
分成了多个部分。
我们遇到的问题是数据库限制。 因此,我们可以通过编程将LISTAGG
值合并到一个地方。 目前我没有看到任何其他解决方案,或者在整个互联网上找不到任何合适的解决方案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.