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. 😀