获取子查询中的列名,然后返回这些列的值?

时间:2016-10-28 14:58:16

标签: sql oracle select subquery

似乎这是不可能的,但我离这么近 - 也许有人可以带我走最后一步......

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

此代码:

FIELD1, FIELD2, FIELD3, FIELD4...

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

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

我希望有一种方法可以简单地将字段名称列表删除到这样的选择语句中:

? CHECK_ADJACENTS(range("i5")).Address

这可能吗?

1 个答案:

答案 0 :(得分:2)

假设这种情况

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,稍加修改yur查询以连接字段,以一个唯一的字符串构建结果:

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

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