【问题标题】:Literal does not match format string error When calculating the difference between two dates in oracle在oracle中计算两个日期之差时,Literal does not match format string error
【发布时间】:2021-07-12 17:05:38
【问题描述】:

我想计算两个日期之间的差异,并在 Oracle 中获取这些日期之间的天数差异。 这是我的代码:

Select To_Date(TO_CHAR(sysdate, 'YYYY/MM/DD','nls_calendar=persian'))- TO_Date(TO_CHAR(SHF_Date))
from DtTable

但我收到此错误:

ORA-01861: 文字与 case 语句的格式字符串不匹配

【问题讨论】:

  • SYSDATE(显然还有SHF_Date)返回一个DATE值,切勿在已经是DATE的值上使用TO_DATE()

标签: sql oracle date select oracle11g


【解决方案1】:

存储格式和显示格式是两个不同的东西。我们让 Oracle 存储数据使用它自己的内部格式,对于DATE 列,它是一个人类不可读的 7 字节二进制值。

您如何选择显示报表或应用程序中的值是另一回事 - 例如,您可以显示与 10001,0001e3 相同的数字,或者显示与2021-04-18Sunday 18th April 相同的日期。这与您如何存储它无关。您不能存储任何首选的显示格式。您必须在查询时或在应用程序中处理显示格式。

另外,在 Oracle 日期算术中,从另一个日期减去一个日期会得到天数,因此尝试查询 to_date(date2 - date1) 将永远无法工作,因为它如何将 270 等天数转换为日期?

create table dttable (shf_date date);

insert into dttable (shf_date)
values (to_date('1399/05/01','YYYY-MM-DD', 'nls_calendar=Persian'));

(注意 shf_date 的定义为 Oracle date。在您的表中是这样的吗?)

select to_char(shf_date, 'YYYY-MM-DD', 'nls_calendar=Gregorian') as shf_date_gregorian
     , to_char(shf_date, 'YYYY-MM-DD', 'nls_calendar=Persian') as shf_date_shamsi
     , trunc(sysdate - shf_date) as days_since_shf_date
from   dttable;

SHF_DATE_GREGORIAN   SHF_DATE_SHAMSI DAYS_SINCE_SHF_DATE
-------------------- --------------- -------------------
2020-07-22           1399-05-01                      270

【讨论】:

  • @William Roberston 谢谢威廉。我必须检查 where 子句的这些日期之间的差异。我运行这段代码: select trunc(sysdate - shf_date) from dttable;但我收到“无效号码”错误。
  • @n.e - 那么shf_date 实际上不是date 列,听起来您将其存储为字符串。将表定义(例如来自describe dttable)和示例数据添加到您的问题中。
  • @William Roberston 那么如何计算减去 sysdate 和 shamsidate?
  • @n.e 我的例子和你的有什么不同?如果您复制并粘贴我的示例(如果您已经有一个具有该名称的表,则可能为dttable 使用不同的名称)您会得到相同的结果吗?您能否制作类似于我的示例并将其添加到您的问题中,从create table 开始,然后是insert,然后是select?或者,在db-fiddlesqlfiddle 上创建一个演示(选择Oracle)?
  • @n.e 这就是为什么在提问时包含问题的minimal, complete, reproducible example 总是一个好主意。它还显示了在设计表格时选择正确数据类型的优势。
【解决方案2】:

虽然你多次说过shf_date 是一个约会,但你也说过类似的话:

sysdate 是:DD/MM/YYYY 但 shf_date 是:YYYY/MM/DD

我运行这段代码:select trunc(sysdate - shf_date) from dttable;但我收到“无效号码”错误。

这意味着它不是日期,而是存储为字符串。因此,您需要将该字符串转换为公历中的日期,以便可以将实际日期与 sysdate 进行比较。

修改和扩展威廉的例子:

select sysdate as sysdate_date
     , to_char(sysdate, 'YYYY-MM-DD', 'nls_calendar=Gregorian') as sysdate_gregorian
     , to_char(sysdate, 'YYYY-MM-DD', 'nls_calendar=Persian') as sysdate_shamsi
     , shf_date as shf_date_string
     , to_date(shf_date, 'YYYY/MM/DD', 'nls_calendar=Persian') as shf_date_date
     , to_char(to_date(shf_date, 'YYYY/MM/DD', 'nls_calendar=Persian'), 'YYYY-MM-DD', 'nls_calendar=Gregorian') as shf_date_gregorian
     , to_char(to_date(shf_date, 'YYYY/MM/DD', 'nls_calendar=Persian'), 'YYYY-MM-DD', 'nls_calendar=Persian') as shf_date_shamsi
     , trunc(sysdate - to_date(shf_date, 'YYYY/MM/DD', 'nls_calendar=Persian')) as days_since_shf_date
from   dttable;
SYSDATE_DATE | SYSDATE_GREGORIAN | SYSDATE_SHAMSI | SHF_DATE_STRING | SHF_DATE_DATE | SHF_DATE_GREGORIAN | SHF_DATE_SHAMSI | DAYS_SINCE_SHF_DATE
:----------- | :---------------- | :------------- | :-------------- | :------------ | :----------------- | :-------------- | ------------------:
18-APR-21    | 2021-04-18        | 1400-01-29     | 1399/05/01      | 22-JUL-20     | 2020-07-22         | 1399-05-01      |                 270

db<>fiddle

如果你想在过滤器中使用它,那么你可以这样做:

where trunc(sysdate - to_date(shf_date, 'YYYY/MM/DD', 'nls_calendar=Persian')) = 270

或您需要执行的任何比较。

【讨论】:

    【解决方案3】:

    如果你想使用你的语句

    Select To_Date( TO_CHAR(sysdate, 'YYYY/MM/DD','nls_calendar=persian'), 'YYYY/MM/DD')- TO_Date(TO_CHAR(SHF_Date, 'YYYY/MM/DD'), 'YYYY/MM/DD') from DtTable;
    

    但这没有任何意义。

    这样使用

    Select sysdate - hire_date from employees;
    

    【讨论】:

    • 感谢您的回复。我应该将 sysdate 转换为 shamsi 日期,因为 SHF_Date 格式是 shamsi 日期。
    • @n.e 列SHF_Date 是如何定义的?是DATEVARCHAR2 还是别的什么?
    • 是日期。例如:1399/05/01
    • @n.e 请参阅此链接以了解有关日期数据类型的更多信息。 docs.oracle.com/cd/B19306_01/server.102/b14200/… 日期并没有像您在获取它们时看到的那样存储。日期存储在 Oracle 数据库的七个不同组件中。世纪、年、月、日、时、时、分、秒,并在您使用 NLS_DATE_FORMAT 或用户定义的格式获取它们时进行格式化。
    【解决方案4】:

    sysdate 已经是一个日期,shf_date 似乎也是一个。这里不需要任何转换,直接减去即可:

    SELECT sysdate - SHF_Date FROM DtTable
    

    【讨论】:

    • 感谢您的回复。 SHF_Date 是 Shamsi 日期。例如:'1399/12/05',其格式与 sysdate 格式不同。
    • 我应该将 sysdate 转换为 shamsi 日期。
    • @n.e shf_date 列的 Oracle data type 是什么?
    • @WilliamRobertson 现在是日期。
    • @n.e 如果 sysdate 和 shf_date 在没有任何格式的情况下查询它们时显示的格式不同(没有 to_charto_date 等),那么 shf_date 不能是 Oracle DATE。很可能是VARCHAR2
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-08-23
    • 1970-01-01
    • 1970-01-01
    • 2021-11-25
    • 2011-08-01
    • 2010-12-04
    • 1970-01-01
    相关资源
    最近更新 更多