在oracle 11g中将数据类型排序为varchar2的日期字段

时间:2015-05-07 06:58:48

标签: sql oracle oracle11g date-arithmetic date-conversion

我需要将varchar2数据类型列与数字格式的日期值排序为AppBaseThemeYYMM

值范围为

MMYY

长度为4个字符的值表示1900年到1999年之间的年份 少于4个字符表示年份从2000年及以上开始。

我尝试使用LPAD(fieldname,4,' 0')将值返回为

3
6
9
12
103
.
.
9909
9912

如何根据从1900年开始按升序排列的年份值来排序列。 任何人都可以请我提供解决方案......

3 个答案:

答案 0 :(得分:1)

您需要首先区分现有的四位数值,因此您知道它们是20世纪的日期,然后再填补其余的数据。

然后将其转换为日期并摆弄格式以获得所需的排序顺序:

 select to_char( expanded_dt, 'MMYYYY') as switched_dt
 from (
     select to_date(
                  case when length(dt) = 4 then '19'||dt
                  else '20'||lpad(dt,4,'0') end 
             , 'YYYYMM' )
                 as expanded_dt
      from your_table
     )
order by 1 asc
/

答案 1 :(得分:0)

首先,将 DATE 值存储为 VARCHAR2 且仅使用部分元素是一种糟糕的设计。从长远来看,你应该先修改你的设计。

作为解决方法,如果年份值在1950-2049范围内,您可以使用 RR 格式两位数年。< / p>

TO_DATE(LPAD(date_column, 4,'0'), 'RRMM')

LPAD 会添加所需的前导零。

例如,

SQL> alter session set nls_date_format='MM/DD/YYYY';

Session altered.

SQL> WITH dates AS(
  2  SELECT '3' dt FROM dual UNION ALL
  3  SELECT '6' dt FROM dual UNION ALL
  4  SELECT '9' dt FROM dual UNION ALL
  5  SELECT '12' dt FROM dual UNION ALL
  6  SELECT '103' dt FROM dual UNION ALL
  7  SELECT '9909' dt FROM dual UNION ALL
  8  SELECT '9912' dt FROM dual
  9  )
 10  SELECT dt,
 11         TO_DATE(LPAD(dt, 4,'0'), 'RRMM') date_val
 12  FROM dates
 13  ORDER BY date_val;

DT   DATE_VAL
---- ----------
9909 09/01/1999
9912 12/01/1999
3    03/01/2000
6    06/01/2000
9    09/01/2000
12   12/01/2000
103  03/01/2001

7 rows selected.

SQL>

因此,上面的查询为您提供了所需的输出,日期值现在按升序排序。

答案 2 :(得分:0)

您可以根据值的长度添加世纪标记:

select value,
  case when length(value) = 4 then '19' else '20' end || lpad(value, 4, '0') as dt
from t
order by case when length(value) = 4 then '19' else '20' end || lpad(value, 4, '0');

     VALUE DT   
---------- ------
      9909 199909 
      9912 199912 
         6 200006 
         9 200009 
        12 200012 
       103 200103 

或者使用相同的东西并转换为日期,默认为每月的第一天:

select value, to_date(case when length(value) = 4 then '19' else '20' end
    || lpad(value, 4, '0'), 'YYYYMM') as dt
from t
order by to_date(case when length(value) = 4 then '19' else '20' end
    || lpad(value, 4, '0'), 'YYYYMM');

     VALUE DT       
---------- ----------
      9909 1999-09-01 
      9912 1999-12-01 
         6 2000-06-01 
         9 2000-09-01 
        12 2000-12-01 
       103 2001-03-01 

如果您只查看1950-2049 Y2K安全范围内的日期,您可以跳过世纪部分并使用RR日期模型,但是因为这可能会导致您以后出现问题&# 39;在使用长度来支撑世纪方面确实有任何优势:

select value, to_date(lpad(value, 4, '0'), 'RRMM') as dt
from t
order by to_date(lpad(value, 4, '0'), 'RRMM');

     VALUE DT       
---------- ----------
      9909 1999-09-01 
      9912 1999-12-01 
         6 2000-06-01 
         9 2000-09-01 
        12 2000-12-01 
       103 2001-03-01 

SQL Fiddle