【问题标题】:Return Oracle column names in table.column format?以 table.column 格式返回 Oracle 列名?
【发布时间】:2012-09-02 20:17:35
【问题描述】:

有什么设置或方法可以让 Oracle 以<table>.<column> 格式返回结果吗?例如:

查询:

SELECT     *
FROM       foo f
INNER JOIN bar b
ON         b.foo_id = f.id

期望的结果:

F.ID  F.BLAH  B.ID  B.FOO_ID  B.BLAH
--------------------------------------------------------
1     blah    7     1         blah
2     blah    8     2         blah
3     blah    9     2         blah

显而易见的解决方案是为每一列单独命名SELECT f.id AS F_ID, ...;但是,我需要导出一些非常大的遗留表(超过 300 列),因此使用这种方法会导致查询非常庞大且不切实际。

【问题讨论】:

  • 我不擅长 PL/SQL,但也许您可以在加入表之前尝试重命名表列。
  • 如何导出数据?也许这个逻辑属于那个导出工具,而不是单独的语句?

标签: oracle


【解决方案1】:

Oracle 中没有执行此操作的“选项”;您可能能够找到允许您这样做的客户,因为这是通常在客户中完成的工作;我不知道一个。

要扩展tbone's answer,您将不得不动态地执行此操作。这并不意味着您必须列出每一列。您将使用data dictionary,特别是all_tab_columnsuser_tab_columns 来创建您的查询。使用您想要的确切定义创建视图会更容易,以便您可以根据需要重新使用它。

目的是利用存在的列作为字符串存储在表中这一事实,以便创建查询以使用该列。由于列名和表名存储为字符串,您可以使用字符串聚合技术轻松创建查询或 DDL 语句,然后您可以手动或动态执行。

如果您使用的是 Oracle 11g 第 2 版,listagg 函数可以帮助您:

select 'create or replace view my_view as 
        select '
      || listagg( table_name || '.' || column_name 
               || ' as ' 
               || substr(table_name,1,1) || '_' 
               || column_name, ', ')
        within group 
         ( order by case when table_name = 'FOO' then 0 else 1 end
                  , column_id
          )
       || ' from foo f
            join bar b
              on f.id = b.foo_id'
  from user_tab_columns
 where table_name in ('FOO','BAR')
        ;

假设这个表结构:

create table foo ( id number, a number, b number, c number);
create table bar ( foo_id number, a number, b number, c number);

这个单一的查询产生以下结果:

create or replace view my_view as 
 select FOO.ID as F_ID, FOO.A as F_A, FOO.B as F_B, FOO.C as F_C
      , BAR.FOO_ID as B_FOO_ID, BAR.A as B_A, BAR.B as B_B, BAR.C as B_C 
   from foo f 
   join bar b on f.id = b.foo_id

这里有一个SQL Fiddle 来证明这一点。

在您不使用 11.2 时,您可以使用由 Tom Kyte 创建的未记录函数 wm_concat 或用户定义函数 stragg 获得完全相同的结果。 Oracle Base 在string aggregation techniques 上有一篇文章,Stack Overflow 上也有很多帖子。

作为一个小附录,您实际上可以通过对上述查询稍作更改来创建您正在寻找的内容。您可以使用quoted identifier 创建TABLE_NAME.COLUMN_NAME 格式的列。您必须引用它,因为. 不是 Oracle 中对象名称的有效字符。这样做的好处是你得到你想要的。缺点是如果不使用select * from ...,查询创建的视图会非常痛苦;选择命名列将要求引用它们。

select 'create or replace view my_view as
        select '
      || listagg( table_name || '.' || column_name 
               || ' as ' 
               || '"' || table_name || '.'
               || column_name || '"', ', ')
        within group 
         ( order by case when table_name = 'FOO' then 0 else 1 end
                  , column_id
          )
       || ' from foo f
            join bar b
              on f.id = b.foo_id'
  from user_tab_columns
 where table_name in ('FOO','BAR')
        ;

This query returns:

create or replace view my_view as 
 select FOO.ID as "FOO.ID", FOO.A as "FOO.A", FOO.B as "FOO.B", FOO.C as "FOO.C"
      , BAR.FOO_ID as "BAR.FOO_ID", BAR.A as "BAR.A"
      , BAR.B as "BAR.B", BAR.C as "BAR.C"
   from foo f 
   join bar b on f.id = b.foo_id

【讨论】:

    【解决方案2】:

    使用别名不会使查询变得不切实际,只是不如键入 * 方便。使用动态 SQL 为您生成列:

    select 'f.' || column_name || ' as F_' || column_name || ','
    from all_tab_columns
    where table_name = 'FOO'
    order by column_id;
    

    对您需要的任何其他宽表执行相同操作,然后复制/粘贴到您的查询中。还要注意 30 个字符的限制,希望您的列的大小都不超过 28。

    【讨论】:

    • 感谢您的建议,但我特别要求提供不涉及明确列出列的解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-11-27
    • 2013-08-19
    • 1970-01-01
    • 2014-04-29
    • 2017-02-24
    • 2015-05-01
    • 1970-01-01
    相关资源
    最近更新 更多