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)