在 Oracle 中,将 number(5,10) 转换为日期

发布于 2025-01-06 04:47:09 字数 809 浏览 0 评论 0 原文

在Oracle中执行以下SQL语法时,总是不成功,请帮忙。

40284.3878935185 表示“2010-04-16 09:18:34”,单位为微秒。

纪元日期 1900 年 1 月 1 日(如 Excel)。

create table temp1 (date1 number2(5,10));

insert into temp1(date1) values('40284.3878935185');

select to_date(date1, 'yyyy-mm-dd hh24:mi:ssxff') from temp1

错误报告:SQL 错误:ORA-01861:文字与格式不匹配 细绳 01861. 00000 - “文字与格式字符串不匹配” *原因:输入中的文字必须与中的文字长度相同 格式字符串(前导空格除外)。如果 “FX”修饰符已打开,文字必须完全匹配, 没有多余的空格。 *操作:更正格式字符串以匹配文字。

感谢 Mark Ba​​nnister

现在 SQL 语法是:

select to_char(to_date('1899-12-30','yyyy-mm-dd') + 
date1,'yyyy-mm-dd hh24:mi:ss')  from temp1

但无法获取像 'yyyy-mm-dd hh24:mi:ss.ff' 这样的日期格式。继续寻求帮助。

When ececute the following SQL syntax in Oracle, always not success, please help.

40284.3878935185 represents '2010-04-16 09:18:34', with microsecond.

an epoch date of 01 January 1900 (like Excel).

create table temp1 (date1 number2(5,10));

insert into temp1(date1) values('40284.3878935185');

select to_date(date1, 'yyyy-mm-dd hh24:mi:ssxff') from temp1

Error report: SQL Error: ORA-01861: literal does not match format
string
01861. 00000 - "literal does not match format string"
*Cause: Literals in the input must be the same length as literals in
the format string (with the exception of leading whitespace). If the
"FX" modifier has been toggled on, the literal must match exactly,
with no extra whitespace.
*Action: Correct the format string to match the literal.

Thanks to Mark Bannister

Now the SQL syntax is:

select to_char(to_date('1899-12-30','yyyy-mm-dd') + 
date1,'yyyy-mm-dd hh24:mi:ss')  from temp1

but can't fetch the date format like 'yyyy-mm-dd hh24:mi:ss.ff'. Continue look for help.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

南薇 2025-01-13 04:47:09

使用纪元日期 1899 年 12 月 30 日,尝试:

select to_date('1899-12-30','yyyy-mm-dd') + date1

Using an epoch date of 30 December 1899, try:

select to_date('1899-12-30','yyyy-mm-dd') + date1
以酷 2025-01-13 04:47:09

简单的日期添加不适用于时间戳,至少如果您需要保留小数秒的话。当您执行 to_timestamp('1899-12-30','yyyy-mm-dd')+ date1 (在对马克答案的评论中)时, TIMESTAMP 隐式转换为 DATE 在添加之前,总体答案是DATE,因此没有任何秒小数部分;然后你使用 to_char(..., '... .FF') 它会抱怨 ORA-01821。

您需要将 date1 列保存的天数转换为 间隔。幸运的是,Oracle 提供了一个函数来实现这一点,NUMTODSINTERVAL< /code>

select to_timestamp('1899-12-30','YYYY-MM-DD')
    + numtodsinterval(date1, 'DAY') from temp3;

16-APR-10 09.18.33.999998400

然后您可以以所需的格式显示它,例如(使用 CTE 提供您的 date1 值):

with temp3 as ( select 40284.3878935185 as date1 from dual)
select to_char(to_timestamp('1899-12-30','YYYY-MM-DD')
    + numtodsinterval(date1, 'DAY'), 'YYYY-MM-DD HH24:MI:SSXFF') from temp3;

2010-04-16 09:18:33.999998400

或者限制为千分之一秒:

with temp3 as ( select 40284.3878935185 as date1 from dual)
select to_char(to_timestamp('1899-12-30','YYYY-MM-DD')+
    + numtodsinterval(date1, 'DAY'), 'YYYY-MM-DD HH24:MI:SS.FF3') from temp3;


2010-04-16 09:18:33.999

1899-12-30 的纪元听起来很奇怪,并且与您所说的 Excel 不符。您的预期结果似乎更有可能是错误的,应该是 2010-04-18,所以我会检查您的假设。 Andrew 也提出了一些很好的观点,您应该将您的值存储在表中的 TIMESTAMP 列中。如果您收到这样的数据,您仍然需要按照这些方式在某个时候将其转换为存储。

Simple date addition doesn't work with timestamps, at least if you need to preserve the fractional seconds. When you do to_timestamp('1899-12-30','yyyy-mm-dd')+ date1 (in a comment on Mark's answer) the TIMESTAMP is implicitly converted to a DATE before the addition, to the overall answer is a DATE, and so doesn't have any fractional seconds; then you use to_char(..., '... .FF') it complains with ORA-01821.

You need to convert the number of days held by your date1 column into an interval. Fortunately Oracle provides a function to do exactly that, NUMTODSINTERVAL:

select to_timestamp('1899-12-30','YYYY-MM-DD')
    + numtodsinterval(date1, 'DAY') from temp3;

16-APR-10 09.18.33.999998400

You can then display that in your desired format, e.g. (using a CTE to provide your date1 value):

with temp3 as ( select 40284.3878935185 as date1 from dual)
select to_char(to_timestamp('1899-12-30','YYYY-MM-DD')
    + numtodsinterval(date1, 'DAY'), 'YYYY-MM-DD HH24:MI:SSXFF') from temp3;

2010-04-16 09:18:33.999998400

Or to restrict to thousandths of a second:

with temp3 as ( select 40284.3878935185 as date1 from dual)
select to_char(to_timestamp('1899-12-30','YYYY-MM-DD')+
    + numtodsinterval(date1, 'DAY'), 'YYYY-MM-DD HH24:MI:SS.FF3') from temp3;


2010-04-16 09:18:33.999

An epoch of 1899-12-30 sounds odd though, and doesn't correspond to Excel as you stated. It seems more likely that your expected result is wrong and it should be 2010-04-18, so I'd check your assumptions. Andrew also makes some good points, and you should be storing your value in the table in a TIMESTAMP column. If you receive data like this though, you still need something along these lines to convert it for storage at some point.

情绪 2025-01-13 04:47:09

不确切知道纪元日期,但请尝试以下操作:

select to_date('19700101','YYYYMMDD')+ :secs_since_epoch/86400 from dual;

或者,转换为时间戳,例如:

select cast(to_date('19700101', 'YYYYMMDD') + :secs_since_epoch/86400 as timestamp with local time zone) from dual;

Don't know the epoch date exactly, but try something like:

select to_date('19700101','YYYYMMDD')+ :secs_since_epoch/86400 from dual;

Or, cast to timestamp like:

select cast(to_date('19700101', 'YYYYMMDD') + :secs_since_epoch/86400 as timestamp with local time zone) from dual;
深海夜未眠 2025-01-13 04:47:09

我希望这不会让人觉得太严厉,但你必须完全重新考虑你的方法。

您根本没有保持数据类型的直接性。您的示例的每一行都滥用了一种数据类型。

  • TEMP1.DATE1 不是日期或 varchar2,而是一个数字,
  • 您插入的不是数字 40284.3878935185,而是 STRING >>> '40284.3878935185'<<
  • 您的 SELECT TO_DATE(...) 使用 NUMBER Temp1.Date1 值,但使用格式块将其视为 VARCHAR2

我大约 95% 确定您认为 Oracle 使用简单块数据副本传输此数据。 “既然每个 Oracle 日期都存储为数字,为什么不直接将该数字插入表中呢?”嗯,因为当您将列定义为 NUMBER 时,您是在告诉 Oracle“这不是日期”。因此,Oracle 不将其作为日期进行管理。

这些类型转换中的每一个都是由 Oracle 根据当前会话变量计算的。如果您在法国,那里的“.”是千位分隔符而不是基数,则 INSERT 将完全失败。

所有这些字符串转换都会由 Oracle 认为您运行的语言环境进行修改。检查字典视图V$NLS_PARAMETERS。

对于日期/时间值,情况会变得更糟。日期/时间值可能遍布整个地图 - 主要是因为时区。您的数据库服务器位于哪个时区?它认为您正在从哪个时区运行?如果这还不够让您感到困惑,请查看如果将 Oracle 的默认日历从公历更改为泰佛历,会发生什么情况。

我强烈建议你完全摆脱这些数字。

要创建日期或日期时间值,请使用具有完全不变且明确格式的字符串。然后专门对日期值进行赋值、比较和计算,例如:

GOODFMT 常量 VARCHAR2 = 'YYYY-MM-DD HH24:MI:SS.FFF ZZZ'

Good_Time DATE = TO_DATE('2012-02-17 08:07:55.000 EST',好的DFMT);

I hope this doesn't come across too harshly, but you've got to totally rethink your approach here.

You're not keeping data types straight at all. Each line of your example misuses a data type.

  • TEMP1.DATE1 is not a date or a varchar2, but a NUMBER
  • you insert not the number 40284.3878935185, but the STRING >> '40284.3878935185' <<
  • your SELECT TO_DATE(...) uses the NUMBER Temp1.Date1 value, but treats it as a VARCHAR2 using the format block

I'm about 95% certain that you think Oracle transfers this data using simple block data copies. "Since each Oracle date is stored as a number anyway, why not just insert that number into the table?" Well, because when you're defining a column as a NUMBER you're telling Oracle "this is not a date." Oracle therefore does not manage it as a date.

Each of these type conversions is calculated by Oracle based on your current session variables. If you were in France, where the '.' is a thousands separator rather than a radix, the INSERT would completely fail.

All of these conversions with strings are modified by the locale in which Oracle thinks your running. Check dictionary view V$NLS_PARAMETERS.

This gets worse with date/time values. Date/time values can go all over the map - mostly because of time zone. What time zone is your database server in? What time zone does it think you're running from? And if that doesn't spin your head quite enough, check out what happens if you change Oracle's default calendar from Gregorian to Thai Buddha.

I strongly suggest you get rid of the numbers ENTIRELY.

To create date or date time values, use strings with completely invariant and unambiguous formats. Then assign, compare and calculate date values exclusively, e.g.:

GOODFMT constant VARCHAR2 = 'YYYY-MM-DD HH24:MI:SS.FFF ZZZ'

Good_Time DATE = TO_DATE ('2012-02-17 08:07:55.000 EST', GOODFMT);

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文