【问题标题】:Get column names in subquery, and then return values for those columns?在子查询中获取列名,然后返回这些列的值?
【发布时间】:2017-03-11 12:12:21
【问题描述】:

这似乎是不可能的,但我已经很接近了——也许有人可以带我走最后一步……

我有一堆动态代码,我并不总是知道要处理的表和列,但我知道 data_lengths 为 2000 的 VARCHAR2 列会导致错误。我希望能够动态识别这些“坏”列,并一次性将它们从我的结果中删除。

这段代码:

SELECT LISTAGG(probs.column_name, ', ') WITHIN GROUP (ORDER BY column_name) FROM (select 1 grp, column_name from all_tab_columns where TABLE_NAME = 'MYTABLE' AND DATA_TYPE <> 'VARCHAR2' AND DATA_LENGTH < 2000 ) probs GROUP BY GRP

给我一​​个很好的逗号分隔列表,列出我所有可接受的列名,如下所示:

FIELD1, FIELD2, FIELD3, FIELD4...

我希望有一种方法可以简单地将字段名称列表放入 select 语句中,如下所示:

SELECT (<my subquery, above>) FROM MYTABLE;

这可能吗?

【问题讨论】:

    标签: sql oracle select subquery


    【解决方案1】:

    假设这种情况

    create table mytable ( a number, b number, c number)
    insert into mytable values (10, 20, 30)
    insert into mytable values (1, 2, 3)
    

    并且只存在一个具有该名称的表(否则您应该在来自all_tab_columns 的查询中指定所有者),您的查询可以这样简化:

    SELECT 'select ' || LISTAGG(column_name, ', ') WITHIN GROUP (ORDER BY column_name) || ' from ' || table_name
        FROM all_tab_columns
       WHERE     TABLE_NAME = 'MYTABLE'
             AND DATA_TYPE <> 'VARCHAR2'
             AND DATA_LENGTH < 2000
    GROUP BY table_name  
    

    这将给出:select A, B, C from MYTABLE

    这里的问题是您不能简单地运行返回可变列数的语句;使用它的一种方法可能是构建一个 xml:

    SELECT xmltype(
                   DBMS_XMLGEN.getxml(
                                      (  SELECT 'select ' || LISTAGG(column_name, ', ') WITHIN GROUP (ORDER BY column_name) || ' from ' || table_name
                                           FROM all_tab_columns
                                          WHERE     TABLE_NAME = 'MYTABLE'
                                                AND DATA_TYPE <> 'VARCHAR2'
                                                AND DATA_LENGTH < 2000
                                       GROUP BY table_name)
                                     )
                  )
      FROM DUAL
    
    <?xml version="1.0"?>
    <ROWSET>
      <ROW>
        <A>10</A>
        <B>20</B>
        <C>30</C>
      </ROW>
      <ROW>
        <A>1</A>
        <B>2</B>
        <C>3</C>
      </ROW>
    </ROWSET>
    

    另一种方法是使用一些 PLSQL 和动态 SQL,对您的查询稍作修改以连接字段,以将结果构建为唯一字符串:

    declare
        type tTabResults is table of varchar2(1000);
        vSQL varchar2(1000);
        vTabResults tTabResults;
    begin
        SELECT 'select ' || LISTAGG( column_name, '|| '', '' ||') WITHIN GROUP (ORDER BY column_name) || ' from ' || table_name
        into vSQL
            FROM all_tab_columns
           WHERE     TABLE_NAME = 'MYTABLE'
                 AND DATA_TYPE <> 'VARCHAR2'
                 AND DATA_LENGTH < 2000
        GROUP BY table_name;
        --
        execute immediate vSQL bulk collect into vTabResults;
        --
        for i in vTabResults.first .. vTabResults.last loop
            dbms_output.put_line(vTabResults(i));
        end loop;
    end;
    
    
    
    10, 20, 30
    1, 2, 3
    

    请注意,我将问题简单化了,将数字视为字符串,不使用任何转换,只需打印表中的值,无论其类型如何;在真正的解决方案中,您应该处理列的可能类型并修改初始查询以添加一些类型转换。

    【讨论】:

    • 感谢 Aleksej - 这绝对不像我希望的那么简单,而且由于我的动态代码都在 R 中(我更容易使用),我最终做了 2 个查询 - 第一个确定所有 varchar2 字段,然后使用 R 处理它们,并构建适当的最终查询。非常感谢您的宝贵时间 - 谢谢!
    猜你喜欢
    • 1970-01-01
    • 2021-04-19
    • 2012-11-21
    • 2014-08-31
    • 1970-01-01
    • 1970-01-01
    • 2018-07-08
    • 2020-02-05
    • 1970-01-01
    相关资源
    最近更新 更多