【问题标题】:Sort oracle column that contains number data in the form of varchar?对包含varchar形式的数字数据的oracle列进行排序?
【发布时间】:2013-10-16 01:38:57
【问题描述】:

我有一个 oracle 表,它在 varchar2 列中存储以下类型的数据 -

1009-25-7-7-1-7-22-5-7
1009-25-7-7-1-7-22-5-9
1001-2-53
1001-2-53-57
1001-2-53-72
1001-2-53-76
1001-2-53-88
1001-2-53-13
1001-2-53-17
1001-2-53-25

现在我的要求是对这些数据进行数字排序。我在这一列中有数千行,上面有 n 级组合。知道如何对它进行数字排序。真的可以帮助我获得任何输入,因为我对此一无所知。上面的数字系统是以编程方式生成的,例如“数字 1 - 数字 2 - 数字 3”,所以我需要先根据“数字 1”排序,然后是“数字 2”,依此类推。上述数据集的结果应该是 -

1001-2-53
1001-2-53-13
1001-2-53-17
1001-2-53-25
1001-2-53-57
1001-2-53-72
1001-2-53-76
1001-2-53-88
1009-25-7-7-1-7-22-5-7
1009-25-7-7-1-7-22-5-9

【问题讨论】:

  • 您需要先定义排序逻辑,然后才能实现它。例如,您是按第一个“元素”排序,然后是第二个,等等;是一个包含三个元素的值,始终“低于”一个包含四个元素的值;等等。
  • 包括对表格/列的正确描述。另外,“数字”是什么意思?
  • 正常的ORDER BY 子句发生了什么变化?

标签: sql string oracle sorting numbers


【解决方案1】:

这是相当残酷的,并且可能无法使用。看起来嵌套表可能会对该列执行您想要的操作。下面的示例使用一些内置的 xml 实用程序将列分开并重新组合:

  • 使用 REPLACE 和一些连接将列更改为 xml 字符串
  • 使用 xmlsequence 从 xml 字符串中构建一个 xmltype 从 xmltype 中提取元素并将它们视为行
  • 使用 8 位数字格式转换每个行值(将此掩码扩展为最大宽度数)
  • 反转将行串联在一起的过程 (sort_string)
  • 根据填充数字排序

我把这个和一堆剪切和粘贴放在一起:

http://askankit.blogspot.ca/2009/04/use-xmlagg-in-oracle-to-concat-multiple.html https://forums.oracle.com/message/9408528

CREATE TABLE my_table(mycol varchar2(1024));
insert into my_table values('1009-25-7-7-1-7-22-5-7');
insert into my_table values('1009-25-7-7-1-7-22-5-9');
insert into my_table values('1001-2-53');
insert into my_table values('1001-2-53-57');
insert into my_table values('1001-2-53-72');
insert into my_table values('1001-2-53-76');
insert into my_table values('1001-2-53-88');
insert into my_table values('1001-2-53-13');
insert into my_table values('1001-2-53-17');
insert into my_table values('1001-2-53-25');
insert into my_table values('10');
insert into my_table values('2');

查询:

SELECT mycol, sort_string
  FROM (

    SELECT mycol
          ,SUBSTR(REPLACE(REPLACE(XMLAGG(XMLELEMENT("x", x) ORDER BY seq) 
                                    ,'</x>'
                                   )
                           ,'<x>'
                           ,'|'
                           )
                  ,2 ) AS sort_string

      FROM ( SELECT m.mycol
                   ,TO_CHAR(EXTRACTVALUE(column_value,'inner'), '09999999') AS x
                   ,ROWNUM AS seq
               FROM my_table m
                   ,TABLE(xmlsequence(xmltype(
                      '<outer>' ||
                         '<inner>' || REPLACE(mycol,'-','</inner><inner>') || '</inner>' ||
                      '</outer>'
                    ).EXTRACT('outer/*')))
                      )
      GROUP BY mycol

  ) ORDER BY sort_string

结果:

|                  MYCOL |                                                                               SORT_STRING |
|------------------------|-------------------------------------------------------------------------------------------|
|                      2 |                                                                                  00000002 |
|                     10 |                                                                                  00000010 |
|              1001-2-53 |                                                              00001001| 00000002| 00000053 |
|           1001-2-53-13 |                                                    00001001| 00000002| 00000053| 00000013 |
|           1001-2-53-17 |                                                    00001001| 00000002| 00000053| 00000017 |
|           1001-2-53-25 |                                                    00001001| 00000002| 00000053| 00000025 |
|           1001-2-53-57 |                                                    00001001| 00000002| 00000053| 00000057 |
|           1001-2-53-72 |                                                    00001001| 00000002| 00000053| 00000072 |
|           1001-2-53-76 |                                                    00001001| 00000002| 00000053| 00000076 |
|           1001-2-53-88 |                                                    00001001| 00000002| 00000053| 00000088 |
| 1009-25-7-7-1-7-22-5-7 |  00001009| 00000025| 00000007| 00000007| 00000001| 00000007| 00000022| 00000005| 00000007 |
| 1009-25-7-7-1-7-22-5-9 |  00001009| 00000025| 00000007| 00000007| 00000001| 00000007| 00000022| 00000005| 00000009 |

【讨论】:

    【解决方案2】:

    这是一个丑陋的正则表达式,通过添加前导零将每个 1、2 和 3 位数字转换为 4 位数字。如果数字可以超过 4 位,则必须添加更多替换。

    select * from (
      select that_column original, regexp_replace(regexp_replace(regexp_replace(replace(that_column,'-','--'),'(^|-)(\d{1})(-|$)','\1000\2\3'),'(^|-)(\d{2})(-|$)','\100\2\3'),'(^|-)(\d{3})(-|$)','\10\2\3') sortable
      from that_table
    ) order by sortable;
    

    由于 oracle 没有零宽度匹配,首先将每个 '-' 转换为 '--' 以便数字可以匹配为 -##- 与固定位数。因此最里面的函数是replace(that_column,'-','--')

    之后,不按特定顺序,通过添加前导零将选定大小的数字组转换为更大的大小。将 '(^|-)(\d{1})(-|$)' 替换为 '\1000\2\3' 通过添加 3 个前导零将 1 位组转换为 4 位组。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-09-05
      • 2018-12-16
      • 2010-09-12
      • 1970-01-01
      • 2011-05-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多