Oracle shifts in work with dates - oracle

Can you help me with shifts? I need to assign each event what shift it is.
I want to count how many items machine done in every shift. "ILE" means "HOW MANY ITEMS IN SHIFT WERE DONE"
SELECT lz.EVENT,
TO_CHAR(lz.DATA_ZATW, 'YYYY-MM-DD') AS DATA,
CASE WHEN TO_CHAR(lz.DATA_ZATW, 'HH24:MI') BETWEEN '06:00' AND '13:59' THEN 'First Shift'
WHEN TO_CHAR(lz.DATA_ZATW, 'HH24:MI') BETWEEN '14:00' AND '21:59' THEN 'Second Shift'
WHEN TO_CHAR(lz.DATA_ZATW, 'HH24:MI') BETWEEN '22:00' AND '23:59' THEN 'Third Shift'
WHEN TO_CHAR(lz.DATA_ZATW, 'HH24:MI') BETWEEN '00:00' AND '05:59' THEN 'Third Shift'
END AS SHIFT
FROM PLC.LIST lz;
But when I check now query and I have third shift of 2017-08-03 and it is wrong because according to sysdate I shound have first shift only.
Any idea?
EDIT:
Whole query
SELECT "DATA",
"ZMIANA",
"SOV_GAO_1_ILE",
"SOV_GAD_2_ILE",
"SOV_GAM_3_ILE"
FROM (SELECT TO_CHAR(lz.DATA_ZATW, 'YYYY-MM-DD') AS DATA,
CASE WHEN TO_CHAR(lz.DATA_ZATW, 'HH24:MI:SS') BETWEEN '06:00:00' AND '13:59:59.999999' THEN 1
WHEN TO_CHAR(lz.DATA_ZATW, 'HH24:MI:SS') BETWEEN '14:00:00' AND '21:59:59.999999' THEN 2
WHEN TO_CHAR(lz.DATA_ZATW, 'HH24:MI:SS') BETWEEN '22:00:00' AND '23:59:59.999999' THEN 3
WHEN TO_CHAR(lz.DATA_ZATW, 'HH24:MI:SS') BETWEEN '00:00:00' AND '05:59:59.999999' THEN 3
END AS ZMIANA,
lz.LINIA,
lz.DETAL
FROM PLC.LISTA_ZDARZEN lz
GROUP BY lz.DATA_ZATW,
lz.LINIA,
lz.DETAL) PIVOT (COUNT(DETAL) AS ILE FOR LINIA IN ('SOV_GAO_1' SOV_GAO_1, 'SOV_GAD_2' SOV_GAD_2, 'SOV_GAM_3' SOV_GAM_3));
EDIT:
SHIFTS
6-14 01.08 first shift
14-22 01.08 second shift
22-00 01.08 third shift
00-6 02.08 third shift
6-14 02.08 first shift
14-22 02.08 second shift
22-00 02.08 third shift
00-6 03.08 third shift
6-14 03.08 first shift
14-22 03.08 second shift
22-00 03.08 third shift
00-6 04.08 third shift
HERE ARE DATES:
SELECT TO_DATE('2017-08-01 23:54:56', 'yyyy-mm-dd hh24:mi:ss') FROM dual UNION ALL -- 01.08 Third shift
SELECT TO_DATE('2017-08-01 23:57:58', 'yyyy-mm-dd hh24:mi:ss') FROM dual UNION ALL -- 01.08 Third shift
SELECT TO_DATE('2017-08-02 03:54:56', 'yyyy-mm-dd hh24:mi:ss') FROM dual UNION ALL -- 01.08 Third shift
SELECT TO_DATE('2017-08-02 04:54:56', 'yyyy-mm-dd hh24:mi:ss') FROM dual UNION ALL -- 01.08 Third shift
SELECT TO_DATE('2017-08-02 06:54:56', 'yyyy-mm-dd hh24:mi:ss') FROM dual UNION ALL -- 02.08 First shift
SELECT TO_DATE('2017-08-02 07:54:56', 'yyyy-mm-dd hh24:mi:ss') FROM dual UNION ALL -- 02.08 First shift
SELECT TO_DATE('2017-08-02 10:24:34', 'yyyy-mm-dd hh24:mi:ss') FROM dual UNION ALL -- 02.08 First shift
SELECT TO_DATE('2017-08-02 14:54:56', 'yyyy-mm-dd hh24:mi:ss') FROM dual UNION ALL -- 02.08 Second shift
SELECT TO_DATE('2017-08-02 15:54:56', 'yyyy-mm-dd hh24:mi:ss') FROM dual UNION ALL -- 02.08 Second shift
SELECT TO_DATE('2017-08-02 19:21:10', 'yyyy-mm-dd hh24:mi:ss') FROM dual UNION ALL -- 02.08 Second shift
SELECT TO_DATE('2017-08-02 22:54:56', 'yyyy-mm-dd hh24:mi:ss') FROM dual UNION ALL -- 02.08 Third shift
SELECT TO_DATE('2017-08-02 23:55:20', 'yyyy-mm-dd hh24:mi:ss') FROM dual UNION ALL -- 02.08 Third shift
SELECT TO_DATE('2017-08-02 23:55:56', 'yyyy-mm-dd hh24:mi:ss') FROM dual UNION ALL -- 02.08 Third shift
SELECT TO_DATE('2017-08-03 00:02:34', 'yyyy-mm-dd hh24:mi:ss') FROM dual UNION ALL -- 02.08 Third shift
SELECT TO_DATE('2017-08-03 00:05:34', 'yyyy-mm-dd hh24:mi:ss') FROM dual UNION ALL -- 02.08 Third shift
SELECT TO_DATE('2017-08-03 00:10:38', 'yyyy-mm-dd hh24:mi:ss') FROM dual UNION ALL -- 02.08 Third shift
SELECT TO_DATE('2017-08-03 09:01:24', 'yyyy-mm-dd hh24:mi:ss') FROM dual UNION ALL -- 03.08 First shift
SELECT TO_DATE('2017-08-03 09:01:32', 'yyyy-mm-dd hh24:mi:ss') FROM DUAL UNION ALL -- 03.08 First shift
SELECT TO_DATE('2017-08-03 17:01:10', 'yyyy-mm-dd hh24:mi:ss') FROM dual UNION ALL -- 03.08 Second shift
SELECT TO_DATE('2017-08-03 19:28:45', 'yyyy-mm-dd hh24:mi:ss') FROM DUAL UNION ALL -- 03.08 Second shift
SELECT TO_DATE('2017-08-03 23:54:56', 'yyyy-mm-dd hh24:mi:ss') FROM dual UNION ALL -- 03.08 Third shift
SELECT TO_DATE('2017-08-03 23:55:20', 'yyyy-mm-dd hh24:mi:ss') FROM dual UNION ALL -- 03.08 Third shift
SELECT TO_DATE('2017-08-03 23:55:56', 'yyyy-mm-dd hh24:mi:ss') FROM DUAL -- 03.08 Third shift

Maybe try this:
CASE WHEN TO_CHAR(lz.DATA_ZATW, 'HH24MI') BETWEEN 600 AND 1359 THEN 'First Shift'
WHEN TO_CHAR(lz.DATA_ZATW, 'HH24MI') BETWEEN 1400 AND 2159 THEN 'Second Shift'
WHEN TO_CHAR(lz.DATA_ZATW, 'HH24MI') BETWEEN 2200 AND 2359 THEN 'Third Shift'
WHEN TO_CHAR(lz.DATA_ZATW, 'HH24MI') BETWEEN 0 AND 559 THEN 'Third Shift'
END AS SHIFT
or like this:
CASE WHEN (lz.DATA_ZATW - TRUNC(lz.DATA_ZATW)) * INTERVAL '1' DAY BETWEEN INTERVAL '6' HOUR AND INTERVAL '13:59:59.999999' HOUR TO SECOND THEN 'First Shift'
CASE WHEN (lz.DATA_ZATW - TRUNC(lz.DATA_ZATW)) * INTERVAL '1' DAY BETWEEN INTERVAL '14' HOUR AND INTERVAL '21:59:59.999999' HOUR TO SECOND THEN 'Second Shift'
...
According to your sample data it works:
WITH t (DATA_ZATW) AS (
SELECT TO_DATE('2017-08-03 09:03:31', 'yyyy-mm-dd hh24:mi:ss') FROM dual UNION ALL
SELECT TO_DATE('2017-08-03 09:03:11', 'yyyy-mm-dd hh24:mi:ss') FROM dual UNION ALL
SELECT TO_DATE('2017-08-03 09:03:07', 'yyyy-mm-dd hh24:mi:ss') FROM dual UNION ALL
SELECT TO_DATE('2017-08-03 09:02:44', 'yyyy-mm-dd hh24:mi:ss') FROM dual UNION ALL
SELECT TO_DATE('2017-08-03 09:02:22', 'yyyy-mm-dd hh24:mi:ss') FROM dual UNION ALL
SELECT TO_DATE('2017-08-03 09:02:21', 'yyyy-mm-dd hh24:mi:ss') FROM dual UNION ALL
SELECT TO_DATE('2017-08-03 09:01:58', 'yyyy-mm-dd hh24:mi:ss') FROM dual UNION ALL
SELECT TO_DATE('2017-08-03 09:01:32', 'yyyy-mm-dd hh24:mi:ss') FROM dual UNION ALL
SELECT TO_DATE('2017-08-03 09:01:24', 'yyyy-mm-dd hh24:mi:ss') FROM dual)
SELECT DATA_ZATW,
CASE
WHEN TO_CHAR(DATA_ZATW, 'HH24MI') BETWEEN 600 AND 1359 THEN 'First Shift'
WHEN TO_CHAR(DATA_ZATW, 'HH24MI') BETWEEN 1400 AND 2159 THEN 'Second Shift'
WHEN TO_CHAR(DATA_ZATW, 'HH24MI') BETWEEN 2200 AND 2359 THEN 'Third Shift'
WHEN TO_CHAR(DATA_ZATW, 'HH24MI') BETWEEN 0 AND 559 THEN 'Third Shift'
END AS SHIFT
FROM t;
DATA_ZATW SHIFT
03.08.2017 09:03:31 First Shift
03.08.2017 09:03:11 First Shift
03.08.2017 09:03:07 First Shift
03.08.2017 09:02:44 First Shift
03.08.2017 09:02:22 First Shift
03.08.2017 09:02:21 First Shift
03.08.2017 09:01:58 First Shift
03.08.2017 09:01:32 First Shift
03.08.2017 09:01:24 First Shift
I assume at the end you are looking for something like this:
WITH t (DATA_ZATW) AS (
SELECT TO_DATE('2017-08-03 09:03:31', 'yyyy-mm-dd hh24:mi:ss') FROM dual UNION ALL
SELECT TO_DATE('2017-08-03 09:03:11', 'yyyy-mm-dd hh24:mi:ss') FROM dual UNION ALL
SELECT TO_DATE('2017-08-03 09:03:07', 'yyyy-mm-dd hh24:mi:ss') FROM dual UNION ALL
SELECT TO_DATE('2017-08-03 09:02:44', 'yyyy-mm-dd hh24:mi:ss') FROM dual UNION ALL
SELECT TO_DATE('2017-08-03 09:02:22', 'yyyy-mm-dd hh24:mi:ss') FROM dual UNION ALL
SELECT TO_DATE('2017-08-03 09:02:21', 'yyyy-mm-dd hh24:mi:ss') FROM dual UNION ALL
SELECT TO_DATE('2017-08-03 09:01:58', 'yyyy-mm-dd hh24:mi:ss') FROM dual UNION ALL
SELECT TO_DATE('2017-08-03 09:01:32', 'yyyy-mm-dd hh24:mi:ss') FROM dual UNION ALL
SELECT TO_DATE('2017-08-03 09:01:24', 'yyyy-mm-dd hh24:mi:ss') FROM dual)
SELECT TRUNC(DATA_ZATW), SHIFT, COUNT(*)
FROM
(
SELECT DATA_ZATW,
CASE
WHEN TO_CHAR(DATA_ZATW, 'HH24MI') BETWEEN 600 AND 1359 THEN 'First Shift'
WHEN TO_CHAR(DATA_ZATW, 'HH24MI') BETWEEN 1400 AND 2159 THEN 'Second Shift'
WHEN TO_CHAR(DATA_ZATW, 'HH24MI') BETWEEN 2200 AND 2359 THEN 'Third Shift'
WHEN TO_CHAR(DATA_ZATW, 'HH24MI') BETWEEN 0 AND 559 THEN 'Third Shift'
END AS SHIFT
FROM t
)
GROUP BY TRUNC(DATA_ZATW), SHIFT;

I think that the only thing You have to do is to substract six hours from data_zatw to assign it to previous day.
select data_zatw, trunc(data_zatw - interval '6' hour) shift_date,
case when to_char(data_zatw, 'HH24') >= '06'
and to_char(data_zatw, 'HH24') < '14' then 1
when to_char(data_zatw, 'HH24') >= '14'
and to_char(data_zatw, 'HH24') < '22' then 2
when to_char(data_zatw, 'HH24') >= '22'
or to_char(data_zatw, 'HH24') < '06' then 3
end shift
from lz
Then make your pivot and aggregations and pivot.
Test data:
with lz as (
select to_date(column_value, 'yyyy-mm-dd hh24:mi:ss') data_zatw
from table(
sys.odcivarchar2list(
'2017-08-01 23:54:56', '2017-08-01 23:57:58', '2017-08-02 03:54:56',
'2017-08-02 04:54:56', '2017-08-02 06:54:56', '2017-08-02 07:54:56',
'2017-08-02 10:24:34', '2017-08-02 14:54:56', '2017-08-02 15:54:56',
'2017-08-02 19:21:10', '2017-08-02 22:54:56', '2017-08-02 23:55:20',
'2017-08-02 23:55:56', '2017-08-03 00:02:34', '2017-08-03 00:05:34',
'2017-08-03 00:10:38', '2017-08-03 09:01:24', '2017-08-03 09:01:32',
'2017-08-03 17:01:10', '2017-08-03 19:28:45', '2017-08-03 23:54:56',
'2017-08-03 23:55:20', '2017-08-03 23:55:56')))
select data_zatw, trunc(data_zatw - interval '6' hour) shift_date,
case when to_char(data_zatw, 'HH24') >= '06'
and to_char(data_zatw, 'HH24') < '14' then 1
when to_char(data_zatw, 'HH24') >= '14'
and to_char(data_zatw, 'HH24') < '22' then 2
when to_char(data_zatw, 'HH24') >= '22'
or to_char(data_zatw, 'HH24') < '06' then 3
end shift
from lz

Related

calculate the running total over the column contain date difference in HH:MI:SS format in oracle

I have to find the running total over the column interval.
SELECT
( ( EXTRACT(DAY FROM intrvl) * 24 ) + ( EXTRACT(HOUR FROM intrvl) ) ) ||':'||
EXTRACT(MINUTE FROM intrvl) ||':'||
EXTRACT(SECOND FROM intrvl) ||':'|| as interval
FROM
(
SELECT
( to_timestamp(TO_CHAR(date_column_name,'dd-mon-rrrr hh:mi:ss') ) ) - ( to_timestamp(TO_CHAR(date_column_name,'dd-mon-rrrr hh:mi:ss') ) ) intrvl
FROM
dual
);
currrently Interval column of table has below data:
Interval(HH:mi:ss)
0:4:23
696:1:36
696:4:51
8760:1:18
The best I can come up with is this. Note that the interval data type does not take a format model for displaying - you can't force an interval of 25 hours to be displayed as 25:00:00 (although you can use that to INPUT an interval). Instead, it will be shown as 01 01:00:00 (meaning, a day and an hour).
with
tbl (interv) as (
select interval '0:4:23' hour(9) to second from dual union all
select interval '696:1:36' hour(9) to second from dual union all
select interval '696:4:51' hour(9) to second from dual union all
select interval '8760:1:18' hour(9) to second from dual
)
select interval '1' day * sum(date '2000-01-01' + interv - date'2000-01-01')
as sum_interv
from tbl;
SUM_INTERV
--------------------
+423 00:12:08.000000
In your original attempt you were trying to get a STRING output. I am not sure that's wise, but if that's what you need you can do it like so:
with
tbl (interv) as (
select interval '0:4:23' hour(9) to second from dual union all
select interval '696:1:36' hour(9) to second from dual union all
select interval '696:4:51' hour(9) to second from dual union all
select interval '8760:1:18' hour(9) to second from dual
)
, prep (sum_interv) as (
select interval '1' day * sum(date '2000-01-01' + interv - date'2000-01-01')
from tbl
)
select to_char( extract(day from sum_interv) * 24
+ extract(hour from sum_interv), 'fm999999999' ) || ':' ||
to_char( extract(minute from sum_interv), 'fm00' ) || ':' ||
to_char( extract(second from sum_interv), 'fm00' ) as sum_interv
from prep
;
SUM_INTERV
------------------
10152:12:08

Want to round the data

My Query is :
SELECT TO_CHAR((to_date('01-01-2018 00:00:00','DD-MM-YYYY HH24:MI:SS')+ (level-1)),'DD-MM-YYYY'),
TO_CHAR(to_date('01-01-2018 00:00:00','DD-MM-YYYY HH24:MI:SS') + level,'DD-MM-YYYY') ,
to_number(regexp_substr('7000 T', '^\d+'))/(TO_DATE('04-01-2018 00:00:00', 'DD-MM-YYYY HH24:MI:SS') - TO_DATE('01-01-2018 00:00', 'DD-MM-YYYY HH24:MI:SS'))
|| regexp_substr('7000 T', '[A-Z]') AS IP_PLAN
FROM dual
CONNECT BY level <= to_date('04-01-2018 00:00:00','DD-MM-YYYY HH24:MI:SS')-to_date('01-01-2018 00:00:00','DD-MM-YYYY HH24:MI:SS');
I want IP_PLAN like: 2333 T
ROUND(('7000 T'), '[A-Z]') is trying to round a string value, i.e. the T that is extracted from that source string, which doesn't make sense.
You need to round the number you generated just before that:
select to_char(to_date('01-01-2018 00:00:00', 'DD-MM-YYYY HH24:MI:SS') + level - 1,
'DD-MM-YYYY'),
to_char(to_date('01-01-2018 00:00:00', 'DD-MM-YYYY HH24:MI:SS') + level,
'DD-MM-YYYY') ,
round(
to_number(regexp_substr('7000 T', '^[[:digit:]]+'))
/ (to_date('04-01-2018 00:00:00', 'DD-MM-YYYY HH24:MI:SS')
- to_date('01-01-2018 00:00', 'DD-MM-YYYY HH24:MI:SS'))
)
|| regexp_substr('7000 T', '[^[:digit:]]*$') as ip_plan_consumption
from dual
connect by level <= to_date('04-01-2018 00:00:00', 'DD-MM-YYYY HH24:MI:SS')
- to_date('01-01-2018 00:00:00', 'DD-MM-YYYY HH24:MI:SS');
TO_CHAR(TO TO_CHAR(TO IP_PLAN_CONSUMPTION
---------- ---------- ------------------------------------------
01-01-2018 02-01-2018 2333 T
02-01-2018 03-01-2018 2333 T
03-01-2018 04-01-2018 2333 T
so you're doing
round(<number extracted by regex> / <difference in days >)
which is
round(7000 / 3) => round(2333.333...) => 2333
and then appending the T after wards.
I've changed the regex patterns slightly so it picks up the space ans any characters at the end. That's making some assumptions about possible values in that string though - i.e. that it's always one number followed by one non-numeric section.
Incidentally, if you're using fixed dates then it's simpler to use date literals:
select to_char(date '2018-01-01' + level - 1, 'DD-MM-YYYY'),
to_char(date '2018-01-01' + level, 'DD-MM-YYYY') ,
round(
to_number(regexp_substr('7000 T', '^[[:digit:]]+'))
/ (date '2018-01-04' - date '2018-01-01')
)
|| regexp_substr('7000 T', '[^[:digit:]]*$') as ip_plan_consumption
from dual
connect by level <= date '2018-01-04' - date '2018-01-01';
though I imagine the 7000 T and the date values are all being passed in as string in your real code so they need to be converted. You could use a CTE to only convert them once though, instead of repeatedly as you loop round.
SELECT TO_CHAR((to_date('01-01-2018 00:00:00','DD-MM-YYYY HH24:MI:SS')+ (level-1)),'DD-MM-YYYY'),
TO_CHAR(to_date('01-01-2018 00:00:00','DD-MM-YYYY HH24:MI:SS') + level,'DD-MM-YYYY') ,
round(to_number(regexp_substr('7000 T', '^\d+'))/(TO_DATE('04-01-2018 00:00:00', 'DD-MM-YYYY HH24:MI:SS') - TO_DATE('01-01-2018 00:00', 'DD-MM-YYYY HH24:MI:SS')),0)
AS IP_PLAN_CONSUMPTION
FROM dual
CONNECT BY level <= to_date('04-01-2018 00:00:00','DD-MM-YYYY HH24:MI:SS')-to_date('01-01-2018 00:00:00','DD-MM-YYYY HH24:MI:SS');
you have to use T in some other column;

oracle group by date with specific time

some will say "another question from that guy" but here is my Problem. all this works as designed:
with tab1 as (
select to_timestamp( '04.02.15 14:25:21.503000000' ) as dt from dual union all
select to_timestamp( '04.02.15 14:25:25.154000000' ) as dt from dual union all
select to_timestamp( '09.02.15 22:20:36.861000000' ) as dt from dual union all
select to_timestamp( '09.02.15 22:20:36.883000000' ) as dt from dual union all
select to_timestamp( '10.02.15 04:19:13.839000000' ) as dt from dual union all
select to_timestamp( '10.02.15 04:13:18.142000000' ) as dt from dual union all
select to_timestamp( '10.02.15 12:43:18.171000000' ) as dt from dual union all
select to_timestamp( '11.02.15 04:30:53.654000000' ) as dt from dual union all
select to_timestamp( '11.02.15 22:00:38.951000000' ) as dt from dual union all
select to_timestamp( '11.02.15 22:00:42.014000000' ) as dt from dual union all
select to_timestamp( '16.02.15 08:50:43.967000000' ) as dt from dual union all
select to_timestamp( '16.02.15 16:35:41.387000000' ) as dt from dual union all
select to_timestamp( '16.02.15 16:35:42.835000000' ) as dt from dual union all
select to_timestamp( '17.02.15 04:21:08.542000000' ) as dt from dual union all
select to_timestamp( '17.02.15 04:21:08.912000000' ) as dt from dual union all
select to_timestamp( '17.02.15 04:06:09.818000000' ) as dt from dual union all
select to_timestamp( '17.02.15 04:40:39.411000000' ) as dt from dual union all
select to_timestamp( '18.02.15 04:41:08.218000000' ) as dt from dual union all
select to_timestamp( '18.02.15 03:20:40.609000000' ) as dt from dual union all
select to_timestamp( '18.02.15 01:20:40.712000000' ) as dt from dual union all
select to_timestamp( '20.02.15 06:55:42.185000000' ) as dt from dual union all
select to_timestamp( '20.02.15 12:55:42.364000000' ) as dt from dual union all
select to_timestamp( '20.02.15 12:55:42.518000000' ) as dt from dual union all
select to_timestamp( '20.02.15 12:55:43.874000000' ) as dt from dual union all
select to_timestamp( '20.02.15 14:16:05.080000000' ) as dt from dual union all
select to_timestamp( '20.02.15 18:14:17.630000000' ) as dt from dual union all
select to_timestamp( '22.02.15 21:25:40.683000000' ) as dt from dual union all
select to_timestamp( '22.02.15 21:25:42.046000000' ) as dt from dual union all
select to_timestamp( '23.02.15 12:43:27.246000000' ) as dt from dual
order by dt
),
tab2 as(
select trunc(dt) as leaddate, dt,
case
when dt between (to_timestamp(trunc(dt)) + interval '04:30' hour to minute) and (to_timestamp(trunc(dt)) + interval '28:29' hour to minute) then (dt)
else (dt) - interval '04:30' hour to minute
end as newBaseTime
from tab1
)
select trunc(newBaseTime),
sum(case when ( dt <= to_timestamp(trunc( trunc(dt)),'dd.MM.yy') + interval '17:30' hour to minute) then 1 else 0 end) as beforeTS,
sum(case when ( dt > to_timestamp(trunc( trunc(dt)),'dd.MM.yy') + interval '17:30' hour to minute) then 1 else 0 end) as afterTS
from tab2
group by trunc(newBaseTime)
order by trunc(newBaseTime)
the idea is to Group by days with a "new time base" and check if Dates are before or after a defined daytime. due to contracts days in our company lasts from 4.30a.m. this day to 4.30. next day. my solution above works (with little data), but i guess there is an easier way to get result. any idea?
Not sure exactly what you are trying to do, but you seem stuck on this question... perhaps this is the solution you are looking for?
select dt, trunc(dt - interval '270' minute) as leaddate from tab1
This will preserve the timestamp (showing perhaps "today's" date) but if the time is before 4:30 am, the leaddate will be "yesterday's" date.
If this is NOT what you were looking for, please try to clarify your question.

Return records from first ocurance one day to first occurance next day?

I have a very simple table that logs an event type (#1 through #9) with the timestamp and the shift (days-1,swing-2,grave-3) when it happened. I would like to run a query that gives me all the events from the first day shift event on one date to the first day shift event the very next day.
something like:
select date_dt,event_type,shift
from my_table
where *first occurance* shift#1 and date_dt = *some date*
to
select date_dt,event_type,shift
from my_table
where *first occurance* shift#1 and date_dt = *the next day*`<code>
would this be some type of between statement or a union... just not sure how to return a query that goes from the first event yesterday and stops at the first event today?
thanks for your help.
Chris
You want the between operator
select date_dt,event_type,shift
from mytable
where date_dt between '19-DEC-2013' and
to_date('19-DEC-2013 23:59:59', 'DD-MON-YYYY HH24:MI:SS');
'19-DEC-2013' is the first second of Dec 19, '19-DEC-2013 23:59:59' is the last second of that day.
As you expressed it you wanted no records from the next day, all possible records from just '19-DEC-2013' - the example date.
If you have a table containing the expected start and end times for each shift:
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE my_table ( date_dt,event_type,shift ) AS
SELECT TO_TIMESTAMP ('20-Dec-13 03:23:17.010000', 'DD-Mon-RR HH24:MI:SS.FF'), '2013-12-19 Event 7', 'Security Shift 2' FROM DUAL
UNION ALL SELECT TO_TIMESTAMP ('20-Dec-13 04:59:59.010000', 'DD-Mon-RR HH24:MI:SS.FF'), '2013-12-19 Event 8', 'Security Shift 2' FROM DUAL
UNION ALL SELECT TO_TIMESTAMP ('20-Dec-13 05:30:17.010000', 'DD-Mon-RR HH24:MI:SS.FF'), '2013-12-19 Time Out', 'Security Shift 2' FROM DUAL
UNION ALL SELECT TO_TIMESTAMP ('20-Dec-13 23:29:10.123000', 'DD-Mon-RR HH24:MI:SS.FF'), '2013-12-20 Time In', 'Security Shift 2' FROM DUAL
UNION ALL SELECT TO_TIMESTAMP ('20-Dec-13 23:59:22.111100', 'DD-Mon-RR HH24:MI:SS.FF'), '2013-12-20 Event 1', 'Security Shift 2' FROM DUAL
UNION ALL SELECT TO_TIMESTAMP ('21-Dec-13 00:00:00.000000', 'DD-Mon-RR HH24:MI:SS.FF'), '2013-12-20 Event 2', 'Security Shift 2' FROM DUAL
UNION ALL SELECT TO_TIMESTAMP ('21-Dec-13 02:17:23.333300', 'DD-Mon-RR HH24:MI:SS.FF'), '2013-12-20 Event 3', 'Security Shift 2' FROM DUAL
UNION ALL SELECT TO_TIMESTAMP ('21-Dec-13 04:30:10.444400', 'DD-Mon-RR HH24:MI:SS.FF'), '2013-12-20 Event 4', 'Security Shift 2' FROM DUAL
UNION ALL SELECT TO_TIMESTAMP ('21-Dec-13 05:01:07.123000', 'DD-Mon-RR HH24:MI:SS.FF'), '2013-12-20 Time Out', 'Security Shift 2' FROM DUAL
UNION ALL SELECT TO_TIMESTAMP ('21-Dec-13 23:30:15.123000', 'DD-Mon-RR HH24:MI:SS.FF'), '2013-12-21 Time In', 'Security Shift 2' FROM DUAL
UNION ALL SELECT TO_TIMESTAMP ('21-Dec-13 23:59:59.999999', 'DD-Mon-RR HH24:MI:SS.FF'), '2013-12-21 Event 1', 'Security Shift 2' FROM DUAL
UNION ALL SELECT TO_TIMESTAMP ('22-Dec-13 00:10:00.000000', 'DD-Mon-RR HH24:MI:SS.FF'), '2013-12-21 Event 2', 'Security Shift 2' FROM DUAL
UNION ALL SELECT TO_TIMESTAMP ('22-Dec-13 01:11:11.111111', 'DD-Mon-RR HH24:MI:SS.FF'), '2013-12-21 Event 3', 'Security Shift 2' FROM DUAL
UNION ALL SELECT TO_TIMESTAMP ('22-Dec-13 04:45:45.454545', 'DD-Mon-RR HH24:MI:SS.FF'), '2013-12-21 Event 4', 'Security Shift 2' FROM DUAL;
-- Shift 2 is expected to start at 23:30:00 on the current day and finish at 05:00:00 on the next day.
CREATE TABLE shift_times ( shift, start_time, end_time ) AS
SELECT 'Security Shift 2', TO_DSINTERVAL( '0 23:30:00' ), TO_DSINTERVAL( '1 5:00:00' ) FROM DUAL
Query 1:
-- Find the mid-point of the shift and subtract half-a-day
-- then shift the times so that the event times are an offset
-- from that time. This is used so that the "shifted times" for
-- each shift are all on the same day - even if a shift crosses
-- a day boundary.
WITH shifted_dates AS (
SELECT date_dt - ( start_time + end_time )/2 + TO_DSINTERVAL( '0 12:00:00' ) AS shifted_date,
date_dt,
m.shift,
event_type
FROM my_table m
INNER JOIN
shift_times s
ON ( m.shift = s.shift )
WHERE m.shift = 'Security Shift 2'
),
-- Extract the year-month-day of the shift and conver it to a date.
days AS (
SELECT TO_DATE( EXTRACT( YEAR FROM shifted_date )
|| '-' || EXTRACT ( MONTH FROM shifted_date )
|| '-' || EXTRACT ( DAY FROM shifted_date )
, 'YYYY-MM-DD' ) AS day,
date_dt,
shift,
event_type
FROM shifted_dates
)
-- Select the events for the required day
-- plus the first event of the following day.
SELECT date_dt,
shift,
event_type
FROM days
WHERE day = TO_DATE( '2013-12-20', 'YYYY-MM-DD' )
UNION ALL
SELECT MIN( date_dt ) KEEP ( DENSE_RANK FIRST ORDER BY date_dt ),
MIN( shift ) KEEP ( DENSE_RANK FIRST ORDER BY date_dt ),
MIN( event_type ) KEEP ( DENSE_RANK FIRST ORDER BY date_dt )
FROM days
WHERE day = TO_DATE( '2013-12-20', 'YYYY-MM-DD' ) + INTERVAL '1' DAY
ORDER BY date_dt
Results:
| DATE_DT | SHIFT | EVENT_TYPE |
|---------------------------------|------------------|---------------------|
| December, 20 2013 23:29:10+0000 | Security Shift 2 | 2013-12-20 Time In |
| December, 20 2013 23:59:22+0000 | Security Shift 2 | 2013-12-20 Event 1 |
| December, 21 2013 00:00:00+0000 | Security Shift 2 | 2013-12-20 Event 2 |
| December, 21 2013 02:17:23+0000 | Security Shift 2 | 2013-12-20 Event 3 |
| December, 21 2013 04:30:10+0000 | Security Shift 2 | 2013-12-20 Event 4 |
| December, 21 2013 05:01:07+0000 | Security Shift 2 | 2013-12-20 Time Out |
| December, 21 2013 23:30:15+0000 | Security Shift 2 | 2013-12-21 Time In |
If you don't have a table of shift start and end times then you can just pass that into the query as bind variables.

Oracle PLSQL truncate datetime to specific hours

I have an Oracle PLSQL code generating a list of datetime stamps and I would like to truncate them to the specific hours of 7am and 7pm rather than the beginning of the day.
For example:
01/03/2013 0700 becomes 01/03/2013 0700
01/03/2013 1235 becomes 01/03/2013 0700
01/03/2013 1932 becomes 01/03/2013 1900
02/03/2013 0612 becomes 01/03/2013 1900
My code is currently:
SELECT TRUNC(TRUNC(SYSDATE,'hh') + 1/24 - (ROWNUM) / 24, 'dd') as shift_date
FROM widsys.times
ORDER BY SYSDATE
Thanks
Without conditionals :)
Select your_date,
trunc(your_date - 7/24) + --the date
trunc(to_char(your_date - 7/24,'hh24')/12)/2 + --wich half of day
7/24 --shift the hour
from
your_table;
See a fiddle.
with data(time) as (
select to_date('2013-09-19 00:00:00', 'YYYY-MM-DD HH24:MI:SS') from dual union all
select to_date('2013-09-19 06:45:44', 'YYYY-MM-DD HH24:MI:SS') from dual union all
select to_date('2013-09-19 08:12:25', 'YYYY-MM-DD HH24:MI:SS') from dual union all
select to_date('2013-09-19 18:59:59', 'YYYY-MM-DD HH24:MI:SS') from dual union all
select to_date('2013-09-19 19:00:00', 'YYYY-MM-DD HH24:MI:SS') from dual union all
select to_date('2013-09-19 20:15:35', 'YYYY-MM-DD HH24:MI:SS') from dual union all
select to_date('2013-09-19 23:59:59', 'YYYY-MM-DD HH24:MI:SS') from dual
)
select d.time,
case
when to_number(to_char(d.time, 'HH24')) >= 19 then
trunc(d.time) + 19/24
when to_number(to_char(d.time, 'HH24')) >= 7 then
trunc(d.time) + 7/24
else
trunc(d.time - 1) + 19/24
end as shift_date
from data d
;
Are you looking for a query like this:
SELECT CASE
WHEN TO_CHAR(your_date, 'hh24') > 12
THEN TRUNC(your_date)+ 19/24
ELSE TRUNC(your_date)+ 7/24
END
FROM your_table;

Resources