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'

您可以尝试使用正则表达式或通过尝试SUBSTRINSTR 各种组件来查找无效数据。然而,这种方法只能是近似的,除非您想尝试实施每一个可能的日历规则(即 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

在TO_DATE函数中使用变量

HSQLDB 中的日期差异

统计出当前各个title类型对应的员工当前(to_date='9999-01-01')薪水对应的平均工资。结果给出title以及平均工资avg

Gym-101194E Problem E. Bet

找到最低总和的指数