Oracle SQL Count Records per Hour - sql

So, what I'm trying to do basically is count the amount of shipments, per hour, per carrier, but I'm having difficulties getting it to sum in the columns I want. The goal is to instead of having 1 or 2 under Hour 1 or Hour 2 it would have sum(total shipments). Essentially 24 hours so we could see trends in time of day...
Code:
select router_destination_code,
case when to_char(app_last_updated_date_utc, 'HH24') = '00' then '1' else NULL end as "Hour 1",
case when to_char(app_last_updated_date_utc, 'HH24') = '01' then '2' else NULL end as "Hour 2",
case when to_char(app_last_updated_date_utc, 'HH24') = '02' then '3' else NULL end as "Hour 3",
--case when app_last_updated_date_utc between 'dec/07/2013 16:00:00' and 'dec/14/2013 17:00:00' then count(Router_Destination_code) else NULL end as "Hour_1"
count(Router_Destination_code) as Shipments
from booker.routing_container_history
where
app_last_updated_by_module in ('ManualSlam', 'slam')
and app_last_updated_date_utc between 'dec/07/2013 16:00:00' and 'dec/14/2013 16:00:00'
group by
router_destination_code,
case when to_char(app_last_updated_date_utc, 'HH24') = '00' then '1' else NULL end,
case when to_char(app_last_updated_date_utc, 'HH24') = '01' then '2' else NULL end,
case when to_char(app_last_updated_date_utc, 'HH24') = '02' then '3' else NULL end
order by
case when to_char(app_last_updated_date_utc, 'HH24') = '00' then '1' else NULL end,
case when to_char(app_last_updated_date_utc, 'HH24') = '01' then '2' else NULL end,
case when to_char(app_last_updated_date_utc, 'HH24') = '02' then '3' else NULL end,
count(Router_Destination_code) desc;
Output:
But, the Goal is to have the shipments underneath the hour.
Thank you.
Here is a new approach I did.. But it is showing lots of zeros, and would like it only to show numbers the whole way across.
select router_destination_code,
count(case when to_char(app_last_updated_date_utc, 'HH24') = '16' then router_destination_code else NULL end) as "Hour 1",
count(case when to_char(app_last_updated_date_utc, 'HH24') = '17' then router_destination_code else NULL end) as "Hour 2"
--case when app_last_updated_date_utc between 'dec/07/2013 16:00:00' and 'dec/14/2013 17:00:00' then count(Router_Destination_code) else NULL end as "Hour_1"
--count(Router_Destination_code) as Shipments
from booker.routing_container_history
where
app_last_updated_by_module in ('ManualSlam', 'slam')
and app_last_updated_date_utc between 'dec/07/2013 16:00:00' and 'dec/14/2013 16:00:00'
group by
router_destination_code,
case when to_char(app_last_updated_date_utc, 'HH24') = '16' then router_destination_code else NULL end,
case when to_char(app_last_updated_date_utc, 'HH24') = '17' then router_destination_code else NULL end
order by
case when to_char(app_last_updated_date_utc, 'HH24') = '16' then router_destination_code else NULL end,
case when to_char(app_last_updated_date_utc, 'HH24') = '17' then router_destination_code else NULL end,
count(Router_Destination_code) desc;

I do not know if I understood you well but you may try to just extract hour from date and then group by:
Check this fiddle (sorry for bad syntax):
http://sqlfiddle.com/#!4/a0a97/6
create table a (id number, data date);
insert into a (id, data)
values (1, to_date( '2013-01-01 13:12:01', 'yyyy-mm-dd hh24:mi:ss'));
insert into a (id, data)
values (1, to_date( '2013-01-01 13:12:01', 'yyyy-mm-dd hh24:mi:ss'));
insert into a (id, data)
values (1, to_date( '2013-01-01 14:12:01', 'yyyy-mm-dd hh24:mi:ss'));
select to_char(data,'HH24'), count(1) from a group by to_char(data,'HH24');

Related

PIVOT by timestamp

I need to pivot the time (hour) for the results of this query, so there could be up to 24 hours running across the top as you can replicate in an Excel pivot table. Is there an easy and efficient way to replicate this in the query?
Query:
SELECT
trunc(complete_dstamp) "Date",
to_char(complete_dstamp, 'HH24') "Hour",
user_id "User",
sum(update_qty) "Qty"
FROM
inventory_transaction
WHERE
to_loc_id = 'CONTAINER'
and trunc(complete_dstamp) > (
trunc(current_timestamp)-1
)
GROUP BY
trunc(complete_dstamp),
to_char(complete_dstamp, 'HH24'),
user_id
ORDER BY
1,
2
Desired output:
Current output:
Use conditional aggregation:
SELECT TO_CHAR(complete_dstamp, 'YYYY-MM-DD') AS "Date",
user_id AS "User",
SUM(CASE TO_CHAR(complete_dstamp, 'HH24') WHEN '00' THEN update_qty END) AS hour_0,
SUM(CASE TO_CHAR(complete_dstamp, 'HH24') WHEN '01' THEN update_qty END) AS hour_1,
SUM(CASE TO_CHAR(complete_dstamp, 'HH24') WHEN '02' THEN update_qty END) AS hour_2,
SUM(CASE TO_CHAR(complete_dstamp, 'HH24') WHEN '03' THEN update_qty END) AS hour_3,
SUM(CASE TO_CHAR(complete_dstamp, 'HH24') WHEN '04' THEN update_qty END) AS hour_4,
-- ...
SUM(CASE TO_CHAR(complete_dstamp, 'HH24') WHEN '23' THEN update_qty END) AS hour_23,
sum(update_qty) AS grand_total
FROM inventory_transaction
WHERE to_loc_id = 'CONTAINER'
AND complete_dstamp >= trunc(current_timestamp)
GROUP BY
TO_CHAR(complete_dstamp, 'YYYY-MM-DD'),
user_id
ORDER BY
"Date",
"User"
Or a PIVOT:
SELECT "Date",
user_id AS "User",
hour_0,
hour_1,
hour_2,
hour_3,
hour_4,
-- ...
hour_23,
COALESCE(hour_0, 0)
+ COALESCE(hour_1, 0)
+ COALESCE(hour_2, 0)
+ COALESCE(hour_3, 0)
+ COALESCE(hour_4, 0)
-- ...
+ COALESCE(hour_23, 0) AS grand_total
FROM (
SELECT TO_CHAR(complete_dstamp, 'YYYY-MM-DD') AS "Date",
TO_CHAR(complete_dstamp, 'HH24') AS hour,
user_id,
update_qty
FROM inventory_transaction
WHERE to_loc_id = 'CONTAINER'
AND complete_dstamp >= trunc(current_timestamp)
)
PIVOT (
SUM(update_qty) FOR hour IN (
'00' AS hour_0,
'01' AS hour_1,
'02' AS hour_2,
'03' AS hour_3,
'04' AS hour_4,
-- ...
'23' AS hour_23
)
)
db<>fiddle here

Pivot without aggregate function

I am trying to turn some parts of my rows into columns. To my knowledge, I am only able to use a pivot with an aggregate function,but I would just be pivoting text. For each client I have up to 4 rows grouped by a DLSEQUENCE field. Instead of having the 4 rows, I would like everything to be on 1 row.
SELECT CASE
WHEN Sched_time BETWEEN TRUNC(SCHED_TIME) + INTERVAL '8' HOUR + INTERVAL '30' MINUTE
AND TRUNC(SCHED_TIME) + INTERVAL '14' HOUR + INTERVAL '45' MINUTE AND
TO_CHAR(SCHED_TIME, 'DY') IN ('MON', 'TUE', 'WED', 'THU', 'FRI')
THEN 'ABC'
ELSE 'DEF'
END AS Organization,
Client_Last_Name,
Client_First_Name,
Sched_Time,
Field_Name,
CASE
WHEN Recoded_Response = '1' THEN 'Yes'
WHEN Recoded_Response = '2' THEN 'No'
ELSE Recoded_Response
END AS Responses,
Dlsequence
FROM DAILY_LOG_CUSTOM_DATA
WHERE SERVICE_NAME = 'Medical'
AND FIELD_CATEGORY = 'Background Information'
AND Field_Name IN
(
'Restraint?',
'History',
'Findings',
'Treatment'
)
AND Sched_Time >= TO_DATE('2020-03-01 01:00:00', 'YYYY/MM/DD HH:MI:SS')
AND Sched_Time < TO_DATE('2020-03-31 12:59:00', 'YYYY/MM/DD HH:MI:SS')
Order BY Dlsequence
Here is my table:
I would like the response fields that go with ('Restraint?','History','Findings','Treatment') to have their own column for each DLSEQUENCE field.
The following should do what you had in mind:
SELECT DLSEQUENCE,
ORGANIZATION,
CLIENT_LAST_NAME,
CLIENT_FIRST_NAME,
SCHED_TIME,
LISTAGG("Restraint?", ',') WITHIN GROUP (ORDER BY DLSEQUENCE) AS "Restraint?",
LISTAGG("Findings", ',') WITHIN GROUP (ORDER BY DLSEQUENCE) AS "Findings",
LISTAGG("History", ',') WITHIN GROUP (ORDER BY DLSEQUENCE) AS "History",
LISTAGG("Treatment", ',') WITHIN GROUP (ORDER BY DLSEQUENCE) AS "Treatment"
FROM (SELECT DLSEQUENCE,
ORGANIZATION,
CLIENT_LAST_NAME,
CLIENT_FIRST_NAME,
SCHED_TIME,
CASE
WHEN FIELD_NAME = 'Restraint?' THEN RESPONSES
ELSE NULL
END AS "Restraint?",
CASE
WHEN FIELD_NAME = 'Findings' THEN RESPONSES
ELSE NULL
END AS "Findings",
CASE
WHEN FIELD_NAME = 'History' THEN RESPONSES
ELSE NULL
END AS "History",
CASE
WHEN FIELD_NAME = 'Treatment' THEN RESPONSES
ELSE NULL
END AS "Treatment"
FROM YOUR_TABLE)
GROUP BY DLSEQUENCE,
ORGANIZATION,
CLIENT_LAST_NAME,
CLIENT_FIRST_NAME,
SCHED_TIME
db<>fiddle here

Case Expression and dates

I have the below case expression.
SELECT end_dt,
CASE WHEN TO_CHAR(A.END_DT,'MM/DD/YYYY') = '01/01/3000' THEN ''
WHEN TO_CHAR(A.END_DT,'MM/DD/YYYY') > TO_CHAR(SYSDATE,'MM/DD/YYYY') THEN TO_CHAR(SYSDATE,'MM/DD/YYYY')
ELSE TO_CHAR(A.END_DT,'MM/DD/YYYY')
END ENDDATE,
CASE WHEN TO_CHAR(A.END_DT,'YYYYMM') = '300001' THEN ''
WHEN TO_CHAR(A.END_DT,'YYYYMM') > TO_CHAR(SYSDATE,'YYYYMM') THEN TO_CHAR(SYSDATE,'YYYYMM')
ELSE TO_CHAR(A.END_DT,'YYYYMM')
END ENDDATE_YYYYMM,
CASE WHEN TO_CHAR(A.END_DT,'YYYY') = '3000' THEN ''
WHEN TO_CHAR(A.END_DT,'YYYY') > TO_CHAR(SYSDATE,'YYYY') THEN TO_CHAR(SYSDATE,'YYYY')
WHEN TO_CHAR(A.END_DT,'YYYY') > TO_CHAR(SYSDATE,'YYYY') THEN TO_CHAR(SYSDATE,'YYYY')
ELSE TO_CHAR(A.END_DT,'YYYY')
END ENDDATE_YYYY
FROM A
LEFT D ON A.ID = D.ID
WHERE 1=1
ORDER BY 1
OutPut:
End_dt ENDDATE ENDDATE_YYYYMM ENDDATE_YYYY
12/5/2012 14:33:24 01/05/2018 201212 2012
Expected output:
End_dt ENDDATE ENDDATE_YYYYMM ENDDATE_YYYY
12/5/2012 14:33:24 12/5/2012 201212 2012
Why do I get a result of 01/05/2018 and not 12/5/2012?
You're doing string comparisons on dates. Stop. Do date comparisons on dates.
The string '12/5/2012' is greater than the string '01/05/2018' because 1 is greater than 0. Oracle is performing a binary comparison.
SQL> select *
2 from dual
3 where '12/5/2012' > '01/05/2018';
D
-
X
Stop converting all your dates to strings and all will be well
SQL> select *
2 from dual
3 where date '2018-05-01' > date '2012-05-12';
D
-
X
Incidentally, the empty string '' is equivalent to NULL in Oracle.
Your query should look like:
CASE WHEN A.END_DT = date '3000-01-01' then null
WHEN A.END_DT > SYSDATE THEN TO_CHAR(SYSDATE,'MM/DD/YYYY')
ELSE TO_CHAR(A.END_DT,'MM/DD/YYYY')
END ENDDATE,
Don't do date comparisons as strings. It works for the other values, because you have the right format -- YYYYMMDD (or a partial piece of that).
Try this logic:
SELECT end_dt,
(CASE WHEN TO_CHAR(A.END_DT, 'MM/DD/YYYY') = '01/01/3000' THEN ''
WHEN A.END_DT > SYSDATE
THEN TO_CHAR(SYSDATE, 'MM/DD/YYYY')
ELSE TO_CHAR(A.END_DT, 'MM/DD/YYYY')
END) as ENDDATE,
(CASE WHEN TO_CHAR(A.END_DT, 'YYYYMM') = '300001' THEN ''
WHEN TO_CHAR(A.END_DT, 'YYYYMM') > TO_CHAR(SYSDATE, 'YYYYMM')
THEN TO_CHAR(SYSDATE,'YYYYMM')
ELSE TO_CHAR(A.END_DT,'YYYYMM')
END) as ENDDATE_YYYYMM,
(CASE WHEN TO_CHAR(A.END_DT, 'YYYY') = '3000' THEN ''
WHEN TO_CHAR(A.END_DT, 'YYYY') > TO_CHAR(SYSDATE, 'YYYY')
THEN TO_CHAR(SYSDATE, 'YYYY')
WHEN TO_CHAR(A.END_DT, 'YYYY') > TO_CHAR(SYSDATE,'YYYY')
THEN TO_CHAR(SYSDATE, 'YYYY')
ELSE TO_CHAR(A.END_DT, 'YYYY')
END) as ENDDATE_YYYY

SQL union query not returning both columns

I am trying to retrieve data from a database in a particular format to hook into a dashboard app. I need one column called "Import" with counts beneath it, and another called "Export" with relevant counts in that. I have the following query right now but it is only returning an Import column and I've verified there is relevant data to show as Export as well. Any ideas? Adding a screenshot of the result I'm getting...
SELECT count(*) as "Import", a.ship_id "Ship"
FROM SERVICE_EVENTS a JOIN CONTAINERS b ON a.eq_nbr = b.nbr
WHERE (
(to_char(sysdate, 'HH24') between '07' and '17' and a.performed between trunc(sysdate) + 7/24 and sysdate and category = 'I')
OR
(to_char(sysdate, 'HH24') between '18' and '23' and a.performed between trunc(sysdate) + 18/24 and sysdate and category = 'I')
OR
(to_char(sysdate, 'HH24') between '00' and '06' and a.performed between trunc(sysdate - 1) + 18/24 and sysdate and category = 'I')
)
AND a.TSERV_ID in ('LOAD', 'DISCHARGE') group by a.ship_id
UNION
SELECT count(*) as "Export", a.ship_id "Ship"
FROM SERVICE_EVENTS a JOIN CONTAINERS b ON a.eq_nbr = b.nbr
WHERE (
(to_char(sysdate, 'HH24') between '07' and '17' and a.performed between trunc(sysdate) + 7/24 and sysdate and category = 'E')
OR
(to_char(sysdate, 'HH24') between '18' and '23' and a.performed between trunc(sysdate) + 18/24 and sysdate and category = 'E')
OR
(to_char(sysdate, 'HH24') between '00' and '06' and a.performed between trunc(sysdate - 1) + 18/24 and sysdate and category = 'E')
)
AND a.TSERV_ID in ('LOAD', 'DISCHARGE') group by a.ship_id
;
You can do a conditional aggregation and simplify your query to this:
SELECT
a.ship_id AS Ship,
COUNT(CASE WHEN category = 'I' THEN 1 END) AS Import,
COUNT(CASE WHEN category = 'E' THEN 1 END) AS Export
FROM SERVICE_EVENTS a
JOIN CONTAINERS b
ON a.eq_nbr = b.nbr
WHERE
(
(to_char(sysdate, 'HH24') BETWEEN '07' AND '17' AND a.performed BETWEEN trunc(sysdate) + 7/24 AND sysdate)
OR (to_char(sysdate, 'HH24') BETWEEN '18' AND '23' AND a.performed BETWEEN trunc(sysdate) + 18/24 AND sysdate)
OR (to_char(sysdate, 'HH24') BETWEEN '00' AND '06' AND a.performed BETWEEN trunc(sysdate - 1) + 18/24 AND sysdate)
)
AND a.TSERV_ID in ('LOAD', 'DISCHARGE')
GROUP BY a.ship_id
You can explicitly select null as the column not being counted and do one more aggregation.
select max(Import) as Import, max(Export) as Export, Ship
from (
SELECT count(*) as "Import", null as "Export", a.ship_id "Ship"
FROM SERVICE_EVENTS a JOIN CONTAINERS b ON a.eq_nbr = b.nbr
WHERE (
(to_char(sysdate, 'HH24') between '07' and '17' and a.performed between trunc(sysdate) + 7/24 and sysdate and category = 'I')
OR
(to_char(sysdate, 'HH24') between '18' and '23' and a.performed between trunc(sysdate) + 18/24 and sysdate and category = 'I')
OR
(to_char(sysdate, 'HH24') between '00' and '06' and a.performed between trunc(sysdate - 1) + 18/24 and sysdate and category = 'I')
)
AND a.TSERV_ID in ('LOAD', 'DISCHARGE') group by a.ship_id
UNION
SELECT null as import, count(*) as "Export", a.ship_id "Ship"
FROM SERVICE_EVENTS a JOIN CONTAINERS b ON a.eq_nbr = b.nbr
WHERE (
(to_char(sysdate, 'HH24') between '07' and '17' and a.performed between trunc(sysdate) + 7/24 and sysdate and category = 'E')
OR
(to_char(sysdate, 'HH24') between '18' and '23' and a.performed between trunc(sysdate) + 18/24 and sysdate and category = 'E')
OR
(to_char(sysdate, 'HH24') between '00' and '06' and a.performed between trunc(sysdate - 1) + 18/24 and sysdate and category = 'E')
)
AND a.TSERV_ID in ('LOAD', 'DISCHARGE') group by a.ship_id
) t
group by Ship

How to combine 2 oracle queries with differrent where clauseses into 1 query

I have below 2 oracle queries with different where conditions
(Some criteria in where condition is same). Is it possible to combine these 2 queries to 1 query?
queries are here
Different conditions: TX_TYPE, TX_STATUS
Common conditions: SUBSCRIBER_ID, MERCHANT_ID, IS_TAXABLE, TX_DATE
Query1:
select sum(t.AMOUNT) Amt1
from RS_TRANSACTION_LOG t, RS_MERCHANT m
where t.SUBSCRIBER_ID = 11338329
and t.MERCHANT_ID = m.MERCHANT_ID
and t.TX_TYPE = '1'
and t.TX_STATUS in (5, 42)
and m.IS_TAXABLE = 'Y'
and TX_DATE between to_date('11/01/2015 00:00:00','MM/dd/YYYY HH24:MI:SS')
and to_date('11/30/2015 23:59:59','MM/dd/YYYY HH24:MI:SS');
Query2:
select sum(t.AMOUNT) Amt2
from RS_TRANSACTION_LOG t, RS_MERCHANT m
where t.SUBSCRIBER_ID = 11338329
and t.MERCHANT_ID = m.MERCHANT_ID
and t.TX_TYPE = '5'
and t.TX_STATUS = 5
and m.IS_TAXABLE = 'Y'
and TX_DATE between to_date('11/01/2015 00:00:00','MM/dd/YYYY HH24:MI:SS')
and to_date('11/30/2015 23:59:59','MM/dd/YYYY HH24:MI:SS');
What about using an OR to combine the conditions and CASE to separate the amounts:
select sum(case when t.TX_TYPE = '1' and t.TX_STATUS in (5,42) then t.AMOUNT else 0 end) Amt1,
sum(case when t.TX_TYPE = '5' and t.TX_STATUS = 5 then t.AMOUNT else 0 end) Amt2
from RS_TRANSACTION_LOG t,
RS_MERCHANT m
where t.SUBSCRIBER_ID=11338329
and t.MERCHANT_ID=m.MERCHANT_ID
and ((t.TX_TYPE = '1' and t.TX_STATUS in (5,42)) or
(t.TX_TYPE='5' and t.TX_STATUS = '5'))
and m.IS_TAXABLE='Y'
and TX_DATE between
to_date('11/01/2015 00:00:00','MM/dd/YYYY HH24:MI:SS') and
to_date('11/30/2015 23:59:59','MM/dd/YYYY HH24:MI:SS');