java - Oracle 10g 在日期中接受 5 位数年份

标签 java oracle oracle10g oracle-sqldeveloper

我设法在 Oracle 10g 的日期列中输入日期 21-Feb-12017(我知道这不是正确的日期)。甲骨文接受了这个日期罚款。当我尝试在 SQL Developer 中重新选择它时,SQL Developer 将其显示为 NULL。但是当我尝试通过 java 检索日期时,我得到了插入的值。想知道发生了什么,因为我还可以看到 Oracle 将不同的 5 位数年份转换为 4 位数年份。我输入了 21-Feb-21019,Oracle 在存储时将年份转换为 4581。我什至可以在 SQL Developer 中选择这个值。

我想知道是否可以读取原始日期,例如 21-Feb-21019 更改为 21-Feb-4581,那么如何读取 21-Feb-21019 而不是 21-Feb-4581。

最佳答案

Oracle 使用7 bytes 在表中存储DATE。其中前 2 个字节是:

  • 世纪 + 100
  • 世纪年份 + 100

因此,(技术上)可以存储的最大日期是这两个字节的值 255199 ,这将给出年份 15599 (我忽略了理论上您可以将 255 存储在第二个字节中,因为这会带来一大堆单独的问题)。

您可以convert a raw value to a date使用DBMS_STATS.CONVERT_RAW_VALUE,这意味着我们可以绕过创建日期的常规方法,直接生成要存储的字节值。

此函数是一个示例:

CREATE FUNCTION createDate(
  year   int,
  month  int,
  day    int,
  hour   int,
  minute int,
  second int
) RETURN DATE DETERMINISTIC
IS
  hex CHAR(14);
  d DATE;
BEGIN
  hex := TO_CHAR( FLOOR( year / 100 ) + 100, 'fm0X' )
      || TO_CHAR( MOD( year, 100 ) + 100, 'fm0X' )
      || TO_CHAR( month, 'fm0X' )
      || TO_CHAR( day, 'fm0X' )
      || TO_CHAR( hour + 1, 'fm0X' )
      || TO_CHAR( minute + 1, 'fm0X' )
      || TO_CHAR( second + 1, 'fm0X' );
  DBMS_OUTPUT.PUT_LINE( hex );
  DBMS_STATS.CONVERT_RAW_VALUE( HEXTORAW( hex ), d );
  RETURN d;
END;
/

然后,如果您有日期列,则可以插入通常不允许插入的值:

CREATE TABLE table_name ( date_column DATE );

INSERT INTO table_name ( date_column )
VALUES ( DATE '2019-12-31' + INTERVAL '1:02:03' HOUR TO SECOND );

INSERT INTO table_name ( date_column ) VALUES ( createDate( 15599, 12, 31, 1, 2, 3 ) );

INSERT INTO table_name ( date_column ) VALUES ( createDate( 12017, 2, 21, 0, 0, 0 ) );
当年份超出日期的正常范围时,

TO_CHAR 不起作用。要获取表中存储的值,您可以使用 DUMP 获取包含字节值的字符串,也可以使用 EXTRACT 获取各个组件。

SELECT DUMP( date_column ),
       TO_CHAR( date_column, 'YYYY-MM-DD' ) AS value,
       TO_CHAR( EXTRACT( YEAR FROM date_column ), 'fm00000' )
         || '-' || TO_CHAR( EXTRACT( MONTH  FROM date_column ), 'fm00' )
         || '-' || TO_CHAR( EXTRACT( DAY    FROM date_column ), 'fm00' )
         || ' ' || TO_CHAR( EXTRACT( HOUR   FROM CAST( date_column AS TIMESTAMP ) ), 'fm00' )
         || ':' || TO_CHAR( EXTRACT( MINUTE FROM CAST( date_column AS TIMESTAMP ) ), 'fm00' )
         || ':' || TO_CHAR( EXTRACT( SECOND FROM CAST( date_column AS TIMESTAMP ) ), 'fm00' )
         AS full_value
FROM table_name;

输出:

DUMP(DATE_COLUMN)                 | VALUE      | FULL_VALUE          
:-------------------------------- | :--------- | :-------------------
Typ=12 Len=7: 120,119,12,31,2,3,4 | 2019-12-31 | 02019-12-31 01:02:03
Typ=12 Len=7: 255,199,12,31,2,3,4 | 0000-00-00 | 15599-12-31 01:02:03
Typ=12 Len=7: 220,117,2,21,1,1,1  | 0000-00-00 | 12017-02-21 00:00:00

db<> fiddle here

关于java - Oracle 10g 在日期中接受 5 位数年份,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59758473/

相关文章:

sql - 甲骨文特殊字符

oracle - Oracle中没有时间的日期类型

java - java中如何读取一张ico格式的图片?

java - java中的指数法

sql - 为什么 LIKE '%' 与 '' 或 NULL 不匹配

sql - 找出字符串中出现次数最多的字符

oracle - 如何使用 NHibernate 以编程方式调用 Oracle 存储过程?

java - 矩阵 : get value from given matrix

java - 在 Java 中通过 D-Bus MPRIS 访问 Clementine 实例

oracle - 使用 plsql 的用户定义的自定义聚合函数