Разница между двумя датами
У меня есть таблица со следующими данными
fromDate | toDate
20JAN11 | 29DEC30
Обе даты относятся к 21-му веку (т.е. 2011 и 2030 годы), но сохраняются только последние два символа.
Почему следующий оператор (при запуске из модуля PL/SQL) для вышеуказанных данных всегда возвращает положительное значение
dateDifference := (fromDate - toDate)
Если я запускаю следующий оператор из sqlplus, я получаю правильное отрицательное значение, которое является правильным.
select to_date('20JAN11','DDMONYY')-to_Date('29DEC30','DDMONYY') from dual;
Я помню, как читал где-то, что Oracle иногда использовал не тот век, но я не совсем помню точный сценарий, где это могло бы произойти.
3 ответа
Предполагая, что эти столбцы имеют DATE
тип данных, который, кажется, имеет место: Oracle всегда хранит DATE
значения во внутреннем формате, который включает в себя полный год. Тот факт, что вы видите только двухзначный год, связан с форматом даты, используемым для преобразования даты в строку для отображения. Поэтому, скорее всего, сохраненные значения века не соответствуют вашим ожиданиям.
Попробуйте выбрать даты в явном формате, чтобы увидеть, что вы действительно сохранили:
SELECT TO_CHAR( fromDate, 'DD-MON-YYYY' ), TO_CHAR( toDate, 'DD-MON-YYYY' )
Работает без форматирования
CREATE TABLE DATETEST(FROMDATE DATE, TODATE DATE);
insert into DATETEST (fromdate,todate) values (to_date('20Jan11','ddMonrr'),to_date('29DEC30','ddMonrr'));
SELECT TO_CHAR(FROMDATE,'ddMonrrrr hh24:mi:ss') FROMDATE,
TO_CHAR(TODATE,'ddMonrrrr hh24:mi:ss') TODATE
from datetest ;
/*
FROMDATE TODATE
------------------ ------------------
20Jan2011 00:00:00 29Dec2030 00:00:00
*/
set serveroutput on
DECLARE
l_FROMDATE DATETEST.FROMDATE%type ;
L_TODATE DATETEST.TODATE%TYPE;
dateDifference number;
BEGIN
--notice -- no formatting just putting them into a variable for test
SELECT FROMDATE, TODATE
INTO L_FROMDATE, L_TODATE
from datetest;
DATEDIFFERENCE := L_FROMDATE - L_TODATE ;
DBMS_OUTPUT.PUT_LINE('DATEDIFFERENCE = ' || DATEDIFFERENCE );
end ;
--DATEDIFFERENCE = -7283
SELECT FROMDATE-TODATE
from datetest ;
/* --still not formatting
FROMDATE-TODATE
----------------------
-7283
*/
SELECT (FROMDATE - TODATE) DATEDIFF,
TO_CHAR(FROMDATE,'ddMonrrrr') FROMDATE,
to_char(todate,'ddMonrrrr') todate
from (
SELECT TO_DATE('20JAN11','DDMONYY') FROMDATE,
TO_DATE('29DEC30','DDMONYY') TODATE
FROM DUAL)
;
/*
DATEDIFF FROMDATE TODATE
---------------------- --------- ---------
-7283 20Jan2011 29Dec2030
*/
попробуйте выполнить первый запрос к вашей таблице:
SELECT TO_CHAR(FROMDATE,'ddMonrrrr hh24:mi:ss') FROMDATE,
TO_CHAR(TODATE,'ddMonrrrr hh24:mi:ss') TODATE
from datetest ;
Посмотрим, действительно ли годы - это то, что вы ожидаете.
(Изменить: изменено для использования двухзначных лет)
Кажется, работает для меня в любом случае на моей базе данных 10g:
SQL> set serveroutput on
SQL>
SQL> DECLARE
2 d1 DATE := to_date('20JAN11','DDMONRR');
3 d2 DATE := to_date('29DEC30','DDMONRR');
4 diff INTEGER;
5 BEGIN
6 diff := d1 - d2;
7 dbms_output.put_line(diff);
8 END;
9 /
-7283
PL/SQL procedure successfully completed
SQL>
РЕДАКТИРОВАТЬ: работает для YY вместо формата года RR также.
РЕДАКТИРОВАТЬ 2: Что-то вроде этого, вы имеете в виду?
SQL> create table t (d1 date, d2 date);
Table created
SQL> insert into t values (to_date('20JAN11','DDMONYY'), to_date('29DEC30','DDMONYY'));
1 row inserted
SQL> commit;
Commit complete
SQL>
SQL> DECLARE
2 R t%ROWTYPE;
3 diff INTEGER;
4 BEGIN
5 SELECT d1, d2
6 INTO R
7 FROM t;
8 diff := R.d1 - R.d2;
9 dbms_output.put_line(diff);
10 END;
11 /
-7283
PL/SQL procedure successfully completed
SQL>
Как утверждает @Alex, вы можете проверить свои данные.