将 regexp_replace 连接到 listagg:结果太长(SQL 错误:ORA-01489)
Posted
技术标签:
【中文标题】将 regexp_replace 连接到 listagg:结果太长(SQL 错误:ORA-01489)【英文标题】:Concatenating regexp_replace into listagg: Result too long (SQL Error: ORA-01489) 【发布时间】:2019-03-15 11:53:06 【问题描述】:我为一个包创建了一个pl/sql procedure
,该包在应该匹配的表集之间执行协调。
我正在使用 listagg 将循环中当前表名的列名连接成一个用于比较两个表(34 个集合,每个表名循环)的动态 SQL 语句中使用的字符串。
该过程按预期工作,但结果意外地从减号返回。经过研究,我确定某些字段包含在平面文件中收到的 HEX (00) 字符,该字符仅在侦察一侧的数据上填充数据。为了考虑特殊字符,我添加了一个 regexp_replace 与列名 select 中的 listagg 串联,因此它输出完整的 listagg 结果,每个列名都包含在一个 regexp_replace 中。
它有效。但是,有些表有一百多列,listagg 会因为结果超过 4000 个字符而失败。
有没有更好的方法来处理整个事情?
代码如下:
将列名收集到逗号分隔列表中(逗号字符连接到字符串本身,用作下面动态 SQL 选择中的分隔符)
execute immediate
'SELECT ' || q'listagg('regexp_replace(' || column_name || ', ''[^A-Z0-9 ]'', '''')', '||'', '' || ')' || ' within group (order by rownum) "COLUMN_NAME"
FROM user_tab_cols
where table_name =''' || csrpubtable.table_name || ''''
into v_column_names;
这两个动态 SQL 语句在两个方向上执行协调。这些与错误没有直接关系,但绝对与我提出的以更好的整体方式完成任务的问题有关。
--Insert data to RECON_PUB_TABLES where record exists in FILE but not PROD
execute immediate
'INSERT INTO RECON_PUB_TABLES
SELECT ''' || csrpubtable.table_name || ''', ''FILE'' , ' || v_column_names || ', trunc(sysdate) from ' || csrpubtable.table_name || '
minus
SELECT ''' || csrpubtable.table_name || ''', ''FILE'' , ' || v_column_names || ', trunc(sysdate) from ' || csrpubtable.table_name || '@pub_recon2prod where trunc(' || v_lastupdate_column || ') <= trunc(to_date(''' || v_compare_date || ''', ''dd-MON-yy''))';
--Insert data to RECON_PUB_TABLES where record exists in PROD but not FILE
execute immediate
'INSERT INTO RECON_PUB_TABLES
SELECT ''' || csrpubtable.table_name || ''', ''PROD'' , ' || v_column_names || ', trunc(sysdate) from ' || csrpubtable.table_name || '@pub_recon2prod where trunc(' || v_lastupdate_column || ') <= trunc(to_date(''' || v_compare_date || ''', ''dd-MON-yy''))
minus
SELECT ''' || csrpubtable.table_name || ''', ''PROD'' , ' || v_column_names || ', trunc(sysdate) from ' || csrpubtable.table_name ;
【问题讨论】:
【参考方案1】:varchar2 在 plsql 中被限制为 32k 如果 32 就足够了,你可以试试这样的方法
create or replace procedure conc_col_names(tableName IN varchar2) as
collist varchar2(32767);
begin
for xx in (select * from user_tab_columns where table_name = tableName order by column_name asc) loop
if ( length(collist) > 0) then
collist := collist||',';
end if;
collist := collist||'regexp_replace('||xx.column_name||',''[^A-Z0-9 ]'')';
end loop;
/* add the rest code for comparing rows in the two table here */
end;
/
【讨论】:
谢谢克里斯蒂安。我没有考虑过像这样连接列名的循环。字符总数超过 4000(当 listagg 出错时),但我相信它远低于 32k,我可以验证。我会看看这个,看看我是否可以将它集成到 listagg 的位置。 工作得很好。再次感谢克里斯蒂安。以上是关于将 regexp_replace 连接到 listagg:结果太长(SQL 错误:ORA-01489)的主要内容,如果未能解决你的问题,请参考以下文章
将所有 String 元素从 List 连接到 String 的最快方法