我试图返回我的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
转换为数字数据类型?
谢谢!
答案 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表的卡片。但问题是该表有两列代表卡片日期。
假设:
为什么你不能使用简单的算术?像那样:
-- 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