Oracle 10 г, принимая 5 ди git год в дате - PullRequest
0 голосов
/ 15 января 2020

Мне удалось ввести дату 21 февраля 12017 (я знаю, что это неправильная дата) в Oracle 10g в столбце даты. Oracle принял дату штрафа. Когда я попытался выбрать его обратно в SQL Developer, SQL Developer отобразил его как NULL. Но когда я попытался получить дату через java, я получил значение обратно как то, как я вставил. Интересно, что происходит, потому что я также увидел, что Oracle конвертировал другой год с 5 ди git в год с 4 ди git. Я ввел 21 февраля 21019 и Oracle преобразовал год в 4581 во время хранения. Я мог бы даже выбрать это значение в SQL разработчику.

Мне было интересно, можно ли считать исходную дату назад, например, 21 февраля 21019 изменилось на 21 февраля 4581, так как читать 21 февраля 21019 вместо 21 февраля 4581?

1 Ответ

2 голосов
/ 16 января 2020

Oracle хранит DATE s в таблицах, используя 7 байтов , где первые 2 байта:

  • Век + 100
  • Год века + 100

Таким образом, максимальная дата, которая может (технически) быть сохранена, - это когда эти два байта имеют значения 255 и 199, которые дают год 15599 (I '). м, игнорируя, что теоретически вы можете хранить 255 во втором байте, поскольку это открывает целую кучу отдельных проблем).

Вы можете преобразовать необработанное значение в дату , используя 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

дБ <> скрипка здесь

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...