【问题标题】:How do I get this timestamp in the format I want, Oracle SQL如何以我想要的格式获取此时间戳,Oracle SQL
【发布时间】:2018-12-18 10:50:49
【问题描述】:

我先运行如下命令,得到如下结果:

select to_char(systimestamp, 'YYYY-MM-DD HH24:MI:SS') from dual;

TO_CHAR(SYSTIMESTAM
-------------------
2018-07-10 10:21:40

这是我想要存储 TIMESTAMP 对象的格式。

但是,当我将其转换回来时,它并没有以我想要的格式出现:

select to_timestamp(to_char(systimestamp, 'YYYY-MM-DD HH24:MI:SS'), 'YYYY-MM-DD HH24:MI:SS') from dual;

TO_TIMESTAMP(TO_CHAR(SYSTIMESTA
-------------------------------
10-JUL-18 10.21.40.000000000 AM

实际上,它将 2018 更改为末尾,将 07 设置为“JUL”,而 10 现在位于最前面。时间也用点分隔,有很多 0 和一个 AM。

我该如何解决这个问题?我是 SQL 开发新手,所以我不确定格式。

非常感谢

【问题讨论】:

  • 时间戳以内部格式存储。使用to_char() 转换为您喜欢的任何字符串表示形式。
  • 我想将数据类型保留为时间戳,以便稍后在需要时对其进行解析(给我从该日期到该日期的记录),例如
  • @KSplitX - 对,这就是 Oracle 的内部表示所做的。您只需将其格式化为可读的字符串,以便最终显示给最终用户。
  • 好吧,如果我理解正确的话,datatype 应该仍然是 TIMESTAMP,如果我以后想解析它,我可以写一个 sql 查询,比如 . .. select to_char(timestamp1, format) from my_table where timestamp1 > timestamp2, 这应该返回我想要的任何格式
  • 为什么不将 SQL 客户端配置为 显示 时间戳?

标签: sql oracle timestamp


【解决方案1】:

这是我想要存储 TIMESTAMP 对象的格式。

这是一个常见的误解——时间戳(和日期)数据类型没有格式;它们在数据库中存储为 20 个字节(或日期为 7 个字节)representing:

  • 年份(2 个字节),
  • 月、日、小时、分钟、整数秒(每个 1 个字节),
  • 小数秒(4 个字节),
  • 时区偏移小时数(1 字节),
  • 时区偏移分钟(1 字节),
  • 其他数据(包括时区位置)(7 个字节)

您可以使用DUMP 函数查看字节:

SELECT DUMP( your_timestamp_column ) FROM your_table;

数据库将对这 20 个字节进行操作,无需任何格式。但这对显示给您(用户)没有用,因此您用于访问数据库的用户界面(SQL/Plus、SQL Developer、Toad、Java、C# 等)将从数据库接收这些原始字节,并将默默地将它们格式化为对您(用户)来说更易于理解的格式。

你真正要问的是:

如何让我用来访问 Oracle 数据库的应用程序更改它用于显示 TIMESTAMP 数据类型的默认格式?

对于 SQL/Plus(和 SQL Developer),您可以使用 NLS_TIMESTAMP_FORMAT 会话参数:

ALTER SESSION SET NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS';

然后:

SELECT SYSTIMESTAMP FROM DUAL;

将输出:

2018-07-10 16:24:53

但是,这只会为您的用户当前会话设置默认格式;其他用户可以设置他们自己的参数,并且可以在他们的会话期间更改值,因此您不应依赖它来提供一致的格式。

相反,如果您想要具有特定格式的TIMESTAMP,那么您应该将其转换为可以具有格式的数据类型 - 字符串。

SELECT TO_CHAR( SYSTIMESTAMP, 'YYYY-MM-DD HH24:MI:SS' ) FROM DUAL;

那么,用户将其默认时间戳格式更改为什么并不重要 - 您的值将始终按照您的预期进行格式化。

【讨论】:

    【解决方案2】:

    正如@Gordon 所说,时间戳(和日期)不是以您可以识别的格式存储的,Oracle 使用了您永远不需要了解或检查的内部表示(但如果您对那种类型感兴趣,它会记录在案)的东西)。

    当您查询时间戳时,它会使用您客户端的 NLS 设置显示,除非您有一个覆盖这些设置的客户端。我可以设置我的会话以匹配您所看到的:

    alter session set nls_timestamp_format = 'DD-MON-RR HH.MI.SS.FF AM';
    
    select to_char(systimestamp, 'YYYY-MM-DD HH24:MI:SS') from dual;
    
    TO_CHAR(SYSTIMESTAM
    -------------------
    2018-07-10 15:37:31
    
    select to_timestamp(to_char(systimestamp, 'YYYY-MM-DD HH24:MI:SS'), 'YYYY-MM-DD HH24:MI:SS') from dual;
    
    TO_TIMESTAMP(TO_CHAR(SYSTIMESTA
    -------------------------------
    10-JUL-18 03.37.31.000000000 PM
    

    我可以改变它,看看你想看到什么:

    alter session set nls_timestamp_format = 'YYYY-MM-DD HH24:MI:SS';
    
    select to_timestamp(to_char(systimestamp, 'YYYY-MM-DD HH24:MI:SS'), 'YYYY-MM-DD HH24:MI:SS') from dual;
    
    TO_TIMESTAMP(TO_CHA
    -------------------
    2018-07-10 15:37:32
    

    但是您所做的只是从带有时区的时间戳(systimestamp 就是这样)转换为字符串,然后再转换回时间戳。您正在丢失时区部分和任何小数秒;您也可以使用cast

    select cast(systimestamp as timestamp(0)) from dual;
    
    CAST(SYSTIMESTAMPAS
    -------------------
    2018-07-10 15:37:32
    

    您可以使用默认的timestamp_tz 格式查看时区和小数秒:

    select systimestamp from dual;
    
    SYSTIMESTAMP                        
    ------------------------------------
    2018-07-10 15:37:33.776469000 +01:00
    

    并用不同的alter 更改它:

    alter session set nls_timestamp_tz_format = 'YYYY-MM-DD HH24:MI:SS.FF3 TZH:TZM';
    
    select systimestamp from dual;
    
    SYSTIMESTAMP                  
    ------------------------------
    2018-07-10 15:37:34.070 +01:00
    

    如果您真的在谈论将时间戳存储在表中,这并不完全相关,但表明存在变化。

    在您的表格中将数据类型设为timestamp(或timestamp with time zonetimestamp with local time zone),并且只需担心将值格式化为字符串,以便在可能的最后时刻呈现给最终用户。

    当您确实需要显示它时,如果显示格式对您很重要,请使用带有显式格式掩码的to_char() - 不要假设运行您的查询的其他任何人都具有相同的 NLS 设置。如您所见,很容易更改这些以修改输出。 (大多数客户端都有办法让您设置默认值,因此您不必每次连接时都执行相同的alter 命令;例如,在 SQL Developer 中,从工具->首选项->数据库->NLS)。如果您想始终显示相同的格式,请使用以下内容:

    select to_char(your_column, 'YYYY-MM-DD HH24:MI:SS') as column_alias
    from your_table
    where your_column < timestamp '2018-01-01 00:00:00'
    

    它还显示了使用时间戳文字过滤的列值(仍然作为时间戳)。

    【讨论】:

      【解决方案3】:

      所以根据您上面的回复,听起来您可能正在尝试做一些您实际上不需要做的事情。

      正如 Gordon 所提到的,时间戳以内部格式存储,因此您可以使用这些值进行操作。如果您将字段存储为时间戳数据类型,则无需关心它在数据库中的格式,您只需要关心它在最后查找查询的方式。您可以使用 to_char 显示日期字段,如果您正确构建了查询,则仍然使用日期范围。

          select to_char(systimestamp, 'YYYY-MM-DD HH24:MI:SS')
          from dual
          WHERE systimestamp <= current_timestamp;
      

      我认为如果不使用 to_char 并丢失数据类型,就不可能像您描述的那样显示时间戳。

      【讨论】:

      • WHERE systimestamp &lt;= current_timestamp 毫无意义。它总是返回 TRUE。
      猜你喜欢
      • 2015-12-14
      • 2023-04-04
      • 1970-01-01
      • 2020-08-24
      • 2016-08-23
      • 2017-12-25
      • 2020-09-24
      • 2019-09-12
      • 1970-01-01
      相关资源
      最近更新 更多