Laiko rėžis datos rėžio oracle užklausoje

sql_date_time

Laikas nuo laiko tenka ištraukti tam tikrų valandų kelių dienų duomenis, pav. gauti duomenis už praėjusio mėnesio kiekvieną dieną 08:00–09:00 valandomis. Kartais pasitaiko tai įdomesni poreikiai, pav. gauti tam tikro laiko intervalo duomenis tik savaitgaliais arba tik konkrečią dieną (pav. tik antradieniais ir pan.). Užduotis paprasta, bet dėl to, kad tai daryti tenka ne dažnai, vis pamirštu konkrečia sintaksę. Tenka pasikelti senus failus, juose ieškoti konkretaus sprendimo. Taip daryti nusibodo ir nusprendžiau savo naudojamą techniką aprašyti čia. Gal kam nors irgi pravers…

Tarkim, turim lentelę t, kurioje yra saugomi maždaug mėnesio date tipo įrašai, kas 15 minučių. Pasibandymui (pav. ant sqlfiddle.com) tokią lentelę galit pasigaminti taip:

create table t
(id number, DT date);

insert into t (id, DT)
SELECT
rownum as id
,TO_DATE('2014-08-01', 'yyyy-mm-dd') + (rownum-1)*(15/24/60) AS DT
FROM dual
CONNECT BY LEVEL <= (TO_DATE('2014-08-27 00:00:00', 'yyyy-mm-dd HH24:MI:SS') - TO_DATE('2014-08-01 00:00:00', 'yyyy-mm-dd HH24:MI:SS'))*24*4
order by 1;

Pačiam paprasčiausiam duomenų ištraukimui galima panaudoti tokį selectą:

select
ID
,TO_CHAR(DT, 'yyyy-mm-dd HH24:MI:SS') as DT
from t
order by ID

Select sakinio rezultatas yra maždaug toks:

ID   	DT
--   ------------------
1    2014-08-01 00:00:00
2    2014-08-01 00:15:00
3    2014-08-01 00:30:00
4    2014-08-01 00:45:00
.... .....
2493 2014-08-26 23:00:00
2494 2014-08-26 23:15:00
2495 2014-08-26 23:30:00
2496 2014-08-26 23:45:00

Pabandyk šiuose 2496 įrašuose atsirinkti 2014-08-01 – 2014-08-03 dienų „duomenis” nuo 08:00 iki 09:00. Tam prieš tai buvusi selectą papildom taip:

select
ID
,TO_CHAR(DT, 'yyyy-mm-dd HH24:MI:SS') as DT
from t
where
TO_CHAR(DT, 'yyyy-mm-dd') between '2014-08-01' and '2014-08-03'
and TO_CHAR(DT, 'HH24:MI:SS') >= '08:00:00'
and TO_CHAR(DT, 'HH24:MI:SS') <= '09:00:00'
order by ID

Užklausos rezultatas gaunasi toks:

ID   DT
---  -------------------
33   2014-08-01 08:00:00
34   2014-08-01 08:15:00
35   2014-08-01 08:30:00
36   2014-08-01 08:45:00
37   2014-08-01 09:00:00
129  2014-08-02 08:00:00
130  2014-08-02 08:15:00
131  2014-08-02 08:30:00
132  2014-08-02 08:45:00
133  2014-08-02 09:00:00
225  2014-08-03 08:00:00
226  2014-08-03 08:15:00
227  2014-08-03 08:30:00
228  2014-08-03 08:45:00
229  2014-08-03 09:00:00

Dabar pabandyk išsitraukti 2014-08-01 – 2014-08-15 periodo savaitgalių duomenis nuo 08:00 iki 09:00. Tam prieš tai buvusi selectą papildom taip:

select
ID
,TO_CHAR(DT, 'yyyy-mm-dd HH24:MI:SS') as DT
from t
where
TO_CHAR(DT, 'yyyy-mm-dd') between '2014-08-01' and '2014-08-15'
and TO_CHAR(DT, 'dy') in ( 'sat','sun' )
and TO_CHAR(DT, 'HH24:MI:SS') >= '08:00:00'
and TO_CHAR(DT, 'HH24:MI:SS') <= '09:00:00'
order by ID

Įvykdę užklausą, gaunam štai ką:

ID   DT
---  -------------------
129  2014-08-02 08:00:00
130  2014-08-02 08:15:00
131  2014-08-02 08:30:00
132  2014-08-02 08:45:00
133  2014-08-02 09:00:00
225  2014-08-03 08:00:00
226  2014-08-03 08:15:00
227  2014-08-03 08:30:00
228  2014-08-03 08:45:00
229  2014-08-03 09:00:00
801  2014-08-09 08:00:00
802  2014-08-09 08:15:00
803  2014-08-09 08:30:00
804  2014-08-09 08:45:00
805  2014-08-09 09:00:00
897  2014-08-10 08:00:00
898  2014-08-10 08:15:00
899  2014-08-10 08:30:00
900  2014-08-10 08:45:00
901  2014-08-10 09:00:00

Panašiu principu galim užklausi duomenų visoms darbo dienoms, t. y. be savaitgalių:

select
ID
,TO_CHAR(DT, 'yyyy-mm-dd HH24:MI:SS') as DT
from t
where
TO_CHAR(DT, 'yyyy-mm-dd') between '2014-08-01' and '2014-08-15'
and TO_CHAR(DT, 'dy') not in ( 'sat','sun' )
and TO_CHAR(DT, 'HH24:MI:SS') >= '08:00:00'
and TO_CHAR(DT, 'HH24:MI:SS') <= '09:00:00'
order by ID

 Iš rezultatų matome, kad užklausa veikia teisingai ir ignoruoja savaitgalių duomenis:

ID   DT
---  -------------------
33   2014-08-01 08:00:00
34   2014-08-01 08:15:00
35   2014-08-01 08:30:00
36   2014-08-01 08:45:00
37   2014-08-01 09:00:00
321  2014-08-04 08:00:00
322  2014-08-04 08:15:00
323  2014-08-04 08:30:00
...  ...

Kaip matot, viskas tikrai labai paprasta. Taip paprasta, kad beveik visada pasimiršta. 😀