TO_DATE 然后在 WHERE 中使用 BETWEEN
Posted
技术标签:
【中文标题】TO_DATE 然后在 WHERE 中使用 BETWEEN【英文标题】:TO_DATE and then use in the WHERE with a BETWEEN 【发布时间】:2013-06-10 18:53:39 【问题描述】:我可以在下面使用这个 SELECT,去掉 24 小时的谬误并将其替换为 00 小时,然后运行 WHERE TRUNC(TO_DATE(FIX_DATETIME, 'MMDDYYHH24MISS')) BETWEEN TRUNC(SYSDATE-90) AND TRUNC(SYSDATE) ?可以一次性完成吗?如果是这样,无论是通过还是更多,如何?非常感谢您的帮助,并尊重您的技能水平。
SELECT MOPACTIVITY.MOPID,
(CASE
WHEN SUBSTR(MOPACTIVITY.MOPID, 7, 2) = '24' THEN SUBSTR(MOPACTIVITY.MOPID, 1, 2)||SUBSTR(MOPACTIVITY.MOPID, 3, 2)||SUBSTR(MOPACTIVITY.MOPID, 5, 2)||'00'||SUBSTR(MOPACTIVITY.MOPID, 9, 2)||SUBSTR(MOPACTIVITY.MOPID, 11, 2)
ELSE MOPACTIVITY.MOPID
END ) FIX_DATETIME,
sysdate "SYSDATE"
FROM MOPUSER.MOPACTIVITY
【问题讨论】:
为什么要将日期存储在 varchar 列中?这肯定会惹上麻烦。 大公司数据库。我已经要求改变,但它不会发生。这就是我为什么要尝试解决它的原因。有什么想法吗? 唯一的 明智的解决方案是将列更改为适当的DATE
列。其他一切都只是一个技巧。
我听到并同意你的看法,但改变不会发生。数据库不会改变,所以我必须破解它。我相信我已经向高层提出了这个问题,但我在大喊大叫。 :( 不知道如何破解它?
【参考方案1】:
暂且不谈名为MOPID
的列的不协调性,有人自然会认为它是某种数字ID,实际上是VARCHAR2
,恰好代表DATE
,而且您永远不应该将DATE
存储为VARCHAR2
,因为您将不可避免地在该列中得到无效数据,这将导致查询在查询计划更改时看似随机地开始抛出错误...
WHERE to_date(MOPACTIVITY.MOPID, 'MMDDYYHH24MISS') BETWEEN (sysdate-90) and sysdate
会做你想做的事。
识别包含无效数据的行(当您使用错误的数据类型时几乎可以肯定)
CREATE OR REPLACE FUNCTION is_valid_date( p_str IN VARCHAR2,
p_mask IN VARCHAR2 )
RETURN VARCHAR2
IS
l_dt DATE;
BEGIN
l_dt := to_date( p_str, p_mask );
RETURN 'Y';
EXCEPTION
WHEN OTHERS THEN
RETURN 'N';
END;
然后
SELECT *
FROM MOPACTIVITY
WHERE is_valid_date( MOPID, 'MMDDYYHH24MISS' ) = 'N'
您可以尝试使用正则表达式或通过尝试SUBSTR
和INSTR
各种组件来查找无效数据。然而,这种方法只能是近似的,除非您想尝试实施每一个可能的日历规则(即 29-31 是某些月份和某些年份的有效日期,但不是其他日期)。让to_date
尝试转换并依靠 Oracle 来实现所有这些规则通常更容易。
【讨论】:
我喜欢你的介绍:-)。我假设sysdate - 90
暗示 OP 也想要 3 个月前,这意味着 ADD_MONTHS(sysdate, -3)
可能 是他们真正想要的。
我完全同意你关于 MOPID 字段是如何设置的,但我继承了这个烂摊子。我尝试了您建议的相同代码,但出现错误:ORA-01850:小时必须在 0 到 23 之间。是什么原因造成的,我该如何解决?
这可能意味着您的数据无效,正如预测的那样。您可以使用 SELECT MOPID FROM myTable WHERE SUBSTR(MOPID, 7, 2) NOT BETWEEN '00' AND '23'
之类的查询找到错误值。
@EdGibbs,这肯定是问题的核心!我仍在努力寻找解决方案。你让我更近了一步。谢谢!
不客气!如果您需要深入研究并找到错误的值,可能首先要确保该列至少有 12 位数字。您可以使用SELECT * FROM myTable WHERE NOT REGEXP_LIKE(MOPID, '^\d12$')
找到不完全是 12 位的列。一旦你得到了不是所有数字的东西,你就可以开始做一些数字比较,以确保月份在 1 到 12 之间,小时在 0 到 23 之间,等等。祝你好运 - 我继承了很多糟糕的数据库,所以我能感受到你的痛苦:)【参考方案2】:
如果您正在寻找 日期 比较,您应该使用:
WHERE to_date(MOPACTIVITY.MOPID, 'MMDDYYHH24MISS') BETWEEN trunc(sysdate-90) and trunc(sysdate)
或
WHERE to_date(substr(MOPACTIVITY.MOPID, 1, 6), 'MMDDYY') BETWEEN trunc(sysdate-90) and trunc(sysdate)
这假设您需要完整的日期,包括当天(部分到当前时间)和从午夜开始的第一天(不是当前时间)。
【讨论】:
错误:ORA-01830:日期格式图片在转换整个输入字符串之前结束 所以我的地方看起来像这样 所以真的没有办法将 varchar2 字段剥离为 mm/dd/yyyy 格式,以便在 sql 的 WHERE 中的 BETWEEN 中使用?我知道这是正确的字段类型,但这是我无法控制的。 :( @CorpaLoom 。 . .我想我只是不在字符串中存储日期/时间字段。无论如何,我修改了答案以显示两种不同的方法。 ...非常感谢您的帮助!以上是关于TO_DATE 然后在 WHERE 中使用 BETWEEN的主要内容,如果未能解决你的问题,请参考以下文章
ORA-01839“日期对于指定的月份无效”对于 where 子句中的 to_date
统计出当前各个title类型对应的员工当前(to_date='9999-01-01')薪水对应的平均工资。结果给出title以及平均工资avg