如何在Oracle 10g中将多个列值作为新行返回?

时间:2013-05-02 14:06:12

标签: sql oracle10g

我有一张表格,其中多个帐号与不同的ID(DR_NAME)相关联。每个帐户可能只有0个帐户,多达16个帐户。我相信UNPIVOT会起作用,但我使用的是Oracle 10g,它不支持这个。

DR_NAME   ACCT1   ACCT2   ACCT3   ACC4  
======================================
SMITH     1234
JONES     5678    2541    2547
MARK      NULL    
WARD      8754    6547

我想为每个名称显示一个新行,每行只有一个帐号

DR_NAME   ACCT
==============
SMITH     1234
JONES     5678
JONES     2541
JONES     2547
MARK      NULL
WARD      8754
WARD      6547

3 个答案:

答案 0 :(得分:1)

Oracle 10g没有UNPIVOT函数,但您可以使用UNION ALL查询将列拆分为行:

select t1.DR_NAME, d.Acct
from yourtable t1
left join
(
  select DR_NAME, ACCT1 as Acct
  from yourtable
  where acct1 is not null
  union all
  select DR_NAME, ACCT2 as Acct
  from yourtable
  where acct2 is not null
  union all
  select DR_NAME, ACCT3 as Acct
  from yourtable
  where acct3 is not null
  union all
  select DR_NAME, ACCT4 as Acct
  from yourtable
  where acct4 is not null
) d
  on t1.DR_NAME = d.DR_NAME;

请参阅SQL Fiddle with Demo

此查询使用UNION ALL将列转换为行。我添加了where子句以删除任何null值,否则您将为acct值为null的每个帐户获取多行。排除null值会删除您在最终结果中显示的dr_name = Mark。要包含只有null值的行,我再次将连接添加到表中。

答案 1 :(得分:1)

我知道的最有效的方法是使用某种逻辑进行交叉连接:

select *
from (select t.dr_name,
             (case when n.n = 1 then acct1
                   when n.n = 2 then acct2
                   when n.n = 3 then acct3
                   when n.n = 4 then acct4
              end) as acct
      from t cross join
           (select 1 as n from dual union all
            select 2 from dual union all
            select 3 from dual union all
            select 4 from dual
           ) n
     ) s
where acct is not null

union all方法通常会为每个子查询扫描一次表。这种方法通常会扫描一次表。

答案 2 :(得分:1)

如果您只对插入这些记录感兴趣,那么请查看多表插入 - 对数据进行单次扫描并生成多行,这样效率非常高。

此处的代码示例:http://docs.oracle.com/cd/B28359_01/server.111/b28286/statements_9014.htm#SQLRF01604

请注意,您可以使用多行的语法多次引用同一个表。

insert all
  when acct1 is not null then into target_table (..) values (dr_name,acct1)
  when acct2 is not null then into target_table (..) values (dr_name,acct2)
  when acct3 is not null then into target_table (..) values (dr_name,acct3)
  when acct4 is not null then into target_table (..) values (dr_name,acct4)
select
  dr_name,
  acct1,
  acct2,
  acct3,
  acct4
from my_table.