我设法在 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
因此,(技术上)可以存储的最大日期是这两个字节的值 255
和 199
,这将给出年份 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/