Oracle przechowuje DATE
s w tabelach przy użyciu 7 bajtów, gdzie pierwsze 2 bajty to:
- Wiek + 100
- Rok stulecia + 100
Tak więc maksymalna data, która może (technicznie) być przechowywana, jest wtedy, gdy te dwa bajty mają wartości 255
i 199
co dałoby rok 15599
(ignoruję, że teoretycznie można by przechowywać 255
w drugim bajcie, ponieważ otwiera to całą stertę oddzielnych problemów).
Możesz przekonwertować nieprzetworzoną wartość na datę za pomocą DBMS_STATS.CONVERT_RAW_VALUE
co oznacza, że możemy ominąć normalne metody tworzenia dat i bezpośrednio wygenerować wartości bajtów, które zostaną zapisane.
Ta funkcja jest tego przykładem:
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;
/
Następnie, jeśli masz kolumnę daty, możesz wstawić wartości, których normalnie nie wolno wstawiać:
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
nie działa, gdy rok przekracza normalne granice daty. Aby uzyskać wartości przechowywane w tabeli, możesz użyć DUMP
aby uzyskać ciąg znaków zawierający wartości bajtów lub możesz użyć EXTRACT
aby uzyskać poszczególne komponenty.
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;
wyjścia:
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<>graj tutaj