将 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 的最快方法

将 str 连接到列表的好方法?

将列表的索引连接到字符串变量中

libvirt:为啥直接将 LUN 连接到 KVM 来宾时 IOPS 很少

将 1 到 n 个项目连接到新的 spark 列中

如何将变量传递给连接到按钮pyqt5 python的函数[关闭]