【问题标题】:oracle: display results of dynamic sql based on antoher sqloracle:显示基于另一个sql的动态sql的结果
【发布时间】:2022-01-11 17:24:44
【问题描述】:

我想显示基于另一个 sql 的动态 sql 的结果,但得到错误消息。我的代码:

DECLARE
    sql_qry      VARCHAR2(1000) := NULL;
    TYPE results IS
        TABLE OF all_tab_columns%rowtype;
    results_tbl  results;
BEGIN
    FOR i IN (
        SELECT
            *
        FROM
            all_tab_columns
        WHERE
                owner = 'OWNER_XYZ'
            AND upper(column_name) LIKE '%COLUMN_XYZ%'
        ORDER BY
            table_name,
            column_name
    ) LOOP
        sql_qry := ' SELECT DISTINCT '
                   || i.column_name
                   || ' as column_name '
                   || ' FROM '
                   || i.owner
                   || '.'
                   || i.table_name
                   || ' WHERE SUBSTR('
                   || i.column_name
                   || ',1,1) =  ''Y''';
        EXECUTE IMMEDIATE sql_qry BULK COLLECT
        INTO results_tbl;
           dbms_output.put_line(results_tbl);
    END LOOP;
END;

我收到错误消息:

PLS-00306: wrong number or types of arguments in call to 'PUT_LINE'

事实上,我需要所有查询的结果,它们之间有一个这样的联合 [1] [1]:https://i.stack.imgur.com/llxzr.png

【问题讨论】:

  • 尝试运行 - dbms_output.put_line(results_tbl.column_name);
  • 谢谢,但我收到 PLS-00302:必须声明组件“COLUMN_NAME”
  • results 是使用all_tab_columns 定义的,因此批量收集无论如何都不起作用(目前还没有那么远);您只从目标表中选择一个列,因此集合需要反映该列及其数据类型。您的put_line 也指整个收藏,而不是其中的一条记录;所以results_tbl(1).column_name 是有效的,尽管您实际上需要循环并使用索引变量以便查看所有值。

标签: sql oracle dynamic


【解决方案1】:

您的动态查询正在选择单个列,但您正在批量收集到 results_tbl,它的类型为 results,基于 all_tab_columns%rowtype - 它有很多列。

如果您将集合类型定义为您需要的数据类型的单列,即某个长度的字符串:

DECLARE
    sql_qry      VARCHAR2(1000) := NULL;
    TYPE results IS
        TABLE OF varchar2(4000);
    results_tbl  results;
...

然后,您会将单列批量收集到该单列集合中。要显示结果,您需要遍历集合:

        FOR j IN 1..results_tbl.COUNT loop
           dbms_output.put_line(results_tbl(j));
        END LOOP;

所以整个块变成:

DECLARE
    sql_qry      VARCHAR2(1000) := NULL;
    TYPE results IS
        TABLE OF varchar2(4000);
    results_tbl  results;
BEGIN
    FOR i IN (
        SELECT
            *
        FROM
            all_tab_columns
        WHERE
                owner = 'OWNER_XYZ'
            AND upper(column_name) LIKE '%COLUMN_XYZ%'
        ORDER BY
            table_name,
            column_name
    ) LOOP
        sql_qry := ' SELECT DISTINCT '
                   || i.column_name
                   || ' as column_name '
                   || ' FROM '
                   || i.owner
                   || '.'
                   || i.table_name
                   || ' WHERE SUBSTR('
                   || i.column_name
                   || ',1,1) =  ''Y''';
        EXECUTE IMMEDIATE sql_qry BULK COLLECT
        INTO results_tbl;
        
        FOR j IN 1..results_tbl.COUNT loop
           dbms_output.put_line(results_tbl(j));
        END LOOP;
    END LOOP;
END;
/

但是,您也可以在不使用 PL/SQL 的情况下执行此操作,使用 an XML trick 的变体。您可以使用以下内容将动态查询的结果作为 XML 文档获取:

select dbms_xmlgen.getxmltype(
    'select distinct "' || column_name || '" as value'
      || ' from "' || owner || '"."' || table_name || '"'
      || ' where substr("' || column_name || '", 1, 1) = ''Y'''
  )
from all_tab_columns
where owner = 'OWNER_XYZ'
and upper(column_name) like '%COLUMN_XYZ%';

然后从中提取你想要的值:

with cte (xml) as (
  select dbms_xmlgen.getxmltype(
      'select distinct "' || column_name || '" as value'
        || ' from "' || owner || '"."' || table_name || '"'
        || ' where substr("' || column_name || '", 1, 1) = ''Y'''
    )
  from all_tab_columns
  where owner = 'OWNER_XYZ'
  and upper(column_name) like '%COLUMN_XYZ%'
)
select x.value
from cte
cross apply xmltable(
  '/ROWSET/ROW'
  passing cte.xml
  columns value varchar2(4000) path 'VALUE'
) x;

如果您需要这些信息(以及所有者、实际列名等),您还可以轻松地包含每个值的来源表。

db<>fiddle 展示了这两种方法。

【讨论】:

  • 就是这样!太好了,谢谢!
猜你喜欢
  • 2015-02-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多