【问题标题】:oracle PLSQL- Only provide hour, minute and second from timestamporacle PLSQL - 仅提供时间戳中的小时、分钟和秒
【发布时间】:2017-12-04 16:19:48
【问题描述】:

有没有办法只从时间戳中提取 HOUR、MINUTES 和 Seconds.. 以及 date ofc 但我不希望它显示 fractional_seconds_precision.. 例如,当我输入以下内容时:

TO_TIMESTAMP('2017-12-02 05:00:00', 'YYYY-MM-DD HH24:MI:SS')

我只想显示我在格式中指定的内容,我不希望显示 FF,但每当我检查输出时,FF 总是随之而来。如何删除它?另外,我想问一下,有没有办法将使用时间戳输入的日期与使用 TO_DATE 输入的日期进行比较?如果我希望一个是时间戳,另一个是 TO_DATE 格式怎么办?谢谢

【问题讨论】:

  • 您希望它显示在哪里?由客户端(或应用程序)决定如何显示时间戳值。为了比较,Oracle 将在日期和时间戳之间implicitly convert...
  • 在我的数据库中.. 就像我在字段中插入该格式的时间戳值一样,它仍然显示 FF 沿
  • @AlexPoole ^^^^
  • 什么用小数秒显示? SQL*Plus? SQL开发者?一些应用程序?如果它是时间戳,则您不能删除小数秒,但您可以(并且应该)格式化日期以供最终显示。请参阅 to_char()format models。您也不要以该格式插入 - 您正在将字符串转换为 Oracle 的内部时间戳格式;用to_char() 反转它会再次给你一个字符串。
  • @AlexPoole 嗯,我还需要对时间进行一些计算,所以如果我将其转换为字符串,我还能做到吗?抱歉,Oracle 上的整个日期和时间都是新手

标签: oracle timestamp


【解决方案1】:

你的问题没有真正的意义,但我明白你为什么问这个问题。

基本上,您是在说“我有这个字符串 "1",但是当我将它解析为一个数字时,它在小数点后有很多数字:1.0000000000000。如果没有那些额外的零,我该如何存储它”

答案是,你不能:11.000000000 是同一个东西,它们以相同的方式存储,而不是由你决定它的存储方式。您所看到的 1.000000000 的输出是因为您没有要求以特定格式(如 $1.00)输出内部数字 1,所以您只是以默认格式获取它您正在使用的数据库或查询工具

最终,不用担心 - 作为开发人员隐藏或显示这些零无关紧要。当您再次查询时间戳时是否包含它们并不重要。当您的前端应用程序将内容转储到报告中时,它应该按原样从 Oracle 检索时间戳并自行进行格式化;将 $1 存储为数字 1,而不是字符串“$1”。当需要将其放在报告中时,请在生成报告的代码中将其格式化为 1.00 美元。

如果您正在运行使用时间戳字段的查询,则可以与日期进行比较...请记住,日期和时间戳也有时间组件,因此请使用范围查询它们。例如获取时间戳为今天的所有行:

select * from t where mytimestamp >= trunc(sysdate) and mytimestamp < trunc(sysdate)+1

这比这样做更好:

select * from t where trunc(mytimestamp) = trunc(sysdate)

因为 trunc(mystimestamp) 意味着您正在操纵表数据来运行查询。除非您专门为 trunc(mytimestamp) 的输出建立索引,否则此查询可能会像狗一样运行,因为如果查询要求在比较表数据之前对其进行操作,则无法使用 mytimestamp 列上的索引

这可能有助于您在内部考虑,日期通常存储为自某个历史点以来的天数。时间是一天的一小部分。在内部,01-jan-1970 00:00 可能是0,而01-jan-1970 18:00 即下午 6 点,是一天中的四分之三,因此它将存储为 0.75。 02-jan-1970 因此将存储为 1。当您使用 trunc 时,您会去掉小数部分。这就是为什么 trunc 从日期中“删除”时间的原因。它不会“删除”它 - 你不能从日期中删除时间,因为发生的一切都发生在某个时间点。但它确实将时间分量减少到午夜,所以 trunc()ing all the adtes在表格中有效地使它们全部发生在相关日期的午夜。

Oracle 可以在日期方面截断其他内容,例如截断到月初,但现在,请记住,在内部它们是小数,使用范围查询它们(例如“在 1970 年 1 月 1 日到 1970 年 1 月 2 日之间"实际上是在说“介于 0 和 1 之间”——这就是 0.75,即 1970 年 1 月 1 日下午 6 点)

【讨论】:

  • 实际上,如果有人关心(他们不应该!)像 1.00000000 这样的数字的 Oracle 内部存储仍然只是 1(不完全是这样,但在概念上) ); .00000000 未存储 - 它不占用任何磁盘空间。 .00000000在数字显示时由前端加回,但不存盘。
  • 对于任何对 oracle 如何存储数字感到好奇的人:asktom.oracle.com/pls/asktom/… - 本质上,Oracle 为 NUMBER 存储尽可能少的字节。 10,000 需要 2 个字节。 1,000,000,000,000,000,000 也需要 2 个字节,但 999,999,999,999,999,999(仅比以前少 1 个)需要 10 个字节
  • Oracle 也不将日期存储为自一个纪元以来的天数; MoS 文档 ID 69028.1 和 in answers to this question 中描述了内部表示。一天的小数部分用于日期算术,但不用于存储。时间戳类似,但计算返回的是间隔而不是天数。
【解决方案2】:

当您将字符串转换为时间戳(或日期)时,结果是internal Oracle format,您通常无需担心。您只需要知道它在内部看起来与您输入的完全不同。

当您查询时间戳时,您的客户端会决定如何使用您的 NLS 设置格式化时间戳以进行显示。虽然您可以修改它们,但通常最好不要依赖它们 - 因为运行您的代码的其他人可能有不同的设置 - 并将时间戳显式转换为字符串 using the to_char() function 和合适的 format model。在这种情况下:

select to_char(your_column, 'YYYY-MM-DD HH24:MI:SS') from your_table

但这样做只是为了显示目的;当您使用时间戳值时 - 例如添加或删除间隔 - 将其保留为时间戳,并避免执行任何会导致隐式转换为不同数据类型的事情,因为这可能会导致各种问题。

在您的示例中,小数秒部分将为零,但情况可能并非总是如此。如果您实际上有非零小数秒的值,并且想在计算时忽略这些值,您可以 cast() 将该值更改为稍微不同的数据类型,例如精度受限的时间戳:

select cast(to_timestamp('2017-12-02 05:00:00.123', 'YYYY-MM-DD HH24:MI:SS.FF3') as timestamp(0))
from dual;

CAST(TO_TIMESTAMP('2017-12-0
----------------------------
02-DEC-17 05.00.00.000000000

(由我的客户使用我的 NLS 设置显示!),或者您可以转换为日期,具体取决于您正在执行的计算类型 - 您可能已经隐含地这样做了。 Oracle datetimestamp(0) 具有相同的精度,因为两者都可以保存精确到秒的值,但它们的存储方式不同。

如果您将日期与时间戳进行比较,则 Oracle 将 implicitly convert them,这可能会影响其利用索引的能力。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-07-11
    • 2021-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-24
    • 2017-08-01
    • 2013-10-08
    相关资源
    最近更新 更多