Oracle
 sql >> Datenbank >  >> RDS >> Oracle

Oracle 10g akzeptiert 5-stelliges Jahr in einem Datum

Oracle speichert DATE s in Tabellen mit 7 Bytes, wobei die ersten 2 Bytes sind:

  • Jahrhundert + 100
  • Jahrhundert + 100

Das maximale Datum, das (technisch) gespeichert werden kann, ist also, wenn diese beiden Bytes die Werte 255 haben und 199 was das Jahr 15599 ergeben würde (Ich ignoriere, dass Sie theoretisch 255 speichern könnten im zweiten Byte, da dies einen ganzen Haufen separater Probleme aufwirft).

Sie können einen Rohwert mithilfe von DBMS_STATS.CONVERT_RAW_VALUE in ein Datum umwandeln Das bedeutet, dass wir die normalen Methoden zum Erstellen von Daten umgehen und die zu speichernden Bytewerte direkt generieren können.

Diese Funktion ist ein Beispiel dafür:

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;
/

Wenn Sie dann eine Datumsspalte haben, können Sie Werte einfügen, die Sie normalerweise nicht einfügen dürfen:

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 funktioniert nicht, wenn das Jahr die normalen Grenzen eines Datums überschreitet. Um die in der Tabelle gespeicherten Werte zu erhalten, können Sie DUMP verwenden um einen String zu erhalten, der die Bytewerte enthält, oder Sie können EXTRACT verwenden um die einzelnen Komponenten zu erhalten.

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;

Ausgaben:

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<>hier fummeln