How to write a date & time shift query? - sql

Can someone please help me with writing a CASE query. Using the column name PERFORM_DT_TM - date & time format "MM-DD-YYYY HH-MI-SS"
Table name PERFORM_RESULT
The result I want is something like this:
BETWEEN'06:00:00'AND'14:29:59' THEN 'First Shift'
BETWEEN'14:30:00'AND'22:59:59' THEN 'Second Shift'
BETWEEN '23:00:00' AND'05:59:59' THEN 'Third Shift'
ELSE 'UNKNOWN'

You can use to_char(PERFORM_RESULT, 'HH24:MI') to get the hours and minutes from the date; the seconds aren't needed for this.
For 23:00 to 05:59 you need to check two ranges, because BETWEEN doesn't know about clock wraparound, it's just doing a textual comparison.
SELECT CASE
WHEN to_char(PERFORM_DT_TM, 'HH24:MI') BETWEEN '06:00' AND '14:29' THEN 'First Shift'
WHEN to_char(PERFORM_DT_TM, 'HH24:MI') BETWEEN '14:30' AND '22:59' THEN 'Second Shift'
WHEN to_char(PERFORM_DT_TM, 'HH24:MI') BETWEEN '23:00' AND '23:59' THEN 'Third Shift'
WHEN to_char(PERFORM_DT_TM, 'HH24:MI') BETWEEN '00:00' AND '05:59' THEN 'Third Shift'
ELSE 'UNKNOWN'
END
You can also take advantage of the fact that cases are tested sequentially to simplify it, since you don't have to check the beginning of a range if that has been excluded by the previous case.
SELECT CASE
WHEN to_char(PERFORM_DT_TM, 'HH24:MI') <= '05:59' THEN 'Third Shift'
WHEN to_char(PERFORM_DT_TM, 'HH24:MI') <= '14:29' THEN 'First Shift'
WHEN to_char(PERFORM_DT_TM, 'HH24:MI') <= '22:59' THEN 'Second Shift'
WHEN to_char(PERFORM_DT_TM, 'HH24:MI') <= '23:59' THEN 'Third Shift'
ELSE 'UNKNOWN'
END

Assuming this is for Oracle, and assuming that the PERFORM_DT_TM column is datatype DATE...
We can use the TO_CHAR function to format the time portion. For example:
TO_CHAR( t.perform_dt_tm,'HH24:MI' )
And we can do string comparisons in a CASE expression. For example:
SELECT CASE
WHEN TO_CHAR(t.perform_dt_tm,'HH24:MI') >= '06:00'
AND TO_CHAR(t.perform_dt_tm,'HH24:MI') < '14:30'
THEN 'First Shift'
WHEN TO_CHAR(t.perform_dt_tm,'HH24:MI') >= '14:30'
AND TO_CHAR(t.perform_dt_tm,'HH24:MI') < '23:00'
THEN 'Second Shift'
WHEN TO_CHAR(t.perform_dt_tm,'HH24:MI') >= '23:00'
OR TO_CHAR(t.perform_dt_tm,'HH24:MI') < '06:00'
THEN 'Third Shift'
ELSE 'Unknown'
END AS which_shift
, t.perform_dt_tm
, ...
FROM ... t
NOTE: This is based on the assumption that datatype of the column is DATE, and that this is for Oracle. If the column is a different datatype, then we'd need to adjust how the "time" portion is extracted.
The TO_CHAR function is specific to Oracle. If this is for a database other than Oracle, we would need to adjust the expression that extracts the time portion. (e.g. DATE_FORMAT for MySQL)
An equivalent result can be obtained more concisely:
SELECT CASE
WHEN TO_CHAR(t.perform_dt_tm,'HH24') < '06:00'
THEN 'Third Shift'
WHEN TO_CHAR(t.perform_dt_tm,'HH24:MI') < '14:30'
THEN 'First Shift'
WHEN TO_CHAR(t.perform_dt_tm,'HH24') < '23:00'
THEN 'Second Shift'
WHEN TO_CHAR(t.perform_dt_tm,'HH24') < '24:00'
THEN 'Third Shift'
ELSE 'Unknown'
END AS which_shift
, t.perform_dt_tm
, ...
FROM ... t

Oracle Setup:
CREATE TABLE PERFORM_RESULT ( PERFORM_DT_TM DATE );
INSERT INTO PERFORM_RESULT
SELECT TIMESTAMP '2016-05-23 00:00:00' FROM DUAL UNION ALL
SELECT TIMESTAMP '2016-05-21 12:00:00' FROM DUAL UNION ALL
SELECT TIMESTAMP '2016-05-19 15:00:00' FROM DUAL;
Query 1 - Comparing using fractions of a day:
SELECT PERFORM_DT_TM,
CASE WHEN time >= 6/24 AND time < 14.5/24 THEN 'First Shift'
WHEN time >= 14.5/24 AND time < 23/24 THEN 'Second Shift'
ELSE 'Third Shift'
END AS shift
FROM (
SELECT PERFORM_DT_TM,
PERFORM_DT_TM - TRUNC( PERFORM_DT_TM ) AS time
FROM PERFORM_RESULT
);
Query 2 - Comparing using intervals:
SELECT PERFORM_DT_TM,
CASE WHEN time >= INTERVAL '6' HOUR
AND time < INTERVAL '14' HOUR + INTERVAL '30' MINUTE
THEN 'First Shift'
WHEN time >= INTERVAL '14' HOUR + INTERVAL '30' MINUTE
AND time < INTERVAL '23' HOUR
THEN 'Second Shift'
ELSE 'Third Shift'
END AS shift
FROM (
SELECT PERFORM_DT_TM,
NUMTODSINTERVAL( PERFORM_DT_TM - TRUNC( PERFORM_DT_TM ), 'DAY' ) AS time
FROM PERFORM_RESULT
);
(or you could just convert all the times to minute intervals - i.e. INTERVAL '360' MINUTE, INTERVAL '870' MINUTE and INTERVAL '1380' MINUTE as the boundaries)
Output:
(Both output the same results)
PERFORM_DT_TM SHIFT
------------------- ------------
2016-05-23 00:00:00 Third Shift
2016-05-21 12:00:00 First Shift
2016-05-19 15:00:00 Second Shift

Assuming PERFORM_DT_TM is in datetime datatype (as it should be), you don't need a format model like 'MM-DD-YYYY' or similar; and you are best off using numeric comparisons rather than lexicographic.
The time of day is PERFORM_DT_TM - trunc(PERFORM_DT_TM). trunc keeps the same date but truncates the time portion back to 00:00:00 AM, so the difference is just the time component of the datetime stored in PERFORM_DT_TM. However, this "time component" is expressed as a fraction of 1 day; to compare to hours, divide the hours by 24 (or alternatively, multiply the time differences by 24; I illustrate the first choice below).
Assuming your table name is MY_TABLE, your case expression can be written (using the "with clause" available in Oracle 11.1 and above) as follows:
with p as (
select PERFORM_DT_TM - trunc(PERFORM_DT_TM) as PERF_TM [, other columns]
from MY_TABLE
)
select [other columns, perhaps PERF_TM,]
case
when PERF_TM >= 6/24 and PERF_TM < 14.5/24 then "First Shift"
when PERF_TM >= 14.5/24 and PERF_TM < 23/24 then "Second Shift"
when PERF_TM < 6/24 or PERF_TM >= 23/24 then "Third Shift"
else "Error/Unknown"
end as SHIFT
from p;

Related

Case when time is beween and on weekends

I am trying to do a case when on one of my columns, but the time has to be between two times during the week and different on the weekends. So if sched_time is between 8:30:00 and 14:45:00 during the week (M-F) then 'ABC' else 'DEF'. The sched_time column looks like this 2020-03-27 09:29:00. Here is what I have so far:
SELECT Client_Last_Name,
Client_First_Name,
Sched_Time,
CASE WHEN Sched_time IS BETWEEN '08:30:00' AND '14:45:00'
THEN 'ABC'
ELSE 'DEF'
END
Field_Name,
Recoded_Response,
Dlsequence
FROM DAILY_LOG_CUSTOM_DATA
WHERE SERVICE_NAME = 'Medical'
AND FIELD_CATEGORY = 'Background Information'
AND Field_Name = 'Restraint?'
AND Recoded_Response = 1
And Sched_Time >= TRUNC(SYSDATE + 1, 'IW') - 8 AND
Sched_Time <= TRUNC(SYSDATE + 1, 'IW') - 1
Assuming that SCHED_TIME is of type DATE then you can take advantage of INTERVAL arithmetic:
SELECT Client_Last_Name,
Client_First_Name,
Sched_Time,
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
Field_Name,
Recoded_Response,
Dlsequence
FROM DAILY_LOG_CUSTOM_DATA
WHERE SERVICE_NAME = 'Medical'
AND FIELD_CATEGORY = 'Background Information'
AND Field_Name = 'Restraint?'
AND Recoded_Response = 1
AND Sched_Time >= TRUNC(SYSDATE + 1, 'IW') - 8 AND
Sched_Time <= TRUNC(SYSDATE + 1, 'IW') - 1
You can use to_char(). Assuming English language settings:
CASE WHEN TO_CHAR(Sched_time, 'HH24:MI:SS') BETWEEN '08:30:00' AND '14:45:00' AND
TO_CHAR(Sched_time, 'DY') NOT IN ('SAT', 'SUN')
THEN 'ABC'
ELSE 'DEF'
END
You can adjust this to include international settings, so the value is in English -- or your native language -- if that is preferable.

Case statement based on the time

I have the following table
Based on the transaction_DT:
if the transaction between 04:00:00 PM to 08:00:00 AM + next day get "After Hour"
Between 08:00:00 AM to 04:00:00 PM within same day get "Working Hour"
Using the case statement it is not works!
CASE
WHEN ( Transacton_DT >= TO_DATE ('4:00:00 PM', 'HH:MI:SS PM')
AND Transacton_DT <= TO_DATE ('11:59:00 PM', 'HH:MI:SS PM') )
OR ( Transacton_DT >= TO_DATE ('12:01:00 AM', 'HH:MI:SS AM')
AND Transacton_DT <= TO_DATE('8:00:00 AM', 'HH:MI:SS AM') )
THEN
'After Hour'
ELSE
'Working Hour'
END AS "Shift"
Hmmm . . . how about something like this:
(case when to_char(transaction_dt, 'HH24:MI') between '08:00' and '16:00'
then 'Working hours' else 'After hours'
end)
Your code doesn't work because you are comparing a value with a time component only (well a default date component) to one with a date component.
case
when to_char(transaction_dt, 'HH24:MI') between '08:00' and '23:59'
or to_char(transaction_dt, 'HH24:MI') between '00:00' and '07:59'
then 'Working hours'
else 'After hours' end

Query date and specific time in the where clause

I'm looking for some help in Oracle SQL. I need to query date and time in the where clause to find shift data based on current date. There are 3 shifts, 5am to 1pm, 1pm to 9pm and 9pm to 5am(next day morning. For example
SELECT 'T1' AS SHIFT, WORK_CENTER, SUM(CASE WHEN AQL='PASS' THEN 1 ELSE 0) END AS AQL_PASSED
FROM Z_INSPECTION_DEFECTS
WHERE DATE_TIME >= TO_DATE((SELECT CONCAT(TO_CHAR(CURRENT_DATE, ''DD-MON-YYYY''), '' 5:00:00 '') FROM DUAL) , ''DD-MON-YYYY HH:MI:SS '') AND
DATE_TIME < TO_DATE((SELECT CONCAT(TO_CHAR(CURRENT_DATE, ''DD-MON-YYYY''), '' 1:00:00 '') FROM DUAL) , ''DD-MON-YYYY HH:MI:SS '')
I do not get any results from this query. The date time field is a timestamp on local Los Angeles time.
The immediate problem is that you're looking dor times that are after 5am and before 1am, which logically means nothing matches - as no time can fulfil both at once. You can use 24-hour times instead:
WHERE DATE_TIME >= TO_DATE((SELECT CONCAT(TO_CHAR(CURRENT_DATE, ''DD-MON-YYYY''), '' 5:00:00 '') FROM DUAL) , ''DD-MON-YYYY HH24:MI:SS '') AND
DATE_TIME < TO_DATE((SELECT CONCAT(TO_CHAR(CURRENT_DATE, ''DD-MON-YYYY''), ''13:00:00 '') FROM DUAL) , ''DD-MON-YYYY HH24:MI:SS '')
But there are other ways to get those, e.g. just without the queries against dual:
WHERE DATE_TIME >= TO_DATE(TO_CHAR(CURRENT_DATE, ''DD-MON-YYYY'') || '' 5:00:00 '', ''DD-MON-YYYY HH24:MI:SS '') AND
DATE_TIME < TO_DATE(TO_CHAR(CURRENT_DATE, ''DD-MON-YYYY'') || ''13:00:00 '', ''DD-MON-YYYY HH24:MI:SS '')
or with truncation and date arithmetic:
WHERE DATE_TIME >= TRUNC(CURRENT_DATE) + (5/24) AND
DATE_TIME < TRUNC(CURRENT_DATE) + (13/24)
You really need to be getting those times in the target time zone though, e.g.:
WHERE DATE_TIME >= FROM_TZ(CAST(TRUNC(CURRENT_DATE) + (5/24) AS TIMESTAMP), ''America/Los_Angeles'') AND
DATE_TIME < FROM_TZ(CAST(TRUNC(CURRENT_DATE) + (13/24) AS TIMESTAMP), ''America/Los_Angeles'')
You need to be careful with current_date, which is in you current session time zone, and sysdate which is in the server time zone. If your session is UTC then current_date might not give you the day you expect.
(I've stuck with escaped single quotes as that is mostly what you have in the question, implying you're probably running this with dynamic SQL; whether you need to is another matter. If you're only doing that to provide the period offsets at runtime then that wouldn't need to be dynamic...)
You can see the generated times from those calculations with:
select FROM_TZ(CAST(TRUNC(CURRENT_DATE) + (5/24) AS TIMESTAMP), 'America/Los_Angeles'),
FROM_TZ(CAST(TRUNC(CURRENT_DATE) + (13/24) AS TIMESTAMP), 'America/Los_Angeles')
from dual;
FROM_TZ(CAST(TRUNC(CURRENT_DATE)+(5/24)ASTIMESTAM FROM_TZ(CAST(TRUNC(CURRENT_DATE)+(13/24)ASTIMESTA
------------------------------------------------- -------------------------------------------------
2018-10-22 05:00:00.000000000 AMERICA/LOS_ANGELES 2018-10-22 13:00:00.000000000 AMERICA/LOS_ANGELES

How to check if current time falls between two time stamps in oracle

How to check if my current time stamp is between a time range.
for ex: I want to check my current time(let's say 03:00 PM) falls between 06:00 PM and 07:00 PM.
How do I check this in Oracle?
SELECT CASE
WHEN SYSDATE - TRUNC( SYSDATE ) BETWEEN 17.5/24 AND 18.5/24
THEN 'Is between 17:30 and 18:30'
ELSE 'Not between 17:30 and 18:30'
END
FROM DUAL;
or
SELECT CASE
WHEN SYSDATE BETWEEN TRUNC( SYSDATE ) + INTERVAL '17:30' HOUR TO MINUTE
AND TRUNC( SYSDATE ) + INTERVAL '18:30' HOUR TO MINUTE
THEN 'Is between 17:30 and 18:30'
ELSE 'Not between 17:30 and 18:30'
END
FROM DUAL;
I'd use strings for the comparision:
select
case when to_char(sysdate, 'HH24:MI') >= '18:00'
and to_char(sysdate, 'HH24:MI') < '19:00' then 'YES' else 'NO'
end as in_time_range
from dual;

ORACLE SQL - How to check whether a time falls within a particular range?

There is a column 'DateTime' that displays the Date and Time in 'YYYY/MM/DD HH24:MI:SS' format.
I need to display only the rows that has time in a particular range(2AM - 6AM) regardless of the particular date.
I have a code that only displays the time range(2AM - 6AM) for the particular day. I need to display the rows that falls in the past 7 days with the time range 2AM-6AM.
SELECT *
FROM <table_name >
WHERE DateTime BETWEEN TO_DATE (
TO_CHAR (TRUNC (SYSDATE), 'DD-MM-YYYY')
|| ' '
|| '02:00:00',
'DD-MM-YYYY HH24:MI:SS')
AND TO_DATE (
TO_CHAR (TRUNC (SYSDATE), 'DD-MM-YYYY')
|| ' '
|| '06:00:00',
'DD-MM-YYYY HH24:MI:SS')
ORDER BY 1 DESC
SELECT *
FROM your_table
WHERE TO_CHAR( DateTime, 'HH24MMSS' ) BETWEEN '020000' AND '060000'
AND DateTime >= TRUNC( SYSDATE ) - INTERVAL '7' DAY
AND DateTime < TRUNC( SYSDATE ) + INTERVAL '1' DAY
or
SELECT *
FROM your_table
WHERE DateTime BETWEEN TRUNC( DateTime ) + INTERVAL '2' HOUR
AND TRUNC( DateTime ) + INTERVAL '6' HOUR
AND DateTime >= TRUNC( SYSDATE ) - INTERVAL '7' DAY
AND DateTime < TRUNC( SYSDATE ) + INTERVAL '1' DAY
You need two conditions for that: one for the hour being between 02 and 05, and one for the day being in the last seven days:
SELECT *
FROM <table_name>
WHERE to_char(DateTime, 'HH') BETWEEN '02' and '05' AND
DateTime BETWEEN SYSDATE - 7 AND SYSDATE
ORDER BY 1 DESC
In this case, I think the easiest way is string comparison:
WHERE SUBSTR(DateTime, 12, 2) BETWEEN '02' and '05'
Note: Between is inclusive so this should get everything up to 05:59:59.
SELECT *
FROM <table_name >
WHERE DateTime BETWEEN TO_DATE (
TO_CHAR (TRUNC (SYSDATE)-7, 'DD-MM-YYYY')
|| ' '
|| '02:00:00',
'DD-MM-YYYY HH24:MI:SS')
AND TO_DATE (
TO_CHAR (TRUNC (SYSDATE), 'DD-MM-YYYY')
|| ' '
|| '06:00:00',
'DD-MM-YYYY HH24:MI:SS')
select * from table_name where to_char(datetime,'HH24')
between '2' and '6' and to_char(datetime,'dd-mon-yy')
between to_char(sysdate,'dd-mon-yy') and to_char(sysdate-7,'dd-mon-yy');