Varchar2 到 Date 用于 sysdate 比较

Posted

技术标签:

【中文标题】Varchar2 到 Date 用于 sysdate 比较【英文标题】:Varchar2 to Date for sysdate comparison 【发布时间】:2014-09-22 15:58:36 【问题描述】:

我正在查询的表的日期存储为 varchar2。我需要使用BETWEEN sysdate-1 AND sysdate-30 将存储为 varchar2 的日期与 sysdate 进行比较(以返回上个月的 varchar2 日期)。

当指定TO_DATE(varchar2, 'DD-MON-YYYY') 时出现错误“文字与格式字符串不匹配”。

我被困住了,因为 Oracle 文档说这是 TO_DATE() 从 varchar2 转换时可接受的格式。

更新:这是一个企业数据库,我没有设计数据库,只能使用我现有的数据库。数据集非常庞大,由 SCADA 设备自动更新,每天超过 10,000 台设备。

SELECT device_name, read_date, sysdate

FROM oracle_database

------- Data Returned by query --------

device_name read_date   sysdate
Device 1    5/14/2013   22-Sep-14
Device 2    5/14/2013   22-Sep-14
Device 3    5/14/2013   22-Sep-14
Device 4    5/14/2013   22-Sep-14
Device 5    5/14/2013   22-Sep-14
Device 6    5/14/2013   22-Sep-14
Device 7    5/14/2013   22-Sep-14

使用 TO_DATE 的结果

SELECT device_name, TO_DATE(read_date, 'DD-MON-YY'), 系统日期

------- 查询返回的数据 ----------

ORA-01861: 文字与格式字符串不匹配

【问题讨论】:

你能举例说明你的输入吗? 您必须使用与您实际存储的字符串相匹配的格式。你必须希望它们都采用相同的格式并且是有效的......它可能有一个尝试多种格式的函数,但这很混乱,尤其是。如果您有 DD/MM 和 MM/DD 日期的混合。这就是为什么不应将日期存储为字符串的原因...无论如何,如果您显示一些示例数据和它们所代表的日期(如果不明显),那么可以建议一个合适的模型。 @Alex,如果我尝试根据“为什么不将日期存储为字符串”来回答,我希望你不会介意。我已经包含了 Ed Stevens 关于它的文章的链接,这非常棒。我在任何地方都使用相同的链接来回答类似的问题。 @LalitKumarB - 虽然它是有效的,但我认为它不能解释 OP 看到的错误,或者如何处理它。 (除了存储为日期;但随后模型问题可能会转移到插入)。但是在知道字符串的格式之前,没什么好说的...... @Alex,如果他不确定 nls 设置,我想告诉 OP 用nls_date_format 更改他的会话,但我没有这样做,因为我的业余爱好者在查询级别格式上玩的比会话级别更多,并且它将覆盖会话级别设置。让我们看看 OP 告诉我们的更多细节。我将尝试根据 OP 的新输入即兴回答。 【参考方案1】:

鉴于您的数据,正确的格式很可能是MM/DD/YYYY。它将匹配一位数和两位数的月份或日期。

MM :从 01 到 12 的月份(前导 0 默认不强制) \ : 任何标点符号 DD :从 01 到 31 的日期(前导 0 默认不强制) \ : 任何标点符号 YYYY:年份

详情请参阅 Oracle 的documentation about datetime Format Models 。

示例如下:

-- Some test data
WITH testdata AS (
  SELECT '5/14/2013' as d FROM DUAL
  UNION SELECT '05/14/2013' FROM DUAL
  UNION SELECT '5/1/2013' FROM DUAL
  UNION SELECT '5/01/2013' FROM DUAL
  UNION SELECT '6-6-2013' FROM DUAL)

-- Actual query demonstrating the use of the MM/DD/YYYY format
select d, TO_DATE(d,'MM/DD/YYYY') FROM testdata

制作:

D           TO_DATE(D,'MM/DD/YYYY')
05/14/2013  05/14/2013
5/01/2013   05/01/2013
5/1/2013    05/01/2013
5/14/2013   05/14/2013
6-6-2013    06/06/2013

如果您确实需要强制执行日期组件由/(而不是任何其他标点符号)分隔的事实,您应该改用fxfmMM/DD/YYYY

fx 标志强制严格比较,用于格式中的标点符号和位数 fm 标志放宽了比较以允许 向上 到指定的位数

【讨论】:

如何将 testdata 子查询与我的 devices 表连接起来?我不能使用日期,因为它不是唯一的。我阅读了与 WITH 相关的 Oracle 文档,但仍然是空白。此外,鉴于上述情况,似乎无法在子查询中返回日期范围之外的任何数据。例如:WHERE sysdate BETWEEN (sysdate-1) AND (sysdate-30) @tx_query - testdata 只是为了提供一些像你这样的示例数据,并展示如何使用这种格式模型成功地将其转换为日期。您不需要testdata 或加入。只需在原始查询中使用 TO_DATE(read_date, 'MM/DD/YYYY') @AlexPoole 对于它的价值,我发现格式是 yyyy-mm-dd 并使用 ROUND(avg(valve_pressure) over (PARTITION BY unique_id order by to_date(read_date,'yyyy- mm-dd') 范围在前 30 行和当前行之间)) MA_30 非常感谢你们两个及时和礼貌的回复。【参考方案2】:
SELECT device_name, TO_DATE(read_date, 'DD/MM/YYYY'), sysdate

【讨论】:

如果您添加一些解释和文档链接,答案会变得更有价值,因此原始发布者和其他用户实际上可以从中学习。【参考方案3】:

首先,您的设计存在缺陷。您永远不应该将 DATE 用作 VARCHAR2 数据类型。

其次,在比较日期并将date literal 转换为DATE 时,始终在两边指定相同的格式掩码。

要将字符串转换为日期,请使用带有正确格式掩码的TO_DATE

要将日期转换为字符串,请使用具有相同格式掩码的TO_CHAR

确保在比较表达式中的值时,explicitly 转换comparison operator 两侧的数据类型以避免implicit data type conversion

你必须阅读这篇由 bEd Stevens 撰写的优秀文章,http://edstevensdba.wordpress.com/2011/04/07/nls_date_format/

【讨论】:

以上是关于Varchar2 到 Date 用于 sysdate 比较的主要内容,如果未能解决你的问题,请参考以下文章

DBMS_SQL.BIND_VAR 到一个函数(例如 sysdate)

oracle中两个varchar2类型的时间怎么进行比较

Sysdate 作为 char 而不是 date

sysdate 的 to_date 函数问题

没有小时、分钟、秒的 Oracle current_date 或 sysdate [重复]

需要对 varchar2 列进行排序