I have a table with some entries, and a DATE column indicating the date/time the record was inserted. What I need is to create a query where the data will be displayed in a tabular format with counts at the 15 minute intervals for the entire day. So, the output would look like:
LABEL DAY DATE 00:00 00:15 00:30 00:45.........23:30 23:45
ORDERS MONDAY 4/19/2021 1 1 0 1 0 1
ORDERS TUESDAY 4/20/2021 1 0 0 0 1 0
This is what they are asking for......and probably have to put that into a CSV at some later date. But for now, is there any simple way to make a query like this, or are we talking writing a procedure?
You can use conditional aggregation:
SELECT label,
TO_CHAR(TRUNC("DATE"), 'DAY') AS day,
TRUNC("DATE") AS "DATE",
COUNT( CASE TRUNC(("DATE" - TRUNC("DATE"))*96) WHEN 0 THEN 1 END ) AS "00:00",
COUNT( CASE TRUNC(("DATE" - TRUNC("DATE"))*96) WHEN 1 THEN 1 END ) AS "00:15",
COUNT( CASE TRUNC(("DATE" - TRUNC("DATE"))*96) WHEN 2 THEN 1 END ) AS "00:30",
COUNT( CASE TRUNC(("DATE" - TRUNC("DATE"))*96) WHEN 3 THEN 1 END ) AS "00:45",
COUNT( CASE TRUNC(("DATE" - TRUNC("DATE"))*96) WHEN 4 THEN 1 END ) AS "01:00"
-- ...
FROM table_name
GROUP BY TRUNC( "DATE" ), label
ORDER BY TRUNC( "DATE" ), label
Or PIVOT:
SELECT TO_CHAR(dt,'FMDAY') AS day,
t.*
FROM (
SELECT label,
TRUNC("DATE") AS dt,
TRUNC( ("DATE" - TRUNC("DATE")) * 96 ) AS time
FROM table_name
)
PIVOT(
COUNT(*) FOR time IN (
0 AS "00:00",
1 AS "00:15",
2 AS "00:30",
3 AS "00:45",
4 AS "01:00",
5 AS "01:15",
-- ...
92 AS "23:00",
93 AS "23:15",
94 AS "23:30",
95 AS "23:45"
)
) t;
db<>fiddle here
I'll try to describe as detailed as I can.
First of all you can truncate your minutes to 15 minutes intervals:
--test data:
with t(label,dt) as (
select 'ORDERS',date'2021-04-21'+numtodsinterval(level*2,'minute')
from dual
connect by level<=30
)
--main query:
select
dt, label, weekday, hh24, quarter, quarter*15 rounded_minutes
from
(
select
dt
,label
,to_char(dt,'day') weekday
,to_char(dt,'hh24') hh24
,trunc(to_number(to_char(dt,'mi'))*4/60) quarter
from t
);
Results:
DT LABEL WEEKDAY HH24 QUARTER ROUNDED_MINUTES
------------------- ------ ---------- ---- ---------- ---------------
2021-04-21 00:02:00 ORDERS wednesday 00 0 0
2021-04-21 00:04:00 ORDERS wednesday 00 0 0
2021-04-21 00:06:00 ORDERS wednesday 00 0 0
2021-04-21 00:08:00 ORDERS wednesday 00 0 0
2021-04-21 00:10:00 ORDERS wednesday 00 0 0
2021-04-21 00:12:00 ORDERS wednesday 00 0 0
2021-04-21 00:14:00 ORDERS wednesday 00 0 0
2021-04-21 00:16:00 ORDERS wednesday 00 1 15
2021-04-21 00:18:00 ORDERS wednesday 00 1 15
2021-04-21 00:20:00 ORDERS wednesday 00 1 15
2021-04-21 00:22:00 ORDERS wednesday 00 1 15
2021-04-21 00:24:00 ORDERS wednesday 00 1 15
2021-04-21 00:26:00 ORDERS wednesday 00 1 15
2021-04-21 00:28:00 ORDERS wednesday 00 1 15
2021-04-21 00:30:00 ORDERS wednesday 00 2 30
2021-04-21 00:32:00 ORDERS wednesday 00 2 30
2021-04-21 00:34:00 ORDERS wednesday 00 2 30
2021-04-21 00:36:00 ORDERS wednesday 00 2 30
2021-04-21 00:38:00 ORDERS wednesday 00 2 30
2021-04-21 00:40:00 ORDERS wednesday 00 2 30
2021-04-21 00:42:00 ORDERS wednesday 00 2 30
2021-04-21 00:44:00 ORDERS wednesday 00 2 30
2021-04-21 00:46:00 ORDERS wednesday 00 3 45
2021-04-21 00:48:00 ORDERS wednesday 00 3 45
2021-04-21 00:50:00 ORDERS wednesday 00 3 45
2021-04-21 00:52:00 ORDERS wednesday 00 3 45
2021-04-21 00:54:00 ORDERS wednesday 00 3 45
2021-04-21 00:56:00 ORDERS wednesday 00 3 45
2021-04-21 00:58:00 ORDERS wednesday 00 3 45
2021-04-21 01:00:00 ORDERS wednesday 01 0 0
As you can see we calculate a quarter of hour using simple trunc(to_number(to_char(dt,'mi'))*4/60). So we just need to multiply it to 4 to get rounded minutes.
Then you can just concatenate them and use pivot clause to aggregate:
with t(label,dt) as (
select 'ORDERS',date'2021-04-21'+numtodsinterval(level*2,'minute')
from dual
connect by level<=3000
)
select *
from (
select
label, weekday, hh24||':'||to_char(quarter*15,'fm00') hhmi
from
(
select
dt
,label
,to_char(dt,'day') weekday
,to_char(dt,'hh24') hh24
,trunc(to_number(to_char(dt,'mi'))*4/60) quarter
from t
)
)
pivot(
count(*) for hhmi in (
'00:00','00:15','00:30','00:45','01:00','01:15','01:30','01:45'
,'02:00','02:15','02:30','02:45','03:00','03:15','03:30','03:45'
,'04:00','04:15','04:30','04:45','05:00','05:15','05:30','05:45'
,'06:00','06:15','06:30','06:45','07:00','07:15','07:30','07:45'
,'08:00','08:15','08:30','08:45','09:00','09:15','09:30','09:45'
,'10:00','10:15','10:30','10:45','11:00','11:15','11:30','11:45'
,'12:00','12:15','12:30','12:45','13:00','13:15','13:30','13:45'
,'14:00','14:15','14:30','14:45','15:00','15:15','15:30','15:45'
,'16:00','16:15','16:30','16:45','17:00','17:15','17:30','17:45'
,'18:00','18:15','18:30','18:45','19:00','19:15','19:30','19:45'
,'20:00','20:15','20:30','20:45','21:00','21:15','21:30','21:45'
,'22:00','22:15','22:30','22:45','23:00','23:15','23:30','23:45'
)
);
Results (shortened for readbility):
LABEL WEEKDAY '00:00' '00:15' '00:30' '00:45' '01:00' '01:15' ... '23:15' '23:30' '23:45'
------ ---------- ---------- ---------- ---------- ---------- ---------- ---------- ... ---------- ---------- ----------
ORDERS friday 8 7 8 7 8 7 ... 7 8 7
ORDERS saturday 8 7 8 7 8 7 ... 7 8 7
ORDERS sunday 8 7 8 7 8 7 ... 0 0 0
ORDERS thursday 8 7 8 7 8 7 ... 7 8 7
ORDERS wednesday 7 7 8 7 8 7 ... 7 8 7
I have this table in Oracle Database:
date | column1 | column2
01/05/2020 00:00 | 50 | 20
01/05/2020 00:15 | 60 | 30
01/05/2020 00:30 | 70 | 40
... | |
01/05/2020 23:45 | 80 | 50
02/05/2020 00:00 | 100 | 40
02/05/2020 00:15 | 110 | 35
And I have this SELECT script:
SELECT
period,
liquid
FROM
(
SELECT
( nvl(SUM(m.column1), 0) - nvl(SUM(m.column2), 0) ) liquid,
TO_CHAR(trunc(m.date), 'dd/MM/YYYY') period
FROM
table m
WHERE
m.id_register IN (id_register)
AND m.date BETWEEN TO_DATE('01/05/2020 00:15:00', 'dd/mm/yyyy hh24:mi:ss') AND TO_DATE('01/06/2020 00:00:00', 'dd/mm/yyyy hh24:mi:ss')
GROUP BY
TO_CHAR(trunc(m.date), 'dd/MM/YYYY')
) vrdm
I need to sum (difference column1 and column2) all day registers in interval between 00:15 and 00:00 (next day) per day. How to make it?
The result that I need is like this:
period | liquid
01/05/2020 | 3000 -> SUM(all differences between column1 and column2 between 01/05 00:15 and 02/05 00:00)
02/05/2020 | 4000 -> SUM(all differences between column1 and column2 between 02/05 00:15 and 03/05 00:00)
03/05/2020 | 3500 -> SUM(all differences between column1 and column2 between 03/05 00:15 and 04/05 00:00)
Just check time part in where clause:
SELECT to_char(trunc(m.dt), 'dd/MM/YYYY') period,
nvl(SUM(m.column1), 0) - nvl(SUM(m.column2), 0) liquid
FROM m
WHERE to_char(m.dt, 'hh24:mi') >= '00:15'
GROUP BY trunc(m.dt)
dbfiddle
I am trying to generate a range of 'last day of the month' dates from a given start date (01/01/2019) to the system date (sysdate).
I am able to generate the date range for this using the below query:
select last_day(add_months (trunc (to_date('01/01/2019','MM/DD/YYYY'), 'MM'), Level - 1))
Month FROM Dual
CONNECT BY Level <= MONTHS_BETWEEN(sysdate, to_date('01/01/2019','MM/DD/YYYY')) + 1
order by month
I am trying to get the last record to equal the sysdate so I can calculate running balances - how can I go about adding this to the above query?
Example output of the solution:
+------------------------+
| MONTH |
+------------------------+
| 1/31/2019 12:00:00 AM |
| 2/28/2019 12:00:00 AM |
| 3/31/2019 12:00:00 AM |
| 4/30/2019 12:00:00 AM |
| 5/31/2019 12:00:00 AM |
| 6/30/2019 12:00:00 AM |
| 7/31/2019 12:00:00 AM |
| 8/31/2019 12:00:00 AM |
| 9/30/2019 12:00:00 AM |
| 10/31/2019 12:00:00 AM |
| 11/30/2019 12:00:00 AM |
| 12/31/2019 12:00:00 AM |
| 1/31/2020 12:00:00 AM |
| 2/25/2020 12:00:00 AM |
+------------------------+
If I understood you correctly, you'd want today's date in the last line. If so, use CASE (lines #13 - 19).
Lines #1 - 12 represent your current query.
SQL> alter session set nls_date_format = 'dd.mm.yyyy hh24:mi:ss';
Session altered.
SQL> WITH your_data
2 AS ( SELECT LAST_DAY (
3 ADD_MONTHS (
4 TRUNC (TO_DATE ('01/01/2019', 'MM/DD/YYYY'), 'MM'),
5 LEVEL - 1))
6 Month
7 FROM DUAL
8 CONNECT BY LEVEL <=
9 MONTHS_BETWEEN (
10 SYSDATE,
11 TO_DATE ('01/01/2019', 'MM/DD/YYYY'))
12 + 1)
13 SELECT CASE
14 WHEN TRUNC (month, 'mm') = TRUNC (SYSDATE, 'mm')
15 THEN
16 TRUNC (SYSDATE)
17 ELSE
18 month
19 END
20 month
21 FROM your_data
22 ORDER BY month;
MONTH
-------------------
31.01.2019 00:00:00
28.02.2019 00:00:00
31.03.2019 00:00:00
30.04.2019 00:00:00
31.05.2019 00:00:00
30.06.2019 00:00:00
31.07.2019 00:00:00
31.08.2019 00:00:00
30.09.2019 00:00:00
31.10.2019 00:00:00
30.11.2019 00:00:00
31.12.2019 00:00:00
31.01.2020 00:00:00
18.02.2020 00:00:00
14 rows selected.
SQL>
When I first saw this I immediately thought a recursive CTE would be perfect. The problem I kept getting a type mismatch on the recursion that I could not resolve. It turned out Oracle 11g has a bug in recursive CTE with recurson with dates. This finally got me to updating at long last. So thanks for the question. Anyway for future viewers a recursive CTE does work.
alter session set nls_date_format = 'yyyy-mm-dd';
with date_list (dte) as
( select last_day(date '2019-01-01') from dual
union all
select least(add_months(dte,1), trunc(sysdate))
from date_list
where dte<trunc(sysdate)
)
select dte from date_list;
import pandas as pd
df=pd.DataFrame(index=pd.date_range("00:00", "04:00", freq="1H").time,data={'column1':[0,1,2,3,4]})
To begin with we have the following df:
column1
00:00:00 0
01:00:00 1
02:00:00 2
03:00:00 3
04:00:00 4
How do we sort from a specific index value in an ascending order, e.g. from 03:00:00?
Desired output:
column1
03:00:00 3
04:00:00 4
00:00:00 0
01:00:00 1
02:00:00 2
this is the only answer I could think of, but maybe someone is aware of a more elegant approach
df.loc[np.concatenate([np.array(df.index[3:]),np.array(df.index[:3])])]
column1
03:00:00 3
04:00:00 4
00:00:00 0
01:00:00 1
02:00:00 2