对记录中的变量进行排序

时间:2013-09-25 21:14:07

标签: sql oracle sorting

我有一个带有多个列的Oracle表,其中一些填充了变量,有大量可能的变量,下面的示例并非详尽无遗。

ID  Col1  Col2  Col3 
--------------------
1   A     B
2   B     A     D
3   B     C
4   C     B     
5   B     B
6   E     D   
7   B     A     C

我需要创建一个解析每行中变量的查询:

ID  Col1  Col2  Col3 
--------------------
1   A     B
2   A     B     D
3   B     C
4   B     C     
5   B     B
6   D     E   
7   A     B     C

我正在寻找一个优雅的解决方案,因为现实世界的问题有20列,最多40个不同的变量(每个长度最多4个字符)和数百万条记录。

1 个答案:

答案 0 :(得分:1)

以下是Oracle 10g及更高版本的变体。因为原始数据集中存在大量行,所以我将尽量避免涉及在完整结果集顶部进行分组和分析功能的解决方案。

此示例的基表:

create table tab1 (
  ID   number,
  col1 varchar2(4), 
  col2 varchar2(4), 
  col3 varchar2(4), 
  col4 varchar2(4) 
)

首先,将每个ID的所有列收集到已排序的集合中:

select
  tab1.ID,
  cast( multiset(
    select 
      decode(level,
        1, tab1.col1,
        2, tab1.col2,
        3, tab1.col3,
        4, tab1.col4,
        null
      )       
    from dual 
    connect by level <= 4
    order by 
      decode(level,
        1, tab1.col1,
        2, tab1.col2,
        3, tab1.col3,
        4, tab1.col4,
        null
      ) 
      nulls last          
  ) as sys.ODCIVarchar2List) sorted_values
from tab1;

拥有这样的数据集,可以在保持指定顺序的同时将值解码回列:

select
  ID,
  (
    select column_value 
    from table(data_list.sorted_values)
    where rownum = 1
  ) as col1,
  (
    select max(decode(rownum, 2, column_value, null))
    from table(data_list.sorted_values)
  ) as col2,
  (
    select max(decode(rownum, 3, column_value, null))
    from table(data_list.sorted_values)
  ) as col3,
  (
    select max(decode(rownum, 4, column_value, null))
    from table(data_list.sorted_values)
  ) as col4
from (
  select
    rownum,  -- this needed as workaround for Oracle bug
    tab1.ID,
    cast( multiset(
      select 
        decode(level,
          1, tab1.col1,
          2, tab1.col2,
          3, tab1.col3,
          4, tab1.col4,
          null
        )       
      from dual 
      connect by level <= 4
      order by 
        decode(level,
          1, tab1.col1,
          2, tab1.col2,
          3, tab1.col3,
          4, tab1.col4,
          null
        ) 
        nulls last          
    ) as sys.ODCIVarchar2List) sorted_values
  from tab1
) 
  data_list

<强> SQLFiddle test

请注意,内部rownum子句中必须select作为this Oracle error的解决方法。