Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Oracle Новый топик    Ответить
 работа с датами до наше эры  [new]
ag_smith
Member

Откуда:
Сообщений: 4
добрый день, коллеги
помогите разобраться. Есть такой запрос, цель которого, вывести даты и соответствующие дни заданного интервала. Но, необходимо чтобы он работал с датами до нашей эры. Я пытаюсь внешним запросом убрать все даты нулевого года (которого быть не должно), но запрос ничего не выводит. Например, если ввести: 1) 28-12-0001 BC 2) 02-01-0001 AD
По идее должно выводиться 6 записей, с 28.12 по 02.01
Вот сам запрос

undefine start
undefine finish

select *
from(select to_char(to_date('&&start', 'dd-mm-yyyy BC', 'nls_date_language=english') + rownum - 1, 'dd.mm.yyyy BC') my_date, to_char(to_date('&start', 'dd-mm-yyyy BC', 'nls_date_language=english') + rownum - 1, 'Day') my_day
from (select 1, 2, 3 from dual group by cube(1,1,1,1,1,1,1,1,1,1))
where to_date('&start', 'dd-mm-yyyy BC', 'nls_date_language=english') + rownum - 2 < to_date('&&finish', 'dd-mm-yyyy BC', 'nls_date_language=english')) d
where
to_char(to_date(d.my_date, 'dd.mm.yyyy BC', 'nls_date_language=english')) <= to_date('31.12.0001 BC', 'dd.mm.yyyy BC', 'nls_date_language=english')
and to_char(to_date(d.my_date, 'dd.mm.yyyy BC', 'nls_date_language=english')) >= to_date('01.01.0001 AD', 'dd.mm.yyyy BC', 'nls_date_language=english');
9 июн 19, 23:40    [21905571]     Ответить | Цитировать Сообщить модератору
 Re: работа с датами до наше эры  [new]
Щукина Анна
Member

Откуда:
Сообщений: 1422
ag_smith,

если сравнивать теплое с мягким, то, скорее всего, ничего и не получится... Вы уж или все даты в строки приводите и сравнивайте между собой строки . Или наоборот - все строки переводите в дату и сравнивайте между собой даты.
А так намешали одно с другим, сдобрили всё это неявным преобразованием типов и удивляетесь полученному результату.
10 июн 19, 04:27    [21905604]     Ответить | Цитировать Сообщить модератору
 Re: работа с датами до наше эры  [new]
-2-
Member

Откуда:
Сообщений: 14850
С сотворением нашей эры не все так однозначно
with t1 as (select date '-1-12-31' d from dual)
select '+366+1' "до н.э.", d+366+1 d from t1
union all select '+1+366', d+1+366 from t1
union all select '+367', d+367 from t1;

до н.э D          
------ -----------
+366+1  0002-01-01
+1+366  0002-01-02
+367    0001-01-01
10 июн 19, 09:02    [21905662]     Ответить | Цитировать Сообщить модератору
 Re: работа с датами до наше эры  [new]
SQL*Plus
Member

Откуда: Россия, Москва
Сообщений: 7880
-2-
С сотворением нашей эры не все так однозначно
with t1 as (select date '-1-12-31' d from dual)
select '+366+1' "до н.э.", d+366+1 d from t1
union all select '+1+366', d+1+366 from t1
union all select '+367', d+367 from t1;

до н.э D          
------ -----------
+366+1  0002-01-01
+1+366  0002-01-02
+367    0001-01-01

В Oracle Database 19.2 та же картина:
with t1 as (select TO_date('-0001.12.31', 'SYYYY.MM.DD') AS d from dual)
--
, T AS (
select ' ' AS add_days, d from t1
union all select '+0', d+0 from t1
union all select '-0', d-0 from t1
union all select '+1', d+1 from t1
union all select '+366', d+366 from t1
union all select '+367', d+367 from t1
union all select '+1+366', d+1+366 from t1
union all select '+366+1' , d+366+1 d from t1)
--
SELECT add_days, TO_CHAR(d, 'DD.MM.YYYY B.C.') AS dd_mm_yyyy_BC FROM t;

ADD_DA DD_MM_YYYY_BC  
------ ---------------
       31.12.0001 B.C.
+0     31.12.0001 B.C.
-0     31.12.0001 B.C.
+1     01.01.0001 A.D.
+366   31.12.0001 A.D.
+367   01.01.0001 A.D.
+1+366 02.01.0002 A.D.
+366+1 01.01.0002 A.D.

8 rows selected. 
10 июн 19, 13:10    [21905885]     Ответить | Цитировать Сообщить модератору
 Re: работа с датами до наше эры  [new]
ag_smith
Member

Откуда:
Сообщений: 4
на всякий случай, ниже привожу работающий вариант, если вдруг кто-то столкнется с такой же задачкой

undefine start
undefine finish

select *
from(select to_date('&&start', 'dd-mm-yyyy BC', 'nls_date_language=english') + rownum - 1 my_date, to_char(to_date('&start', 'dd-mm-yyyy BC', 'nls_date_language=english') + rownum - 1, 'Day') my_day
from (select 1, 2, 3 from dual group by cube(1,1,1,1,1,1,1,1,1,1))
where to_date('&start', 'dd-mm-yyyy BC', 'nls_date_language=english') + rownum - 2 < to_date('&&finish', 'dd-mm-yyyy BC', 'nls_date_language=english')) d
where
d.my_date <= to_date('31.12.0001 BC', 'dd.mm.yyyy BC', 'nls_date_language=english')
or d.my_date >= to_date('01.01.0001 AD', 'dd.mm.yyyy BC', 'nls_date_language=english');


коллеги, еще вопрос по этому коду. как организовать защиту от выхода за максимальный интервал oracle, то есть, если одна из дат (start / finish), или обе, введены больше 29.12.9999 AD, то чтобы они приравнивались 29.12.9999 AD? В sql я не силен)
10 июн 19, 14:29    [21905951]     Ответить | Цитировать Сообщить модератору
 Re: работа с датами до наше эры  [new]
SQL*Plus
Member

Откуда: Россия, Москва
Сообщений: 7880
 -- Выполнено на Oracle Database 19.2

ADD_DA DD_MM_YYYY_BC  
------ ---------------
       31.12.0001 B.C.
+0     31.12.0001 B.C.
-0     31.12.0001 B.C.
+1     01.01.0001 A.D.
+366   31.12.0001 A.D.
+367   01.01.0001 A.D.
+1+366 02.01.0002 A.D.
+366+1 01.01.0002 A.D.
Неправильные результаты.
WITH T AS (SELECT TO_DATE('31.12.-0001', 'DD.MM.SYYYY') as d FROM DUAL)
---
          SELECT TO_CHAR(d, 'DD.MM.SYYYY A.D.') AS res FROM t
UNION ALL SELECT TO_CHAR(d+(366), 'DD.MM.SYYYY A.D.') FROM t
UNION ALL SELECT TO_CHAR(d+(366+365), 'DD.MM.SYYYY A.D.') FROM t
UNION ALL SELECT TO_CHAR(d+(366+365+365), 'DD.MM.SYYYY A.D.') FROM t
UNION ALL SELECT TO_CHAR(d+(366+365+365+365), 'DD.MM.SYYYY A.D.') FROM t
UNION ALL SELECT TO_CHAR(d+(366+365+365+365+366), 'DD.MM.SYYYY A.D.') FROM t;

RES
----------------
31.12.-0001 B.C.
31.12. 0001 A.D.
31.12. 0001 A.D.
31.12. 0002 A.D.
31.12. 0003 A.D.
31.12. 0004 A.D.

Здесь регулярно теряется один год.

Нужно заводить Service Request на сайте My Oracle Support (MOS)...

Проверьте, пожалуйста, что получается на менее свежих версиях базы.
10 июн 19, 14:55    [21905977]     Ответить | Цитировать Сообщить модератору
 Re: работа с датами до наше эры  [new]
SQL*Plus
Member

Откуда: Россия, Москва
Сообщений: 7880
ag_smith
на всякий случай, ниже привожу работающий вариант, если вдруг кто-то столкнется с такой же задачкой
undefine start
undefine finish

select *
from(select to_date('&&start', 'dd-mm-yyyy BC', 'nls_date_language=english') + rownum - 1 my_date
          , to_char(to_date('&start', 'dd-mm-yyyy BC', 'nls_date_language=english') + rownum - 1, 'Day') my_day
from (select 1, 2, 3 from dual group by cube(1,1,1,1,1,1,1,1,1,1))
where to_date('&start', 'dd-mm-yyyy BC', 'nls_date_language=english') 
              + rownum - 2 < to_date('&&finish', 'dd-mm-yyyy BC', 'nls_date_language=english')) d
where 
d.my_date <= to_date('31.12.0001 BC', 'dd.mm.yyyy BC', 'nls_date_language=english')
or d.my_date >= to_date('01.01.0001 AD', 'dd.mm.yyyy BC', 'nls_date_language=english');


коллеги, еще вопрос по этому коду. как организовать защиту от выхода за максимальный интервал oracle, то есть, если одна из дат (start / finish), или обе, введены больше 29.12.9999 AD, то чтобы они приравнивались 29.12.9999 AD? В sql я не силен)
При оформлении кода используйте, пожалуйста, тэг SRC данного форума.
10 июн 19, 15:06    [21905984]     Ответить | Цитировать Сообщить модератору
 Re: работа с датами до наше эры  [new]
Elic
Member

Откуда: 1984. Выбраковка финно-угром продолжается. КЯЗ
Сообщений: 29197
SQL*Plus
Нужно заводить Service Request на сайте My Oracle Support (MOS)...

Проверьте, пожалуйста, что получается на менее свежих версиях базы.
Oracle Database 12c. Новые (/старые) грабли языка SQL
Нулевой год был високосным!
Bug с переходом через начало эры
10 июн 19, 15:53    [21906013]     Ответить | Цитировать Сообщить модератору
 Re: работа с датами до наше эры  [new]
SY
Member

Откуда: Middlebury, CT USA
Сообщений: 9563
SQL*Plus
Здесь регулярно теряется один год.

Нужно заводить Service Request на сайте My Oracle Support (MOS)...


И получишь иезуитский ответ date arithmetic используeт астрономическое нумерование годов .

SY.
10 июн 19, 16:01    [21906021]     Ответить | Цитировать Сообщить модератору
 Re: работа с датами до наше эры  [new]
-2-
Member

Откуда:
Сообщений: 14850
SQL*Plus
Проверьте, пожалуйста, что получается на менее свежих версиях базы.
Отродясь так было и менять вряд решатся - могут быть системы, завязанные на юлианское число с лишними 366 днями с -4712.
Предполагаю алгоритм: в арифметике участвует нулевой високосный год. Если в результате операции получается нулевой год, берется следующий год. Если после этого получается несуществующий день 29 февраля плюс-первого года, берется 1 марта. Таким образом, 365 дней нулевого года дублируется на первый год, а первое марта троируется. Разный порядок суммирования с числами менее 60 и более дает разный результат. В обратном направлении нулевой год переводится в минус-первый, но проверка на 29 февраля не делается и поведение несколько иное:
select to_char(date '1-1-1' - 307, 'syyyy-mm-dd') zeroad from dual;

ZEROAD     
-----------
00000-00-00

При этом арифметика с другим несуществующим интервалом дат отрабатывает корректно.
10 июн 19, 16:10    [21906028]     Ответить | Цитировать Сообщить модератору
 Re: работа с датами до наше эры  [new]
SQL*Plus
Member

Откуда: Россия, Москва
Сообщений: 7880
-2-
При этом арифметика с другим несуществующим интервалом дат отрабатывает корректно.


Вы же про этот несуществующий интервал!?
https://ru.wikipedia.org/wiki/Григорианский_календарь
Впервые григорианский календарь был введён папой римским Григорием XIII
в католических странах 4 октября 1582 года взамен прежнего юлианского:
следующим днём после четверга 4 октября стала пятница 15 октября.

SQL> WITH T AS (
  2  Select level as id, DATE '1582-10-01'+level-1 AS d
  3  FROM dual connect by level <= 7)
  4  --
  5  SELECT B.d AS b_d
  6       , A.d AS A_d
  7       , B.d - A.d AS days_between
  8  FROM T A, T B
  9  WHERE B.id = A.id + 1;

B_D         A_D         DAYS_BETWEEN
----------- ----------- ------------
02-OCT-1582 01-OCT-1582            1
03-OCT-1582 02-OCT-1582            1
04-OCT-1582 03-OCT-1582            1
15-OCT-1582 04-OCT-1582            1  
16-OCT-1582 15-OCT-1582            1
17-OCT-1582 16-OCT-1582            1

Ну так смогли же сделать!

Отчего бы не "допилить" тот интервал, который мы здесь обсуждаем?!
10 июн 19, 18:04    [21906115]     Ответить | Цитировать Сообщить модератору
 Re: работа с датами до наше эры  [new]
SY
Member

Откуда: Middlebury, CT USA
Сообщений: 9563
SQL*Plus
Отчего бы не "допилить" тот интервал, который мы здесь обсуждаем?!


Ну мы то за, осталось самая малость - убедить Oracle . Правда последние так лет 25 они упорно твердят - not a bug.

SQL*Plus
Ну так смогли же сделать!


Cделали да не доделали. Вводился Грегорианский каледарь в разных странах в разное время. Посему наример в java есть setGregorianChange. А в Oracle только 15 Октября 1582. Так-что работая например с российскими датaми (15 Января 1918) и с ангийскими (14 Сентября 1752) и кучей других стран обломс.

SY.
10 июн 19, 19:17    [21906158]     Ответить | Цитировать Сообщить модератору
Все форумы / Oracle Ответить