This is written in Oracle 11g or 12c...
Hello,
I am attempting to shape this data into hours of downtime for the previous 12 months, shaped this way to support a graph.
In the Oracle SQL query below, the commented query "M" shows how to put in one record per month. The query "M" shows the final shape I need, except that I need the downtime minutes to fall into each monthly bin.
The data however, is provided by query "D", which I have mocked up for the sake of this example. Of course, a better example might show more edge cases, such as spanning the first of a month, etc. But this example will suffice.
WITH
/*
M AS (
SELECT ADD_MONTHS (TRUNC (SYSDATE, 'MONTH'), -1 * LEVEL) AS MO
, 0 AS DOWNTIME FROM DUAL
CONNECT BY LEVEL <= 12),
*/
D AS ( -- data simulating a downtime day
SELECT 'Target Up' AS AVAILABILITY_STATUS,
TO_DATE ('9/25/2015 15:12:47', 'MM/DD/YYYY HH24:MI:SS')
AS SINCE,
385392 AS MINUTES
FROM DUAL
UNION ALL
SELECT 'Target Down' AS AVAILABILITY_STATUS,
TO_DATE ('11/25/2015 15:12:00', 'MM/DD/YYYY HH24:MI:SS')
AS SINCE,
1440 AS MINUTES
FROM DUAL
UNION ALL
SELECT 'Target Up' AS AVAILABILITY_STATUS,
TO_DATE ('11/26/2015 15:12:00', 'MM/DD/YYYY HH24:MI:SS')
AS SINCE,
200122 AS MINUTES
FROM DUAL)
SELECT *
FROM D
PIVOT
(SUM (MINUTES)
AS TIME
FOR AVAILABILITY_STATUS
IN ('Target Up' AS UP,
'Target Down' AS DOWN,
'Blackout' AS BLACKOUT));
The result now looks like this:
SINCE UP_TIME DOWN_TIME BLACKOUT_TIME
9/25/2015 3:12:47 PM 385,392
11/25/2015 3:12:00 PM 1,440
11/26/2015 3:12:00 PM 200,122
but I need it to look like this:
MO DOWN_MINUTES
3/1/2016 0
2/1/2016 0
1/1/2016 0
12/1/2015 0
11/1/2015 1440
10/1/2015 0
9/1/2015 0
8/1/2015 0
7/1/2015 0
6/1/2015 0
5/1/2015 0
4/1/2015 0
P.S.: For the benefit of the group, the actual downtime in query "M" is generated by the following query, which reads from Oracle Enterprise Manager:
WITH X
AS (SELECT START_TIMESTAMP,
NVL (END_TIMESTAMP, SYSDATE) AS END_TIMESTAMP,
AVAILABILITY_STATUS,
TRUNC (
(NVL (END_TIMESTAMP, SYSDATE) - START_TIMESTAMP) * 24 * 60)
MINUTES
FROM MGMT$AVAILABILITY_HISTORY
WHERE AVAILABILITY_STATUS IN
('Target Down', 'Target Up', 'Blackout')
)
SELECT AVAILABILITY_STATUS,
MIN (START_TIMESTAMP) AS SINCE,
SUM (MINUTES) AS MINUTES
FROM X
GROUP BY AVAILABILITY_STATUS
ORDER BY MIN (START_TIMESTAMP);
Thank you in advance. I have been spinning my wheels on this for days and it's time to ask for help.
try this:
WITH
M AS (
SELECT ADD_MONTHS (TRUNC (SYSDATE, 'MONTH'), -1 * LEVEL) AS MO
, 0 AS DOWNTIME FROM DUAL
CONNECT BY LEVEL <= 12),
D AS ( -- data simulating a downtime day
SELECT 'Target Up' AS AVAILABILITY_STATUS,
TO_DATE ('9/25/2015 15:12:47', 'MM/DD/YYYY HH24:MI:SS')
AS SINCE,
385392 AS MINUTES
FROM DUAL
UNION ALL
SELECT 'Target Down' AS AVAILABILITY_STATUS,
TO_DATE ('11/25/2015 15:12:00', 'MM/DD/YYYY HH24:MI:SS')
AS SINCE,
1440 AS MINUTES
FROM DUAL
UNION ALL
SELECT 'Target Up' AS AVAILABILITY_STATUS,
TO_DATE ('11/26/2015 15:12:00', 'MM/DD/YYYY HH24:MI:SS')
AS SINCE,
200122 AS MINUTES
FROM DUAL)
SELECT M.mo, Nvl(s, 0) AS minutes
FROM M
LEFT JOIN ( SELECT TRUNC (SINCE, 'MONTH') AS D, SUM (MINUTES) AS S
FROM D
WHERE AVAILABILITY_STATUS = 'Target Down'
GROUP BY TRUNC (SINCE, 'MONTH')) GR
ON GR.D = M.MO
ORDER BY 1;
Related
I have a sales table with created datetime, my business hours are from 9 AM to 2 AM in the night on the following day. I am trying to convert the dates into my business date.
01/08/22 09:39:12.000000000 AM +04:00
Lets say I have a sale at 1 AM, this sale has to be considered in the previous day.
Any function that can help me solve this issue would be appreciated
It might be a bit of an overkill, but you could just use EXTRACT:
WITH dat AS
(
SELECT to_date('01/08/22 09:39:12','DD/MM/YY HH24:MI:SS') AS t_stmp FROM dual UNION ALL
SELECT to_date('02/08/22 01:03:15','DD/MM/YY HH24:MI:SS') FROM dual UNION ALL
SELECT to_date('02/08/22 08:27:33','DD/MM/YY HH24:MI:SS') FROM dual UNION ALL
SELECT to_date('02/08/22 14:11:51','DD/MM/YY HH24:MI:SS') FROM dual UNION ALL
SELECT to_date('02/08/22 02:01:15','DD/MM/YY HH24:MI:SS') FROM dual
)
SELECT CASE WHEN EXTRACT(HOUR FROM CAST(t_stmp AS TIMESTAMP)) BETWEEN 2 AND 8 THEN -1
ELSE 0
END + TRUNC(t_stmp,'DD') AS business_date
FROM dat;
business_date
01.08.2022
02.08.2022
01.08.2022
02.08.2022
01.08.2022
It looks like you just need to make a 2 hour shift to get your sales in the right date. You can add or substract hours from DATE/DATETIME/TIMESTAMP data type. If your column is TIMESTAMP then it would be like this:
-- when selecting data for date of sales
SELECT TRUNC(your_column_name - INTERVAL '2' HOUR, 'dd') "SALE_DATE"
-- And/Or
WHERE TRUNC(your_column_name - INTERVAL '2' HOUR, 'dd') = :DATE_OF_SALES
-- TRUNC function always returns DATE datatype
--
-- The opposite conversion would be
CAST(your_datetime_column + INTERVAL '2' HOUR as TIMESTAMP) ...
Here is the small sample with result:
SELECT
to_char(SYSDATE, 'dd.mm.yyyy hh24:mi:ss') "DATETIME",
to_char(SYSDATE - INTERVAL '2' HOUR, 'dd.mm.yyyy hh24:mi:ss') "DATETIME_MINUS_2H",
to_char(SYSDATE + INTERVAL '2' HOUR, 'dd.mm.yyyy hh24:mi:ss') "DATETIME_PLUS_2H",
to_char(SYSDATE - INTERVAL '10' HOUR, 'dd.mm.yyyy hh24:mi:ss') "DATETIME_MINUS_10H"
FROM
DUAL
--
-- R e s u l t
--
-- DATETIME DATETIME_MINUS_2H DATETIME_PLUS_2H DATETIME_MINUS_10H
-- ------------------- ------------------- ------------------- -------------------
-- 07.08.2022 09:58:38 07.08.2022 07:58:38 07.08.2022 11:58:38 06.08.2022 23:58:38
The last column now has the date from day before.
I have the following data:
CUSTOMER_ORDERS:
CUST_ORDER_NO CREATE_DATETIME
WEB904204965 17-SEP-21 03.12.45.719000000 PM
WEB904204966 17-SEP-21 03.16.45.719000000 PM
I want to check the number of orders in every hour, like:
COUNT SLAB
2 1-2 PM
4 2-3 PM
How to write the query for this?
You can trunc the date/time or extract just the hour component, then GROUP BY that expression.
Here's a test case with sample SQL:
Working Test Case with a little data
SELECT COUNT(*) AS n
, to_char(dt, 'HH') AS slab
FROM test
GROUP BY to_char(dt, 'HH')
;
Result:
We could have used 'HH24' to show the 24 hour value or 'HH AM' to show the 'hours plus AM/PM' indicator.
SELECT to_char(current_date, 'HH24') AS slab FROM dual;
SELECT to_char(current_date, 'HH AM') AS slab FROM dual;
I'm new to SQL and was wondering if you could help me create a query that compares the time difference in Days, Hours, Minutes.
For example,
Start time 1 = 13/01/2016, 16:00
End time 1 = 14/01/2016, 18:00
So the time difference should be 1 day and 2 hours right?
Another example.
Start time 2 = 20/10/2016, 12:00
End time 2 = 20/10/2016, 16:00
So the
time difference is just 2 hours.
The reason I need this query is to create a report based on the difference in time between a start time and a finish time of a task.
watch out for problems with DATEDIFF that ignores fractions of days etc
DECLARE #Starttime DATETIME = '20160113 16:00';
DECLARE #Endtime DATETIME ='20160114 15:59';
--calculate difference in seconds then use integer divides and MODULUS to extract days, hours, minutes
;WITH DIFF_SECS AS (SELECT CAST(DATEDIFF(second,#Starttime,#Endtime) AS BIGINT) AS SD)
SELECT SD / (24 * 3600) as NoDays,
(SD % (24 * 3600)) / 3600 as NoHours,
(SD % 3600) / 60 AS NoMinutes
FROM DIFF_SECS;
if you aren't using microsoft SQL - then the formulae are possible still useful
if X = 'difference between times in seconds'
then whole days = X / (24 * 3600) where the divide is an integer divide (always rounds down)
In Oracle I would do it like that:
-- this is only to create some data
WITH MyRows AS (
SELECT to_date('2000/11/30 12:59', 'YYYY/MM/DD HH24:MI') BEGINNING, to_date('2000/11/30 14:01', 'YYYY/MM/DD HH24:MI') ENDING FROM DUAL UNION
SELECT to_date('2000/12/01 12:59', 'YYYY/MM/DD HH24:MI') , to_date('2000/12/02 00:01', 'YYYY/MM/DD HH24:MI') FROM DUAL UNION
SELECT to_date('2000/12/30 12:59', 'YYYY/MM/DD HH24:MI') , to_date('2000/12/31 14:01', 'YYYY/MM/DD HH24:MI') FROM DUAL UNION
SELECT to_date('2000/12/31 12:59', 'YYYY/MM/DD HH24:MI') , to_date('2001/01/01 04:01', 'YYYY/MM/DD HH24:MI') FROM DUAL
)
-- this is the select
SELECT
BEGINNING,
ENDING,
ENDING-BEGINNING IN_DAYS,
(ENDING-BEGINNING)*24 IN_HOURS,
(ENDING-BEGINNING)*24*3600 IN_SECONDS,
case
when (ENDING-BEGINNING)*24*60 >= 3 then round(((ENDING-BEGINNING)*24*60-3)*2)
else 0
end Total_cost_in_hamburgers
FROM MyRows
;
timedifferences are days and if you want to calculate with it (f.e. after 3 minutes every minute costs 2 hamburgers) it is better to calculate that way
I require a query that selects rows where the time is less or equal to 12:00
I had something like this in mind:
SELECT daterow FROM datecolumn WHERE daterow <= TO_DATE('12:00, HH24:MI')
However i get an error:
ORA-01843: not a valid month
How would i go about to get all rows that have a time less than 12:00 mid-day?
Try this,
SELECT daterow FROM datecolumn WHERE daterow <= TO_DATE('12:00', 'HH24:MI');
Try This:
SELECT daterow FROM datecolumn
WHERE TO_DATE(daterow,'HH24:MI') <= TO_DATE('12:00', 'HH24:MI');
In order to select all rows where time portion of the daterow column value is less than or equal to mid-day 12:00 you can use to_char() function to extract hour and minutes and to_number() to convert it to a number for further comparison:
-- sample of data. Just for the sake of demonstration
SQL> with t1(col) as(
2 select sysdate - to_dsinterval('P0DT3H') from dual union all
3 select sysdate - to_dsinterval('P0DT2H') from dual union all
4 select sysdate - to_dsinterval('P0DT1H') from dual union all
5 select sysdate + to_dsinterval('P0DT3H') from dual union all
6 select sysdate + to_dsinterval('-P2DT0H') from dual
7 )
8 select to_char(col, 'dd.mm.yyyy hh24:mi:ss') as res
9 from t1 t
10 where to_number(to_char(col, 'hh24mi')) <= 1200
11 ;
Result:
RES
-------------------
26.08.2013 08:10:59
26.08.2013 09:10:59
26.08.2013 10:10:59
24.08.2013 11:10:59
Sorry, but <= TO_DATE('12:00', 'HH24:MI') does not work. It does not extract the hour and minute from each date and compares it to 12:00. Instead it constructs the date representing high noon on the fisrt of the current month and compares each date to this date.
If you want to extract something from a date, use the extract function.
Attention: When using extract on a date, and want to extract hours, minutes or seconds, you have first to convert the date to a timestamp.
Example:
SELECT
extract(hour FROM cast(A AS TIMESTAMP)) AS h,
extract(MINUTE FROM cast(A AS TIMESTAMP)) AS m
FROM
DEMO
;
You can find a complete example on sqlfiddle. The example also shows that the to_date method doesn't work.
We have times stored in an Oracle varchar(5) field.
Times stored using HH24:MI (ie: 22:30, 10:15).
How can we run a query that will increase or decrease these times by a certain amount? Ie: increase by one hour or decrease by 45 minutes.
you could use the built-in date (and interval -- thanks Alex for the link) calculation:
to_char(to_date(:x, 'hh24:mi') + INTERVAL :y MINUTE,'hh24:mi')
for instance:
SQL> WITH my_data AS (
2 SELECT '12:15' t FROM dual
3 UNION ALL SELECT '10:30' FROM dual
4 )
5 SELECT t,
6 to_char(to_date(t, 'hh24:mi') + INTERVAL '15' MINUTE,'hh24:mi')"t+15"
7 FROM my_data;
T t+15
----- -----
12:15 12:30
10:30 10:45
The functions to convert from/to date and char are TO_DATE() and TO_CHAR():
SELECT
TO_DATE('31/12/2001 23:55:00', 'DD/MM/YYYY HH24:MI:SS') AS "DATE",
TO_CHAR(CURRENT_TIMESTAMP, 'DD/MM/YYYY HH24:MI:SS') AS "CHAR"
FROM DUAL
So you can do:
SELECT
TO_DATE('23:45', 'HH24:MI'),
TO_DATE('23:45', 'HH24:MI') + INTERVAL '45' MINUTE,
TO_CHAR(TO_DATE('23:45', 'HH24:MI') + interval '45' MINUTE, 'HH24:MI')
FROM DUAL
There're possibly other better ways to do it (I'm not sure this will work as expected if ran when DST is about to start) but I'm still learning :)