【发布时间】:2021-05-13 14:08:23
【问题描述】:
我的查询返回许多(数千)行。
l 列对于非常少量的行(最多 10 行)具有一定的价值。
对于每个这样的行,我想在所有这些行上输出非常短(最多 5 个字符)varchar 列 v 的聚合逗号分隔值。
对于没有 l 特殊值的行,我只想输出该行的 v 值。
同一问题的综合示例:从前 10000 个整数中,我想为每个个位数输出 1,2,3,4,5,6,7,8,9;该号码为多位数号码。 (是的,愚蠢的例子,但真实案例是有道理的。)
with x (v,l) as (
select to_char(level), length(to_char(level)) from dual connect by level <= 10000
)
select case l
when 1 then listagg(v,',') within group (order by v) over (partition by l)
else v
end
from x
order by 1;
问题是,listagg 函数因ORA-01489: result of string concatenation is too long 错误而失败。
我知道 listagg 函数的 4000 个字符限制以及基于 xmlagg 的解决方法。我只是没有得到足够的限制来连接我想要连接的数据,即使对于所有数据来说都不够。在上面的例子中,9 个个位数字的分区适合 4000 个字符,9000 个四位数字的分区不适合。我预计case 表达式会阻止执行不相关行的窗口,但由于某种原因,似乎数据库引擎会评估所有行的窗口。 (另请注意,order by 子句会导致查询快速失败 - 没有它,一些行会在失败之前返回。)
您能解释一下这种行为的一些原因吗?我怀疑窗口计算在逻辑上在select 子句之前,但没有任何证据。在 Oracle 11g、18c 和 19 (livesql) 上重现。
【问题讨论】:
标签: sql oracle case listagg analytic-functions