【问题标题】:Is it possible to use pattern matching to select columns from Oracle SQL db?是否可以使用模式匹配从 Oracle SQL 数据库中选择列?
【发布时间】:2020-09-08 20:03:42
【问题描述】:

我在 Oracle SQL DB 中有一个表,其中包含带有“PERCENT_”等标题的列以及其他名称。我想选择所有带有“PERCENT_”前缀的列。

我已经找到了一些可以回答问题的问题,例如如何在数据库中查找所有列与特定模式匹配的表......但似乎没有一个问题可以回答这个特定问题。

这可以吗?我能够从“all_tab_columns”返回所有匹配的列名的列表

select column_name from all_tab_columns where column_name like 'PERCENT_%' from <table_name>

但是我可以做这样的事情来从我想要的表中选择那些列吗?

with desired_cols as (select column_name from all_tab_columns where column_name like 'PERCENT_%' from <table_name>)
select desired_cols from <table_name>

【问题讨论】:

  • 仅适用于动态 SQL;但是什么会消耗输出?结果集中有不同数量的列会使处理变得复杂,并且在静态 SQL 中是不允许的。
  • 我猜我们最终会生成一个静态 excel 文件。这个查询只是一个完成。

标签: sql oracle oracle12c dynamic-sql


【解决方案1】:

SQL 查询总是返回一组固定的、预定义的列。您所要求的需要动态 SQL:即运行一个收集列名的查询,将结果保存在一个变量中,并使用它来构建要执行的实际查询。

如果这是一次性查询,那么我建议只运行以下查询:

select 'select ' 
    || listagg('"' || column_name || '"', ', ') within group (order by column_id)
    || ' from mytable' as sql_query
from all_tab_columns 
where owner = 'MYSCHEMA' and table_name = 'MYTABLE' and column_name like 'PERCENT_%';

这会生成您想要的查询,然后您可以复制/粘贴并独立运行。

请注意,我在模式名称上添加了一个过滤器(这是唯一标识数据库中的表所必需的)。我还按列在表格中的位置对列进行了排序。

另一方面,如果您想要完全动态的东西,那么您可以构建一个函数,该函数将返回一个保存查询结果的游标。

create function myfunction return sys_refcursor
as
    v_sql varchar(1000);
    v_cursor sys_refcursor;
begin
    select 'select ' 
        || listagg('"' || column_name || '"', ', ') within group (order by column_id)
        || ' from mytable' as sql_query
    into v_sql
    from all_tab_columns 
    where table_name = 'MYTABLE' and column_name like 'PERCENT_%';
        
    open v_cursor for v_sql;
    return v_cursor;
end;
/

然后,你必须决定如何使用光标。

【讨论】:

    【解决方案2】:

    在 18c 及更高版本中,您可以创建多态表函数以根据模式动态选择列。在 12c 及以下,您需要使用 Oracle 数据盒在 SQL 中创建动态 SQL。两种解决方案都需要 PL/SQL,但最终结果的外观和行为就像常规 SQL。在实践中,您可能希望在应用层而不是数据库中解决这些动态问题。例如,如果您正在构建 Excel 电子表格,大多数 Oracle-Excel API 都允许将查询作为字符串传递。

    18c及以上-多态表函数

    首先,创建一个包,用于标识表中的哪些列要通过 SQL 语句传递,以及哪些列要忽略。多态表函数有很多不寻常的语法,所以下面的代码乍一看并没有多大意义。

    create or replace package percent_cols as
        function percent_cols(tab in table) return table pipelined row polymorphic using percent_cols;
        function describe(tab in out dbms_tf.table_t) return dbms_tf.describe_t;
    end percent_cols;
    /
    
    create or replace package body percent_cols as
        function describe (tab in out dbms_tf.table_t) return dbms_tf.describe_t
        as
        begin
            for i in 1 .. tab.column.count() loop
                if tab.column(i).description.name like '%PERCENT\_%' escape '\' then
                    tab.column(i).pass_through := true;
                else
                    tab.column(i).pass_through := false;
                end if;
            end loop;
    
            return null;
        end;
    end percent_cols;
    /
    

    创建一些示例表来测试包:

    create table test1(a number, percent_1 number);
    insert into test1 values(1, 1);
    
    create table test2(percent_1 number, percent_2 number);
    insert into test2 values(2, 2);
    
    create table test3(a number);
    insert into test3 values(3);
    

    以下示例查询仅显示 PERCENT% 列。您可能需要为没有任何匹配列的表添加一些异常处理。

    SQL> select * from percent_cols(test1);
    
     PERCENT_1
    ----------
             1
    
    SQL> select * from percent_cols(test2);
    
     PERCENT_1  PERCENT_2
    ---------- ----------
             2          2
    
    SQL> select * from percent_cols(test3);
    select * from percent_cols(test3)
                  *
    ERROR at line 1:
    ORA-30732: table contains no user-visible columns
    

    12c 及以下 - Oracle 数据磁带

    数据盒让我们以许多有趣的方式扩展 Oracle,但界面很难使用。与其创建自己的 PL/SQL 类型和函数,不如从 my open source project 开始。

    此解决方案需要比多态表函数更多的代码,但它的优势在于将更多逻辑保留在常规 SQL 中 - 您可以在表函数中看到单个数据字典查询,而不是将其隐藏在 PL/SQL 后面.

    select * from table(method4.dynamic_query(
        q'[
            select 'select '||listagg(column_name, ',') within group (order by column_id)||' from '||table_name v_sql
            from all_tab_columns
            where table_name = 'TEST2'
                and column_name like 'PERCENT_%'
            group by table_name
        ]'
    ));
    
     PERCENT_1  PERCENT_2
    ---------- ----------
             2          2
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-04-07
      • 2015-03-13
      • 1970-01-01
      • 1970-01-01
      • 2010-09-26
      • 2013-07-17
      • 1970-01-01
      相关资源
      最近更新 更多