如何将sysdate月份值转换为oracle中的数字?

时间:2014-09-22 14:31:50

标签: sql oracle

我试图返回我的CARD表的卡片,该卡片将在下个月到期。但问题是该表有两列代表卡片日期。列是EXPIREDAY和EXPIREMONTH,都是数字。因此,当我执行该查询时,我收到错误:

   select * from CARD WHERE EXPIREDAY <= sysdate - interval '2' DAY;
   //Oracle error: ORA-00932: inconsistent datatypes: expected NUMBER got DATE

有没有办法将sysdate - interval '2' DAY转换为数字数据类型?

谢谢!

4 个答案:

答案 0 :(得分:2)

如果要将值作为字符串进行比较,可以使用它来转换SYSDATE

SELECT TO_CHAR(sysdate, 'MM') || TO_CHAR(sysdate, 'DD') MONTH_NUM FROM DUAL
-- gives you "0922"

这对于您的数字列,如果您只有一位数

,将使用前导零填充
SELECT TO_CHAR(9, 'FM00') || TO_CHAR(22, 'FM00') MONTH_NUM FROM DUAL
-- also gives you "0922"

如果您可以控制表模式,最好将DAY和MONTH值存储在单个数字字段中,以便将9-SEP作为数值0922存储在此列中月份是第一个,以便使用自然顺序。

答案 1 :(得分:2)

一种简单且不一定非常有效的方法是使用to_date()将日期和月份值转换为实际日期,然后将其与目标日期范围进行比较:

select * from card
where to_date(lpad(expireday, 2, '0')
  ||'/'|| lpad(expiremonth, 2, '0'), 'DD/MM')
between sysdate and add_months(sysdate, 1);

Which appears to work。但如果日期跨越年底,这将有问题。由于您的表格未指定年份,因此您必须先完成一个工作,或允许to_date将其默认为当前年份。如果你让它默认,那么它将无法工作。例如,如果您的表中包含12月和1月的值,并在12月运行此查询,则1月日期将被视为2014年1月,并且不会计入下个月。所以你需要做更多的事情来选择合适的一年。

这会将当前月份之前的任何月号视为 next 年,这对您来说可能已经足够了,因为您只有一个月的窗口:

select * from card
where to_date(lpad(expireday, 2, '0')
  ||'/'|| lpad(expiremonth, 2, '0')
  ||'/'|| (extract(year from sysdate) +
    case when expiremonth < extract(month from sysdate) then 1 else 0 end),
    'DD/MM/YYYY')
between sysdate and add_months(sysdate, 1);

SQL Fiddle使用12月到1月的日期范围。

您可以看到两列合并形成日期in this Fiddle的方式。

通常,道德是......将事物存储为正确的数据类型。将日期存储为日期,而不是字符串或数字。

答案 2 :(得分:2)

  

我试图返回将在下个月到期的CARD表的卡片。但问题是该表有两列代表卡片日期。

假设:

  1. 你正在使用浮动月份(比如:从12月23日到23日)和
  2. 你的桌子只包含一个(浮动?)年份的数据
  3. 为什么你不能使用简单的算术?像那样:

    -- some constant definitions for testing purpose
    with cst as (
      select EXTRACT(DAY from TO_DATE('23/12','DD/MM')) as theDay,
             EXTRACT(MONTH from TO_DATE('23/12','DD/MM')) as theMonth
      from dual)
    
    -- the actual query
    select card.* from card,cst 
      where (expiremonth = theMonth AND expireday > theDay)
         or (expiremonth = 1+MOD(theMonth,12) AND expireday <= theDay);
      --                   ^^^^^^^^^^^^^^^^^^
      --            map [01 .. 12] to [02 .. 12, 01] (i.e.: next month)
    

    这将简单地选择从明天到月底的所有“伪日期”,以及当前#下个月之前(包括)的任何一个“伪日期”。

    请参阅this example


    对于更通用的内容,但可能比转换所有值TO_DATE更高效,您可能想尝试:

    -- the calendar is the key part of the query (see below)
    with calendar as (
      select extract(month from sysdate + level) as theMonth,
             extract(day from sysdate + level) as theDay
        from DUAL connect by ROWNUM <= 8)
    --                                 ^
    --              adjust to the right number of days you are looking for
    select card.* from card join calendar
      on expiremonth = theMonth and expireDay = theDay
    

    这里的想法是简单地构建一个包含所有即将到来的日历的日历,然后在该日历上加入您的数据表。请参阅example here

答案 3 :(得分:1)

尝试使用to_char(sysdate - interval '2' DAY,'ddmmyyyy')转换为字符类型。日期格式('ddmmyyyy')将取决于expiredate

的值