Round time to exact hour SQL Server - sql

I have this SQL query:
select
e.Cedula,
concat (e.Nombre, ' ', e.Apellido) nombre,
C.Descripcion cargo,
max(case when mo.Sentido = 'Entrada' then cast(mo.FechaHora as time)
end) as Entrada,
max(case when mo.Sentido = 'Salida' then cast(mo.FechaHora as time)
end) as Salida,
e.Direccion observaciones
from
mambo.dbo.EMPLEADO e
left join
mambo.dbo.CARGO c on e.IdCargo = c.IdCargo
left join
mambo.dbo.MARCACIONES_PARA_LIQUIDACION mo on e.IdEmpleado = mo.IdEmpleado
and CAST(mo.FechaHora AS DATE) = '2018-04-25'
where
e.IdCentroCosto = 14
and e.estado = '1'
group by
e.IdEmpleado, e.Cedula, e.Nombre, e.Apellido, c.Descripcion, e.Direccion
Which returns this result:
Result of Select
Is there a way I could round the time to the nearest exact hour in a range of 15 minutes?
Example:
if it is 6:45 I want the result to show 7:00
if it is 6:58 I want the result to show 7:00
if it is 17:15 I want the result to show 17:00
if it is 17:01 I want the result to show 17:00
Any help would be very appreciated

Hmmm . . . how about just constructing the value yourself?
datename(hour, dateadd(minute, 30, max(case when mo.Sentido = 'Entrada' then mo.FechaHora end))) + ':00' as Entrada,
The addition of 30 minutes is to facilitate rounding.

You can turn this into a function, some of it can be simplified/removed it is in there to show steps/clarity.
DECLARE #TimeCheck AS VARCHAR(50)
SET #TimeCheck = '17:30'
DECLARE #HourOfTime AS INT
DECLARE #MinuteOfTime AS INT
SET #MinuteOfTime = RIGHT(#TimeCheck, 2)
SET #HourOfTime = LEFT(#TimeCheck, 2)
SELECT #HourOfTime, #MinuteOfTime
-- here if the minutes between 0 and 20 then dont add anything, if it is 30 and 59 add 1 to the hours.
-- if you need more options or need to change the logic you can add more WHEN statements or change the numbers for the between
SET #HourOfTime += CASE
WHEN #MinuteOfTime BETWEEN 0 AND 29 THEN 0
WHEN #MinuteOfTime BETWEEN 30 AND 59 THEN 1
END
SELECT CAST(#HourOfTime AS VARCHAR(30)) + ':00' -- since rounding this will just be hard coded to 00

Related

Comparing Week of Year with "overflow"

So I want to be able to look at a specific week of the year and look at all data in the preceding and following 6 weeks.
WHERE t1.weeknum >= week-6 AND t1.weeknum <=week+6
So if week is 20, I want to return everything between 14 and 26.
The problem is weeks >=47 and <=6. For instance, if week is 4, I want the range to be 50 through 10. Years are a separate dimension and I am including all data regardless of year.
I think this would be similar to a compass heading. Say you are at 350 degrees and turn right 30 degrees. 350+30 = 20 degree bearing.
I'm using SQL Server Express
The Modulus operator (%) seems to be what you want. Since you are using the range 1 to 52 to represent week numbers you need to shift the range to 0 to 51 while calculating:
select WeekNumber,
( WeekNumber - 1 + 52 - 6 ) % 52 + 1 as WeekFrom,
( WeekNumber - 1 + 6 ) % 52 + 1 as WeekTo
from ( values ( 1 ), ( 4 ), ( 6 ), ( 20 ), ( 50 ), ( 52 ) ) as Samples( WeekNumber );
By way of explanation:
Start with WeekNumber.
Subtract 1 to shift it to a zero-based range: 0 to 51.
For "from" values add 52 so that the result is always non-negative. This assumes that the input values are always in the range 1 to 52.
Add or subtract the desired offset (6).
Use modulus to calculate the value with wraparound.
Add 1 to shift the result back to a one-based range: 1 to 52.
Use the StartDate and EndDate in your WHERE clause. Please mark as answer if this is what you need.
declare #StartDayOfYear int
, #EndDayOfYear int
, #WeekNo int
, #YearNo int
, #WeekDate date
, #YearText varchar(4)
, #Start int
, #WeekOfStart date
, #WeekOfEnd date
set #WeekNo = 2
set #YearNo = year(getdate())
set #YearText = #YearNo
set #WeekDate = (select dateadd(day,1 - datepart(dw, #YearText + '-01-01') + (#WeekNo-1) * 7,#YearText + '-01-01'))
set #Start = (select datepart(dayofyear,#WeekDate))
set #StartDayOfYear = (select #Start - 42)
set #EndDayOfYear = (select #Start + 42)
set #WeekOfStart = (select Convert (date,dateadd (day, #StartDayOfYear, #WeekDate)))
set #WeekOfEnd = (select Convert (date,dateadd (day, #EndDayOfYear, #WeekDate)))
select #StartDayOfYear
, #EndDayOfYear
, #WeekDate as StartWeek
, CAST(DATEADD(wk, 0, DATEADD(DAY, 1-DATEPART(WEEKDAY, #WeekOfStart), DATEDIFF(dd, -1, #WeekOfStart))) AS DATE) as StartDate
, CAST(DATEADD(wk, 1, DATEADD(DAY, 0-DATEPART(WEEKDAY, #WeekOfEnd), DATEDIFF(dd, 0, #WeekOfEnd))) AS DATE) as EndDate

T-SQL DATEDIFF giving returning result 1 hours when difference is only 45 minutes

Facing an issue with T-sql Datediff function,
I am calculating date difference in minutes between two dates, and then in hours.
Minute is giving me correct result
SELECT DATEDIFF(minute,'2018-01-22 23:59:00.000','2018-01-23 00:44:00.000')
Result 45 minutes
But when I am trying to calculate hours it's giving me incorrect results for days that are almost over and new day begins,
So if the time parameter is '23:59:00' and the second parameter is '00:44:00' it returns 1 hour difference when its only 45 minutes.
SELECT DATEDIFF(HOUR,'2018-01-22 23:59:00.000','2018-01-23 00:44:00.000')
Result 1 Hour --Incorrect
I am expecting this result to be zero
SELECT DATEDIFF(HOUR,'2018-01-22 23:59:00.000','2018-01-23 00:44:00.000')
Result 0 Hour -- This is the result expected
Update:
Posting my Function here if anyone needs to Calculate difference between two dates in format as Day:Hour:Minute
ALTER FUNCTION [dbo].[UDF_Fedex_CalculateDeliveryOverdue]
(
-- Add the parameters for the function here
#requiredDate VARCHAR(50),
#deliveryStamp VARCHAR(50)
)
RETURNS VARCHAR(25)
AS
BEGIN
DECLARE #ResultVar VARCHAR(25)
SET #ResultVar = ( SELECT CASE WHEN a.Days = 0 AND a.Hours = 0 THEN CAST(a.Minutes AS VARCHAR(10)) + ' Minutes'
WHEN a.Days = 0 THEN CAST(a.Hours AS VARCHAR(10)) + ' Hours ' + CAST(a.Minutes AS VARCHAR(10)) + ' Minutes'
ELSE CAST(a.Days AS VARCHAR(10)) +' Day ' + CAST(a.Hours AS VARCHAR(10)) +' Hours ' + CAST(a.Minutes AS VARCHAR(10)) + ' Minutes'
END
FROM ( SELECT DATEDIFF(hh, #requiredDate,#deliveryStamp)/24 AS 'Days'
,(DATEDIFF(MI, #requiredDate,#deliveryStamp)/60) -
(DATEDIFF(hh, #requiredDate,#deliveryStamp)/24)*24 AS 'Hours'
,DATEDIFF(mi, #requiredDate,#deliveryStamp) -
(DATEDIFF(mi, #requiredDate,#deliveryStamp)/60)*60 AS 'Minutes'
) a)
-- Return the result of the function
RETURN #ResultVar
END
To get value 0 you need to get the result in minutes, and convert to hours:
SELECT DATEDIFF(minute,'2018-01-22 23:59:00.000','2018-01-23 00:44:00.000')/60
For more precision:
SELECT DATEDIFF(minute,'2018-01-22 23:59:00.000','2018-01-23 00:44:00.000')/60.0

if the date difference between two dates is X do this if is Y do something else

My start date is 2009-04-01 (4th of april 2009), end date is getdate().
I need to calculate for every date from the start date until today some things.
I also need to break it into two cases:
case 1: if it's a friday i need to go back 347 days , example
select datediff(dw, '2010-11-22','2011-11-04')
for every friday, then perform some selects.
case 2: if it's from monday to thursday then go back 349 days, example
select datediff(dw, '2010-11-19','2011-11-03')
How can I write this, what I need to perform is not relevant just put it as:
declare #startDate date
declare #endDate date
declare #dateHolder date
declare #tsID int
set #startDate = '2009-04-01'
set #endDate = getdate()
set datefirst 1;
while (select count (tsID) from #tempI)>0
begin
select top 1 #tsID = tsID from #tempI
while (select count (rateDate) from #tempI)>0
begin
select top 1 #dateHolder = rateDate from #tempI
case (select datename (dw, #dateHolder) = '5' then someColumn = #dateHolder - 347 as dateIneedToUseForMyFormula
case (select datename (dw, #dateHolder) = '1' or '2' or '3' or '4' then someColumn = #dateHolder - 349 as dateIneedToUseForMyFormula
-- here i don't know how to write the code, so i'll write pseudo
-- i have tsID rateDate and rate
-- i need to put in a new column (the value obtained from taking the value
-- from the column rate corresponding to the #dateHolder - the value from
-- the column rate corresponding to the #dateHolder - 347 or 349
-- depending on the case) * 100
end
delete from #tempI where #dateHolder = rateDate
end
delete from #tempI where #tsID = tsID
end
EDIT
I was asked in the comments what to do, and given the downvotes, I don't think i made myself clear. I will copy paste what i wrote in the comment:
"
first to iterate through all the tsID in the list, after doing that to iterate through all the dates, get a date subtract 349 or 347 days from it, then check put in a new column the result of : the value of the 'rate' column which corresponds to my date - the value of the 'rate' column which corresponds to the date from 349 or 347 days ago. This performed for all the dates for every id "
edit 2: Expected output
tsID rateDate rate calculated
1 2009-04-01 0.12 null
1 2009-04-02 0.14 null
1 2009-04-03 0.11 null
2 2009-04-01 0.01 null
2 2009-04-02 0.012 null
2 2009-04-03 0.43 null
. . . 347 days later or 349 depending
on what 2009-04-01 was
1 2010-03-16 0.454 (0.454 - 0.12)*100
1 2010-03-17 0.34 (0.34 - 0.14)*100
1 2010-03-18 0.9 (0.9 - 0.11)*100
then same for id 2.3...4...
Try This
Declare #start Date='2009-09-01', #end Date=getdate();
;With NumberSequence( Number ) as
(
Select #start as Number
union all
Select DATEADD(d,1,Number)
from NumberSequence
where Number < #end
)
Select
(CASE WHEN (datepart(dw,Number) =6) THEN DATEADD(d,-347,Number)
ELSE DATEADD(d,-349,Number)
END ) AS Date
From NumberSequence Option (MaxRecursion 10000)
Use a case statement with weekday:
Select Case
When WeekDAy(yourdate, 3) < 4 then datediff(dw, '2010-11-19','2011-11-03')
when WeekDAy(yourdate, 3) = 4 then datediff(dw, '2010-11-22','2011-11-04')
Else ...?... End

Query to calculate partial labor hours

I'm not sure if it's possible to do exactly what I'm wanting, but hopefuly someone here can give me some direction. I'm trying to do some labor reports and a few of them require me to make comparisons to labor by hour.
Starting as simple as possible, I would like to know how I could query over employee In and Out times for a given hour and find out how many total hours have been worked.
For example, if I have:
id In Out
-- ------- ------
1 12:00pm 8:30pm
2 12:00pm 8:15pm
3 8:15pm 11:00pm
and I wanted to query for how many hours of labor there were in the 8 o'clock hour then I would expect to see a result of 2 hours (or 120 minutes... 30m + 15m + 45m).
Then moving on from there I'd like to write a query that will show this information for the whole day, but group on the hour showing this same information for each hour. I realize there are other concerns (i.e. I would also need to group on the date, etc.) but if I can figure this out then the rest will be a breeze.
For more context, you can see a similar question I have here: Query for labor cost by hour
(The difference between this question and the other one, if it's not clear, is that I am asking about a specific approach here. If you think you have a better approach to this problem, then please add it to the other question.)
Try this to get your started, need to tweak it a bit, but should give you what you want on your sample data...
select id,
minutes - case when inMinutes < 0 then 0 else inminutes end as TotalMins
from
(
select id,
case when datediff(mi,'8:00pm',OutTime) >60 then 60 else datediff(mi,'8:00pm',OutTime) end as Minutes,
case when datediff(mi,'8:00pm',InTime) >60 then 60 else datediff(mi,'8:00pm',InTime) end as InMinutes
from testhours
) xx
If that is a Microsoft system then datetime values can be converted to double precision floating point numbers where the decimal point divides the date and time like this:
integer part: number of days since 1900-01-01
decimal part: time in the day (so that 0.5 = 12:00:00)
So you could use something like this:
-- sample datetime values
declare #in datetime, #out datetime
set #in = '2012-01-18 12:00:00'
set #out = '2012-01-18 20:30:00'
-- calculation
declare #r_in real, #r_out real
set #r_in = cast(#in as real)
set #r_out = cast(#out as real)
select (24 * (#r_out - #r_in)) as [hours]
BUT it is not that precise, so I would recommend this for calculation:
select cast(datediff(second, #in, #out) as real)/3600 as [hours]
OK, I would also suggest to use functions because that's maybe a lot slower on large tables but also easier and more simple to code.
But here's another solution without functions:
-- the day you're interested in:
declare #day datetime
set #day = '2012-01-20'
-- sample data
declare #moves table (id int, tin datetime, tout datetime)
insert into #moves values
(1, '2012-01-20 06:30:00', '2012-01-20 15:45:00'),
(2, '2012-01-20 13:05:00', '2012-01-20 19:45:00'),
(3, '2012-01-20 10:10:00', '2012-01-20 10:50:00'),
(4, '2012-01-20 19:35:00', '2012-01-20 21:00:00')
-- a helper table with hours
declare #i int
declare #hours table (h int, f datetime, t datetime)
set #i = 0
while #i < 24
begin
insert into #hours values(#i, dateadd(hour, #i, #day), dateadd(hour, #i + 1, #day))
set #i = #i + 1
end
-- here's the code
select h.h,
sum(case sign(datediff(second, h.f, m.tin))
when 1 then
case sign(datediff(second, m.tout, h.t))
when 1 then datediff(minute, m.tin , m.tout)
else datediff(minute, m.tin , h.t)
end
when null then null
else
case sign(datediff(second, m.tout, h.t))
when 1 then datediff(minute, h.f, m.tout)
else datediff(minute, h.f, h.t)
end
end) as minutesWorked,
count(distinct m.id) as peopleWorking
from #hours h inner join #moves m
-- on h.f >= m.tin and h.t <= m.tout
on h.f <= m.tout and h.t >= m.tin
group by h.h
order by h.h
This will give you the following results:
h minutesWorked peopleWorking
----------- ------------- -------------
6 30 1
7 60 1
8 60 1
9 60 1
10 100 2
11 60 1
12 60 1
13 115 2
14 120 2
15 105 2
16 60 1
17 60 1
18 60 1
19 70 2
20 60 1
21 0 1

simulating Excel networkdays in sql

I am sure somebody has worked out to simulate Excel networkdays function in other programming language.
I'd appreciate if you could share.
Thanks
The idea is to calculate the weekdays between the start of each date's week then applying various offsets.
Find the number of days between the Saturday before each date
Divide by 7 and multiply by 5 to get the number of weekdays
Offset the total for whether the start date is after the end date
Offset again for whether the start is after the end and the start is a Saturday
Again for whether the start is after and the end is Sunday
Again for whether the start is not after and the start is a Sunday
Again for whether the start is not after and the end is a Saturday
Add some random dates into a table.
declare #t table ([start] datetime, [end] datetime)
insert into #t values ('2088-01-14 11:56:23','2011-11-10 03:34:09')
insert into #t values ('2024-09-24 10:14:29','2087-09-16 15:52:06')
Then calcuate NETWORKDAYS for those dates.
select [start],[end]
,((datediff(day,0,[end])-datepart(dw,[end]))-(datediff(day,0,[start])-datepart(dw,[start])))/7*5 --[weekdays]
+ datepart(dw,[end]) - datepart(dw,[start]) --[weekday diff]
+ case when datediff(day,0,[start]) > datediff(day,0,[end]) then -1 else 1 end --[start after]
+ case when datediff(day,0,[start]) > datediff(day,0,[end]) and datepart(dw,[start]) = 7 then 1 else 0 end --[start after and start saturday]
+ case when datediff(day,0,[start]) > datediff(day,0,[end]) and datepart(dw,[end]) = 1 then 1 else 0 end --[start after and end sunday]
+ case when datediff(day,0,[start]) <= datediff(day,0,[end]) and datepart(dw,[start]) = 1 then -1 else 0 end --[start not after and start sunday]
+ case when datediff(day,0,[start]) <= datediff(day,0,[end]) and datepart(dw,[end]) = 7 then -1 else 0 end --[start not after and end saturday]
as [networkdays]
from #t
A SQL solution as per SO question "Equivalent of Excel’s NETWORKDAYS function with Jet ADO"
Hope this helps someone out there but this works for me. Requires you to create a dbo.FederalHolidays table (which can be easily populated with online date sources).
Cleanest way I could come up with that is easily scalable.
--Simulate Excel Formula =NETWORKDAYS() excludes weekend days and federal holidays. Requires a Federal Holiday Table, easy to create.
DECLARE #d1 date, #d2 date
SET #d1 = '4/12/2019'
SET #d2 = '4/23/2019'
SELECT
DATEDIFF(dd,#d1,#d2) +1 --First calculate regular date difference +1 to count the start date; does not exclude weekends/holidays.
- (SELECT COUNT(*) --Calculate number of holidays between the date range and subtract it from DATEDIFF().
FROM [dbo].[FederalHolidays]
WHERE DATE BETWEEN #d1 AND #d2)
- (SELECT (DATEDIFF(wk, #d1, #d2) * 2) --Calculate number of weekend days between the date range and subtract it from DATEDIFF().
+(CASE WHEN DATENAME(dw, #d1) = 'Sunday' THEN 1 ELSE 0 END)
+(CASE WHEN DATENAME(dw, #d2) = 'Saturday' THEN 1 ELSE 0 END)) as NetWorkDays
For what it's worth, I created the following function for mysql that assumes Mon-Fri are business days:
DROP FUNCTION IF EXISTS BusinessDays;
DELIMITER //
CREATE FUNCTION BusinessDays (startDate DATE, endDate DATE)
RETURNS INT
DETERMINISTIC
BEGIN
DECLARE startWeekDay INT;
DECLARE allDays INT;
DECLARE fullWeekCount INT;
DECLARE remainderDays INT;
DECLARE maxPossibleRemainderWeekendDays INT;
DECLARE soloSundays INT;
DECLARE totalBusinessDays INT;
SET startWeekDay = WEEKDAY(startDate);
SET allDays = ABS(DATEDIFF(endDate, startDate)) + 1;
SET fullWeekCount = FLOOR(allDays/7);
SET remainderDays = allDays - (fullWeekCount * 7);
SET maxPossibleRemainderWeekendDays = ROUND(2*(startWeekDay+remainderDays-6)/(ABS(2*(startWeekDay+remainderDays-6))+1))+1;
SET soloSundays = ROUND(2*(startWeekDay-6)/(ABS(2*(startWeekDay-6))+1))+1;
SET totalBusinessDays = allDays - (fullWeekCount * 2) - maxPossibleRemainderWeekendDays + soloSundays;
RETURN totalBusinessDays;
END //
DELIMITER ;
Perhaps this will also help, I created a formula (in Excel) that will simulate the NETWORKDAYS function:
= 1 + ( ( B1 - A1) * 5 - ( WEEKDAY(A1) - WEEKDAY(B1) ) * 2 ) / 7 + IF(A1<=B1,IF(WEEKDAY(B1)=7,-1,0) + IF(WEEKDAY(A1)=1,-1,0), IF(WEEKDAY(B1)<>1,-1,0) + IF(WEEKDAY(A1)<>7,-1,0) )
NOTE: WEEKDAY() has Sunday as 0 to Saturday as 6
I have been looking for this capability for quite some time, so went ahead and just created it on my own.
Usage: This is a function you can create in SQL. You can easily modify this to work outside a function if needed, but I prefer functions to take care of these types of calculations.
I added quite a few comments in case anyone was wondering how it worked. What this does is take two inputs:
#startDate - the beginning date you want to add workday to.
#addDays - the whole number of days you want to add to the #startDate.
Calculation process:
It loops repeatedly until the # of working days has been reached. For example, if you enter 365 days, it will cycle around 500 times before it's able to predict the # of working days to add. I've added #weekendCount in case anyone needs to know the # of weekend days excluded before reaching the final end date.
Once completed, the integer #recCounter essentially is the # of days that must be added to the #startDate before the number of working days is reached. I am sure someone can write this better than I, or perhaps someone can make use of this. Hope this helps! :)
CREATE FUNCTION [dbo].[addNetworkDays](#startDate AS DATETIME, #addDays AS Int)
RETURNS DATETIME
AS
BEGIN
DECLARE #recCounter Int
SET #recCounter = 0
DECLARE #weekendCount Int
SET #weekendCount = 0
DECLARE #workdayCount Int
SET #workdayCount = 0
DECLARE #newDate DateTime
WHILE #addDays > #workdayCount
BEGIN
-- Add another day to the start date
SET #recCounter = #recCounter + 1
-- Cumuluate the weekend vs. workday counter, based on the day of the week. This loop will repeat until #workdayCount has reached the #addDays.
-- Note that #weekendCount is not used in any capacity, can be used if you need to know how many weekend days there are.
IF DATEPART(dw, DATEADD(d, #recCounter, #startDate)) IN (1, 7) SET #weekendCount = #weekendCount + 1
IF DATEPART(dw, DATEADD(d, #recCounter, #startDate)) IN (2, 3, 4, 5, 6) SET #workdayCount = #workdayCount + 1
END
-- At this point, the script has completed the cycle, stopping when the detected # of workdays has reached the count of days the user specified.
-- Calculate the new date, based on the # of cycles *days* detected above.
SET #newDate = DATEADD(d, #recCounter, #startDate)
-- If the new/adjusted date falls on a Saturday or Sunday, add additional days to compensate.
IF DATEPART(dw, #newDate) = 1 SET #newDate = DATEADD(d, 1, #newDate)
IF DATEPART(dw, #newDate) = 7 SET #newDate = DATEADD(d, 1, #newDate)
RETURN CAST(#newDate AS DATETIME)
NETWORKDAYS for Australia
WITH PH_NET_WORKDAY AS
(
----BUILD UNDERLYING WORKDAY DATA TABLE
SELECT
DT,
STATE,
CASE
WHEN WORKDAY-PUBLIC_HOLIDAY <0
THEN 0
ELSE WORKDAY-PUBLIC_HOLIDAY
END AS WORKDAY
FROM
(
SELECT
DT,
STATE,
WORKDAY,
----PUBLIC HOLIDAY INFORMATION HERE
CASE
WHEN STATE = 'NSW'
THEN
CASE
WHEN DT IN (
'01-Oct-2018',
'25-Dec-2018',
'26-Dec-2018',
'01-Jan-2019',
'28-Jan-2019',
'19-Apr-2019',
'20-Apr-2019',
'21-Apr-2019',
'22-Apr-2019',
'25-Apr-2019',
'10-Jun-2019',
'07-Oct-2019',
'25-Dec-2019',
'26-Dec-2019'
)
THEN 1
ELSE 0
END
WHEN STATE = 'SA'
THEN
CASE
WHEN DT IN (
'01-Oct-2018',
'24-Dec-2018',
'25-Dec-2018',
'26-Dec-2018',
'31-Dec-2018',
'01-Jan-2019',
'28-Jan-2019',
'11-Mar-2019',
'19-Apr-2019',
'20-Apr-2019',
'22-Apr-2019',
'25-Apr-2019',
'10-Jun-2019',
'07-Oct-2019',
'24-Dec-2019',
'25-Dec-2019',
'26-Dec-2019'
)
THEN 1
ELSE 0
END
WHEN STATE = 'QLD'
THEN
CASE
WHEN DT IN (
'01-Oct-2018',
'25-Dec-2018',
'26-Dec-2018',
'01-Jan-2019',
'28-Jan-2019',
'19-Apr-2019',
'20-Apr-2019',
'21-Apr-2019',
'22-Apr-2019',
'25-Apr-2019',
'06-May-2019',
'07-Oct-2019',
'25-Dec-2019',
'26-Dec-2019'
)
THEN 1
ELSE 0
END
WHEN STATE = 'VIC'
THEN
CASE
WHEN DT IN (
'28-Sep-2018',
'06-Nov-2018',
'25-Dec-2018',
'26-Dec-2018',
'01-Jan-2019',
'28-Jan-2019',
'11-Mar-2019',
'19-Apr-2019',
'20-Apr-2019',
'21-Apr-2019',
'22-Apr-2019',
'25-Apr-2019',
'10-Jun-2019',
'05-Nov-2019',
'25-Dec-2019',
'26-Dec-2019'
)
THEN 1
ELSE 0
END
WHEN STATE = 'TAS'
THEN
CASE
WHEN DT IN (
'25-Dec-2018',
'26-Dec-2018',
'01-Jan-2019',
'28-Jan-2019',
'11-Mar-2019',
'19-Apr-2019',
'22-Apr-2019',
'23-Apr-2019',
'25-Apr-2019',
'10-Jun-2019',
'25-Dec-2019',
'26-Dec-2019'
)
THEN 1
ELSE 0
END
ELSE 0
END AS PUBLIC_HOLIDAY
FROM
(
SELECT
DT.*,
ST.*
FROM
(
SELECT
TRUNC (TO_DATE('01-JAN-2021','DD-MON-YYYY') - ROWNUM) AS DT,
TRIM(TO_CHAR( TRUNC (TO_DATE('01-JAN-2021','DD-MON-YYYY') - ROWNUM) , 'DAY')) AS WEEK_DAY,
CASE
WHEN TRIM(TO_CHAR( TRUNC (TO_DATE('01-JAN-2021','DD-MON-YYYY') - ROWNUM) , 'DAY')) = 'SATURDAY'
THEN 0
WHEN TRIM(TO_CHAR( TRUNC (TO_DATE('01-JAN-2021','DD-MON-YYYY') - ROWNUM) , 'DAY')) = 'SUNDAY'
THEN 0
----BUILD STATE PUBLIC HOLIDAY DATE SET HERE, WE CAN EXCLUDE PUBLIC HOLIDAYS
ELSE 1
END AS WORKDAY
FROM DUAL CONNECT BY ROWNUM < (365.25*8+1)
) DT
,
(
SELECT 'NSW' AS STATE FROM DUAL
UNION
SELECT 'QLD' AS STATE FROM DUAL
UNION
SELECT 'SA' AS STATE FROM DUAL
UNION
SELECT 'ACT' AS STATE FROM DUAL
UNION
SELECT 'VIC' AS STATE FROM DUAL
UNION
SELECT 'ACT' AS STATE FROM DUAL
) ST
)
)
),
----A SAMPLE DATA SET FOR SAME DATES BETWEEN DIFFERENT STATE TO TEST PUBLIC HOLIDAY DIFFERENCES
SAMPLE_DATA AS
(
SELECT
'01-FEB-2019' AS D1,
'11-FEB-2019' AS D2,
'NSW' AS STATE
FROM DUAL
UNION
SELECT
'01-FEB-2019' AS D1,
'11-FEB-2019' AS D2,
'SA' AS STATE
FROM DUAL
UNION
SELECT
'19-APR-2019' AS D1,
'26-APR-2019' AS D2,
'NSW' AS STATE
FROM DUAL
)
----SELECT WORKDAYS FROM PH TABLE AND INSERT INTO SAPLE TABLE
SELECT
SAMPLE_DATA.*,
(
SELECT SUM(WORKDAY)
FROM PH_NET_WORKDAY
WHERE
STATE = SAMPLE_DATA.STATE
AND DT>=SAMPLE_DATA.D1
AND DT<=SAMPLE_DATA.D2
)
AS WORKDAYS
FROM SAMPLE_DATA