Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Oracle Новый топик    Ответить
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
 Помогите с запросом. Количество-во 29 февраля между 2 датами  [new]
alf19
Member

Откуда: Киев
Сообщений: 70
Помогите написать запрос для опредения количества 29-х февраля между двумя датами
2 мар 07, 14:08    [3853901]     Ответить | Цитировать Сообщить модератору
 Re: Помогите с запросом. Количество-во 29 февраля между 2 датами  [new]
яп пошел
Guest
год делится нацело на четыре?
2 мар 07, 14:23    [3854049]     Ответить | Цитировать Сообщить модератору
 Re: Помогите с запросом. Количество-во 29 февраля между 2 датами  [new]
dmidek
Member

Откуда: Киев - Дортмунд
Сообщений: 116208
В лоб через pivot

SQL> with dates
  2  as
  3  (select to_date('03-04-2003', 'DD-MM-YYYY') start_date,
  4          to_date('03-04-2023', 'DD-MM-YYYY') end_date  from dual)
  5  select count(*)
  6    from (select start_date + level - 1 dates
  7            from dates
  8          connect by start_date + level <= end_date)
  9   where to_char(dates, 'DDMM') = '2902'
 10  /

  COUNT(*)
----------
         5

SQL> 
2 мар 07, 14:24    [3854056]     Ответить | Цитировать Сообщить модератору
 Re: Помогите с запросом. Количество-во 29 февраля между 2 датами  [new]
Bogdanov Andrey
Member

Откуда: Да уже и сам не знаю...
Сообщений: 2203
alf19
Помогите написать запрос для опредения количества 29-х февраля между двумя датами


select sum(decode(to_char(to_date('28.02.'||(to_char(sysdate,'YYYY')+D.N),
                                  'DD.MM.YYYY')+1,'DD.MM'),
                  '29.02',1,
                  0))
  from (select rownum N from dual
        connect by level < months_between(sysdate + 5000, sysdate)/12+1) D;
2 мар 07, 14:30    [3854107]     Ответить | Цитировать Сообщить модератору
 Re: Помогите с запросом. Количество-во 29 февраля между 2 датами  [new]
orawish
Member

Откуда: Гадюкино-2 (City)
Сообщений: 15487
with t as (select sysdate d1, sysdate + 10000 d2 from dual)
,t2 as (select t.*,trunc(d1,'y') y1,trunc(d2,'y') y2 from t)
,t3 as (select d1,d2,y1,y2,last_day(add_months(y1,(level-1)*12+1)) dd  from t2
connect by level*12 <= months_between(y2,y1)+12)
select count(*) from t3 where d1 <= dd and dd <= d2 and extract(day from dd)=29
2 мар 07, 14:34    [3854139]     Ответить | Цитировать Сообщить модератору
 Re: мой монстрик:)  [new]
ГостЪ
Guest
with tab as (select to_date('29-03-2000', 'DD-MM-YYYY') dt1, to_date('29-03-8000', 'DD-MM-YYYY') dt2 from dual)
select Sm
     + case
         when mod(Extract(year from Dt1), 4) = 0 and
              (mod(Extract(year from Dt1), 25) != 0 or
               mod(Extract(year from Dt1), 16) = 0) and
              (Extract(month from Dt1) <= 2) then
          1 else 0 end 
      + case
         when mod(Extract(year from Dt2), 4) = 0 and
              (mod(Extract(year from Dt2), 25) != 0 or
               mod(Extract(year from Dt2), 16) = 0) and
              (Extract(month from Dt2) > 2 or
               Extract(month from Dt2) = 2 and Extract(day from Dt2) = 1) then
          1 else 0 end
  from tab
       ,(select sum(case when mod(Yr, 4) = 0 and
                          (mod(Yr, 25) != 0 or mod(Yr, 16) = 0) then
                      1  else 0 end) Sm
          from (select Extract(year from Add_Months(Dt1, 12 * level)) Yr
                  from Tab
                connect by Trunc(Add_Months(Dt1, 12 * (level - 1)), 'y') < Trunc(Dt2, 'y')))
2 мар 07, 14:46    [3854259]     Ответить | Цитировать Сообщить модератору
 Re: Помогите с запросом. Количество-во 29 февраля между 2 датами  [new]
Bogdanov Andrey
Member

Откуда: Да уже и сам не знаю...
Сообщений: 2203
dmidek
В лоб через pivot
[/src]

Самый наглядный способ, но довольно медленный.
2 мар 07, 14:47    [3854272]     Ответить | Цитировать Сообщить модератору
 Re: мой монстрик:)  [new]
Bogdanov Andrey
Member

Откуда: Да уже и сам не знаю...
Сообщений: 2203
ГостЪ
with tab as (select to_date('29-03-2000', 'DD-MM-YYYY') dt1, to_date('29-03-8000', 'DD-MM-YYYY') dt2 from dual)
select Sm
     + case
...


А этот дает неверную цифирку.
2 мар 07, 14:50    [3854295]     Ответить | Цитировать Сообщить модератору
 Re: мой монстрик:)  [new]
ГостЪ
Guest
Bogdanov Andrey
ГостЪ
with tab as (select to_date('29-03-2000', 'DD-MM-YYYY') dt1, to_date('29-03-8000', 'DD-MM-YYYY') dt2 from dual)
select Sm
     + case
...


А этот дает неверную цифирку.


это у тебя не верная цифра, детка:)

select sum(decode(to_char(to_date('28.02.'||(to_char(to_date('28-02-2000', 'DD-MM-YYYY'),'YYYY')+D.N),
                                  'DD.MM.YYYY')+1,'DD.MM'),
                  '29.02',1,
                  0))
  from (select rownum N from dual
        connect by level < months_between(to_date('28-02-2000', 'DD-MM-YYYY'), to_date('28-02-2001', 'DD-MM-YYYY'))/12+1) D;
2 мар 07, 14:54    [3854320]     Ответить | Цитировать Сообщить модератору
 Re: Помогите с запросом. Количество-во 29 февраля между 2 датами  [new]
orawish
Member

Откуда: Гадюкино-2 (City)
Сообщений: 15487
Bogdanov Andrey
dmidek
В лоб через pivot
[/src]

Самый наглядный способ, но довольно медленный.

+1

Присоединен к:
Oracle9i Enterprise Edition Release 9.2.0.7.0 - 64bit Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.7.0 - Production

SQL> set timing on
SQL> with t as (select to_date('01.01.0001','dd.mm.yyyy') d1,
  2                    to_date('01.03.9999','dd.mm.yyyy') d2 from dual)
  3  select sum(case to_char(d1+level,'mmdd') when '0229' then 1 end) c
  4  from t connect by level < d2-d1;

         C
----------
      2436

Затрач.время: 00:00:27.10
SQL> ;
  1  with t as (select to_date('01.01.0001','dd.mm.yyyy') d1,
  2                    to_date('01.03.9999','dd.mm.yyyy') d2 from dual)
  3  select sum(case to_char(d1+level,'mmdd') when '0229' then 1 end) c
  4* from t connect by level < d2-d1
SQL> with t as (select to_date('01.01.0001','dd.mm.yyyy') d1,
  2                    to_date('01.03.9999','dd.mm.yyyy') d2 from dual)
  3  ,t2 as (select t.*,trunc(d1,'y') y1,trunc(d2,'y') y2 from t)
  4  ,t3 as (select d1,d2,y1,y2,last_day(add_months(y1,(level-1)*12+1)) dd  from t2
  5  connect by level*12 <= months_between(y2,y1)+12)
  6  select count(*) from t3 where d1 <= dd and dd <= d2 and extract(day from dd)=29;

  COUNT(*)
----------
      2436

Затрач.время: 00:00:00.14
2 мар 07, 14:57    [3854348]     Ответить | Цитировать Сообщить модератору
 Re: Помогите с запросом. Количество-во 29 февраля между 2 датами  [new]
dmidek
Member

Откуда: Киев - Дортмунд
Сообщений: 116208
Bogdanov Andrey
dmidek
В лоб через pivot
[/src]

Самый наглядный способ, но довольно медленный.


Не то, чтобы я возражал, но если уж Вы "по гамбургскому счету"

select sum(decode(to_char(to_date('28.02.'||(to_char(sysdate,'YYYY')+D.N),
                                  'DD.MM.YYYY')+1,'DD.MM'),
                  '29.02',1,
                  0))
  from (select rownum N from dual
        connect by level < months_between(sysdate + 1, sysdate)/12+1) D;
/
1
2 мар 07, 14:58    [3854360]     Ответить | Цитировать Сообщить модератору
 Re: мой монстрик:)  [new]
Stax.
Guest
ГостЪ

...
select to_date('25-01-2000', 'dd-mm-yyyy') dt1, to_date('28-01-2000', 'DD-MM-YYYY') dt2 from dual)
...


=1 ?
......
stax
2 мар 07, 14:58    [3854368]     Ответить | Цитировать Сообщить модератору
 Re: мой монстрик:)  [new]
ГостЪ
Guest
Stax.
ГостЪ

...
select to_date('25-01-2000', 'dd-mm-yyyy') dt1, to_date('28-01-2000', 'DD-MM-YYYY') dt2 from dual)
...


=1 ?
......
stax

не буду переписывать:)
2 мар 07, 15:04    [3854422]     Ответить | Цитировать Сообщить модератору
 Re: мой монстрик:)  [new]
Bogdanov Andrey
Member

Откуда: Да уже и сам не знаю...
Сообщений: 2203
ГостЪ

это у тебя не верная цифра, детка:)


Ну возрастом мы мерятся не будем. А вот то, что в 2000 году было только одно 29-ое февраля - я уверен. Ваш же запрос возавращает 2.
Учите матчасть.
2 мар 07, 15:16    [3854553]     Ответить | Цитировать Сообщить модератору
 Re: Помогите с запросом. Количество-во 29 февраля между 2 датами  [new]
Andrew Max
Member

Откуда:
Сообщений: 1045
Попытка №1. Без использования PIVOT-ов, CONNECT BY и т.д.

SQL> var date1 varchar2(10)
SQL> var date2 varchar2(10)
SQL>
SQL> exec :date1 := '28.02.1996'; :date2 := '31.03.2012'

Процедура PL/SQL успешно завершена.

SQL> select case when d1 > d2
  2              then 0
  3              else td2 - td1 -
  4                   (to_number(to_char(td2, 'YYYY')) - to_number(to_char(td1, 'YYYY')))*365 +
  5                   case when to_number(to_char(d1, 'MM')) > 2
  6                         and to_char(last_day(to_date('01.02.' || to_char(td1, 'YYYY'), 'DD.MM.YYYY')), 'DD') = '29'
  7                        then -1
  8                        else 0
  9                   end +
 10                   case when to_number(to_char(d2, 'MM')) > 2
 11                         and to_char(last_day(to_date('01.02.' || to_char(td2, 'YYYY'), 'DD.MM.YYYY')), 'DD') = '29'
 12                          or to_char(d2, 'DDMM') = '2902'
 13                        then 1
 14                        else 0
 15                   end
 16         end cnt2902
 17    from (select d1, d2, trunc(d1, 'YYYY') td1, trunc(d2, 'YYYY') td2
 18            from (select trunc(to_date(:date1, 'DD.MM.YYYY')) d1,
 19                         trunc(to_date(:date2, 'DD.MM.YYYY')) d2
 20                    from dual));

   CNT2902
----------
         5

SQL>

PS: Возможно, сыро. Подумаю еще...
2 мар 07, 15:24    [3854606]     Ответить | Цитировать Сообщить модератору
 Re: Помогите с запросом. Количество-во 29 февраля между 2 датами  [new]
dmidek
Member

Откуда: Киев - Дортмунд
Сообщений: 116208
Bogdanov Andrey
dmidek
В лоб через pivot
[/src]

Самый наглядный способ, но довольно медленный.


Ну что же, чуть чуть ускорить наверное можно :-)

SQL> with dates
  2  as
  3  (select to_date('03-04-2003', 'DD-MM-YYYY') start_date,
  4          to_date('03-04-2008', 'DD-MM-YYYY') end_date  from dual)
  5  select count(decode(to_char(start_date + level - 1,'DDMM'),'2902',1)) dates
  6            from dates
  7          connect by start_date + level <= end_date
  8  /

     DATES
----------
         2

SQL> 
2 мар 07, 15:25    [3854612]     Ответить | Цитировать Сообщить модератору
 Re: Помогите с запросом. Количество-во 29 февраля между 2 датами  [new]
ORA-01403
Member

Откуда: Москва
Сообщений: 60
Еще вариант для любителей изващений:

with dates as
    (select to_date('03-04-0001', 'DD-MM-YYYY') start_date,
              to_date('03-04-9999', 'DD-MM-YYYY') end_date from dual)
select count(1) from
(select level + extract(year from start_date)-1 as yr
   from dates
   where  (to_char(start_date,'MMDD') < '0229' OR level != 1)
      AND (to_char(end_date,'MMDD') > '0229' OR level <=  extract(year from end_date) - extract(year from start_date))
 connect by level <= extract(year from end_date) - extract(year from start_date) + 1) pivot
where bitand(yr, 3) = 0 and ((round(yr/100) != yr/100 OR round(yr/400) = yr/400) OR yr < 1582)
2 мар 07, 15:28    [3854650]     Ответить | Цитировать Сообщить модератору
 Re: мой монстрик:)  [new]
ГостЪ
Guest
Bogdanov Andrey
ГостЪ

это у тебя не верная цифра, детка:)


Ну возрастом мы мерятся не будем. А вот то, что в 2000 году было только одно 29-ое февраля - я уверен. Ваш же запрос возавращает 2.
Учите матчасть.


По следам Станислава ты идёшь очень медленно. Я уже признал эту ошибку.
2 мар 07, 15:35    [3854711]     Ответить | Цитировать Сообщить модератору
 Re: Помогите с запросом. Количество-во 29 февраля между 2 датами  [new]
alf19
Member

Откуда: Киев
Сообщений: 70
Всем огромное СПАСИБО!!!
2 мар 07, 16:18    [3855077]     Ответить | Цитировать Сообщить модератору
 Re: Помогите с запросом. Количество-во 29 февраля между 2 датами  [new]
orawish
Member

Откуда: Гадюкино-2 (City)
Сообщений: 15487
Вот - залудил совместимо с (< ?) = 8
 select dd2-dd1-365*(to_char(dd2,'yyyy')-to_char(dd1,'yyyy')) d 
   from (select 
           decode(sign(to_number(to_char(d1,'mm.dd'))-2.29)
                 ,-1 , to_date('28.02.'||to_char(d1,'yyyy'),'dd.mm.yyyy')
                 , 0 , to_date('28.02.'||to_char(d1,'yyyy'),'dd.mm.yyyy')
                 , 1 , last_day(add_months(trunc(d1,'yyyy'),1))
                 ) dd1
           ,decode(sign(to_number(to_char(d2,'mm.dd'))-2.29)
                 ,-1 , to_date('28.02.'||to_char(d2,'yyyy'),'dd.mm.yyyy')
                 , 0 , last_day(add_months(trunc(d2,'yyyy'),1))
                 , 1 , last_day(add_months(trunc(d2,'yyyy'),1))
                 ) dd2
         from (select to_date('01.01.0001','dd.mm.yyyy') d1, 
                      to_date('01.03.9999','dd.mm.yyyy') d2 from dual)
);
Но радовался недолго - результат то не сходится на десяточку с ап..
Начал рыть - и нарыл (ёшкин гребень ихим девелоперам через анус в гланды)

SQL> with t as (
  2  select to_date('01.01.1560','dd.mm.yyyy') d1
  3        ,to_date('01.01.1599','dd.mm.yyyy') d2 from dual
  4  ) select (d2-d1)/365 y,mod(d2-d1,365) m from t;

         Y          M
---------- ----------
        39          0

Ну (типа), НЕ БЫЛО ВИСОКОСНЫХ ЛЕТ, пол-шестнадцатого века. Корова сожрала.
Это на 9.2.0.7, но что-то мне подсказывает, что не только..
2 мар 07, 16:49    [3855338]     Ответить | Цитировать Сообщить модератору
 Re: Помогите с запросом. Количество-во 29 февраля между 2 датами  [new]
ORA-01403
Member

Откуда: Москва
Сообщений: 60
orawish
Ну (типа), НЕ БЫЛО ВИСОКОСНЫХ ЛЕТ, пол-шестнадцатого века. Корова сожрала.
Это на 9.2.0.7, но что-то мне подсказывает, что не только..


Если быть точным, то в 1582 году поменяли признак високосности :). А вот что намудрили в Oracle по этому поводу - х.з. )))
2 мар 07, 16:53    [3855385]     Ответить | Цитировать Сообщить модератору
 Re: Помогите с запросом. Количество-во 29 февраля между 2 датами  [new]
orawish
Member

Откуда: Гадюкино-2 (City)
Сообщений: 15487
ORA-01403
orawish
Ну (типа), НЕ БЫЛО ВИСОКОСНЫХ ЛЕТ, пол-шестнадцатого века. Корова сожрала.
Это на 9.2.0.7, но что-то мне подсказывает, что не только..


Если быть точным, то в 1582 году поменяли признак високосности :). А вот что намудрили в Oracle по этому поводу - х.з. )))
Ну я же и говорю - намутили 10 лет содержащих 29 февраля, но длиной по 365 дней.
2 мар 07, 16:56    [3855420]     Ответить | Цитировать Сообщить модератору
 Re: Помогите с запросом. Количество-во 29 февраля между 2 датами  [new]
Andrew Max
Member

Откуда:
Сообщений: 1045
orawish
Начал рыть - и нарыл (<censored> ихим девелоперам <censored>) ...

Ну (типа), НЕ БЫЛО ВИСОКОСНЫХ ЛЕТ, пол-шестнадцатого века.
...

SQL> var date1 varchar2(10)
SQL> var date2 varchar2(10)
SQL>
SQL> exec :date1 := '01.01.1560'; :date2 := '01.01.1599'

Процедура PL/SQL успешно завершена.

SQL>
SQL> select (to_date(:date2, 'DD.MM.YYYY') - to_date(:date1, 'DD.MM.YYYY'))/365 years1,
  2         to_number(to_char(to_date(:date2, 'DD.MM.YYYY'), 'YYYY')) -
  3         to_number(to_char(to_date(:date1, 'DD.MM.YYYY'), 'YYYY')) years2 from dual;

    YEARS1     YEARS2
---------- ----------
        39         39

SQL> select * from v$version where rownum = 1;

BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.1.0.4.0 - Prod

SQL>

Мда...
Вот что значит темное средневековье...
2 мар 07, 17:15    [3855561]     Ответить | Цитировать Сообщить модератору
 Re: Помогите с запросом. Количество-во 29 февраля между 2 датами  [new]
ORA-01403
Member

Откуда: Москва
Сообщений: 60
orawish
Ну я же и говорю - намутили 10 лет содержащих 29 февраля, но длиной по 365 дней.


Нее... там все хитрее... в 1582 году было не 365, а 355 дней :), как Папа Римский в свое время и распорядился. Так что все нормально.

SQL>  select to_date('01.01.1583', 'DD.MM.YYYY') - to_date('01.01.1582', 'DD.MM.YYYY') from dual
  2  /

TO_DATE('01.01.1583','DD.MM.YYYY')-TO_DATE('01.01.1582','DD.MM.YYYY')
---------------------------------------------------------------------
                                                                  355
2 мар 07, 17:15    [3855562]     Ответить | Цитировать Сообщить модератору
 Re: Помогите с запросом. Количество-во 29 февраля между 2 датами  [new]
orawish
Member

Откуда: Гадюкино-2 (City)
Сообщений: 15487
ORA-01403
orawish
Ну я же и говорю - намутили 10 лет содержащих 29 февраля, но длиной по 365 дней.


Нее... там все хитрее... в 1582 году было не 365, а 355 дней :), как Папа Римский в свое время и распорядился. Так что все нормально.

SQL>  select to_date('01.01.1583', 'DD.MM.YYYY') - to_date('01.01.1582', 'DD.MM.YYYY') from dual
  2  /

TO_DATE('01.01.1583','DD.MM.YYYY')-TO_DATE('01.01.1582','DD.MM.YYYY')
---------------------------------------------------------------------
                                                                  355

Нормально - я бы не сказал.. Скорее - весело
SQL> select to_char(to_date('31.12.1582','dd.mm.yyyy'),'ddd') ddd from dual;

DDD
---
365
2 мар 07, 17:23    [3855639]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
Все форумы / Oracle Ответить