SELECT
ride_id,
rideable_type,
started_at,
ended_at,
start_station_name,
start_station_id,
end_station_name,
end_station_id,
start_lat,
start_lng,
end_lat,
end_lng,
member_casual,
ride_length,
ride_date,
ride_month,
ride_year,
start_time,
end_time,
CAST(day_of_week AS STRING) AS day_of_week,
quarter
FROM
`my-data-project12345-368309.cyclistic_jamesbimler.2022_Q1`
UPDATE
`my-data-project12345-368309.cyclistic_jamesbimler.2022_Q1`
SET
day_of_week =
CASE
WHEN day_of_week = '1' THEN 'Sunday'
WHEN day_of_week = '2' THEN 'Monday'
WHEN day_of_week = '3' THEN 'Tuesday'
WHEN day_of_week = '4' THEN 'Wednesday'
WHEN day_of_week = '5' THEN 'Thursday'
WHEN day_of_week = '6' THEN 'Friday'
WHEN day_of_week = '7' THEN 'Saturday'
END
WHERE
day_of_week IN ('1','2','3','4','5','6','7')
I'm trying to change the day_of_week column from an int to a string to represent the days of the week but I keep getting the error Syntax error: Expected end of input but got identifier
I have tried to move code around and delete things with no luck.
Try this code. There is a syntax error missing semicolon, it is added.
SELECT
ride_id,
rideable_type,
started_at,
ended_at,
start_station_name,
start_station_id,
end_station_name,
end_station_id,
start_lat,
start_lng,
end_lat,
end_lng,
member_casual,
ride_length,
ride_date,
ride_month,
ride_year,
start_time,
end_time,
CAST(day_of_week AS STRING) AS day_of_week,
quarter
FROM
`my-data-project12345-368309.cyclistic_jamesbimler.2022_Q1`;
UPDATE
`my-data-project12345-368309.cyclistic_jamesbimler.2022_Q1`
SET
day_of_week =
CASE
WHEN day_of_week = '1' THEN 'Sunday'
WHEN day_of_week = '2' THEN 'Monday'
WHEN day_of_week = '3' THEN 'Tuesday'
WHEN day_of_week = '4' THEN 'Wednesday'
WHEN day_of_week = '5' THEN 'Thursday'
WHEN day_of_week = '6' THEN 'Friday'
WHEN day_of_week = '7' THEN 'Saturday'
END
WHERE
day_of_week IN ('1','2','3','4','5','6','7');
Related
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.
I want to calculate next business day in Oracle query. So on Monday - Thursday it should be sysdate+1, on Friday it should be sysdate+3, on Saturday it should be sysdate+2 and on Sunday it should be sysdate+1.
I want to do it dynamically, rather than have lots of where statements covering the different days.
where order_date = CASE WHEN (1 + TRUNC (SYSDATE) - TRUNC (SYSDATE, 'IW')) < 5
THEN TRUNC (SYSDATE) + 1
ELSE TRUNC (SYSDATE + 4), 'IW')
END
I found this from the answer Next business day (Monday - Friday) in Oracle? but it seems error in query and I can't work it out.
You can use to_char(sysdate, 'fmday') which returns the string name of the day:
where order_date =
case
when to_char(sysdate, 'fmday', 'nls_date_language=AMERICAN') = 'friday' then trunc(sysdate) + 3
when to_char(sysdate, 'fmday', 'nls_date_language=AMERICAN') = 'saturday' then trunc(sysdate) + 2
else trunc(sysdate) + 1
end
and better:
where order_date =
trunc(sysdate) + case
when to_char(sysdate, 'fmday', 'nls_date_language=AMERICAN') = 'friday' then 3
when to_char(sysdate, 'fmday', 'nls_date_language=AMERICAN') = 'saturday' then 2
else 1
end
to have the results from the statement, use below statement.
where order_date =
(Select
CASE WHEN (1 + TRUNC (SYSDATE) - TRUNC (SYSDATE, 'IW')) < 5
THEN TRUNC (SYSDATE) + 1
ELSE TRUNC ((SYSDATE + 4), 'IW')
END from dual);
Select
null link,
a.Time_Frame "Start_Date",
(a.Row_Number*(REGR_SLOPE(a.Failures, a.Row_Number) Over (Partition by a.State)) + (REGR_INTERCEPT(a.Failures, a.Row_Number) OVER (Partition by a.State))) Trendline
FROM
(
SELECT ROW_NUMBER() OVER (ORDER BY (Case :P1_DATE_CHOOSER
WHEN 'Daily' THEN trunc(start_time)
WHEN 'Weekly' THEN trunc(start_time, 'WW')
WHEN 'Monthly' THEN trunc(start_time, 'MM')
END)) Row_Number,
(Case :P1_DATE_CHOOSER
WHEN 'Daily' THEN trunc(start_time)
WHEN 'Weekly' THEN trunc(start_time, 'WW')
WHEN 'Monthly' THEN trunc(start_time, 'MM')
END) Time_Frame,
count(job_id) Failures, State
--FROM apps.NI_INFA_ACTIVITY_LOG_V#util.world
FROM NI_INFA_ACTIVITY_LOG_V
WHERE
STATE = 1
and
(
:P1_JOB_TYPE_CHOOSER = 'Workflow' AND INFA_TYPE_CODE = 'WORKFLOW'
OR
:P1_JOB_TYPE_CHOOSER = 'DSS' AND INFA_TYPE_CODE = 'DSS'
OR
:P1_JOB_TYPE_CHOOSER = 'MTT' AND INFA_TYPE_CODE = 'MTT'
OR
:P1_JOB_TYPE_CHOOSER NOT IN ('Workflow','DSS','MTT')
)
group by (Case :P1_DATE_CHOOSER
WHEN 'Daily' THEN trunc(start_time)
WHEN 'Weekly' THEN trunc(start_time, 'WW')
WHEN 'Monthly' THEN trunc(start_time, 'MM')
END), state
ORDER BY State,(Case :P1_DATE_CHOOSER
WHEN 'Daily' THEN trunc(start_time)
WHEN 'Weekly' THEN trunc(start_time, 'WW')
WHEN 'Monthly' THEN trunc(start_time, 'MM')
END)
) a
Group by a.Row_Number, a.Time_Frame,a.Failures, a.State
order by a.State,a.Row_Number;
In the middle is source. This query works in Toad but when I move it to Oracle Apex App developer the chart won't populate data. The only change that is made is I switch the FROM clauses around in the middle. I know that "apps.NI_INFA_ACTIVITY_LOG_V#util.world" works as a source because I'm using it inside other queries in the app. If i get rid of the CASE/WHENS and switch them to just a single line like trunc(start_time) by itself, the data populates. Any help would be appreciated.
Table and sample data:
CREATE TABLE NI_INFA_ACTIVITY_LOG
( TASK_ID VARCHAR2(30 BYTE)
, OBJECT_NAME VARCHAR2(1000 BYTE)
, JOB_ID VARCHAR2(30 BYTE) NOT NULL
, INFA_TYPE_CODE VARCHAR2(10 BYTE)
, RUN_ID NUMBER(10)
, START_TIME DATE
, END_TIME DATE
, STATE NUMBER(1)
);
INSERT INTO NI_INFA_ACTIVITY_LOG
(TASK_ID, OBJECT_NAME, JOB_ID, INFA_TYPE_CODE, RUN_ID, START_TIME, END_TIME, STATE)
VALUES
( '000T0W0N0000000000000U'
, 'CampSync_ERP_SFDC_v1.2'
, '000T0WC1000000001I6W'
, 'WORKFLOW'
, NULL
, TO_DATE('5/22/2015 11:20:10','MM/DD/YYYY HH24:MI:SS')
, TO_DATE('5/22/2015 11:21:02','MM/DD/YYYY HH24:MI:SS')
, 1
);
INSERT INTO NI_INFA_ACTIVITY_LOG
(TASK_ID, OBJECT_NAME, JOB_ID, INFA_TYPE_CODE, RUN_ID, START_TIME, END_TIME, STATE)
VALUES
( '000T0W0N00000000000H'
, 'PMDM_ORA_ORA_ClnLoad_v1.0'
, '000T0WC1000000001J5X'
, 'WORKFLOW'
, NULL
, TO_DATE('5/24/2015 10:30:11','MM/DD/YYYY HH24:MI:SS')
, TO_DATE('5/24/2015 10:32:34','MM/DD/YYYY HH24:MI:SS')
, 1
);
COMMIT;
I found the solution. I'm not entirely certain why this made it work in Apex though:
Select
Null Link,
tf.Time_Frame LABEL,
(tf.Row_number*(REGR_SLOPE(count(data.job_id), tf.Row_number) Over (Partition by data.State)) + (REGR_INTERCEPT(count(data.job_id), tf.Row_number) OVER (Partition by data.State))) Trendline
FROM APPS.NI_INFA_ACTIVITY_LOG_V#util.world data
,
(
Select RowNum Row_number, Time_Frame
from
(
Select
Case :P1_DATE_CHOOSER
WHEN 'Daily' THEN trunc(start_time)
WHEN 'Weekly' THEN trunc(start_time, 'WW')
WHEN 'Monthly' THEN trunc(start_time, 'MM')
END Time_Frame
From APPS.NI_INFA_ACTIVITY_LOG_V#util.world
group by Case :P1_DATE_CHOOSER
WHEN 'Daily' THEN trunc(start_time)
WHEN 'Weekly' THEN trunc(start_time, 'WW')
WHEN 'Monthly' THEN trunc(start_time, 'MM')
END
order by 1
)
) tf
where
tf.Time_Frame = (Case :P1_DATE_CHOOSER
WHEN 'Daily' THEN trunc(data.start_time)
WHEN 'Weekly' THEN trunc(data.start_time, 'WW')
WHEN 'Monthly' THEN trunc(data.start_time, 'MM')
END)
AND
STATE = 1
AND
(
:P1_JOB_TYPE_CHOOSER = 'Workflow' AND data.INFA_TYPE_CODE = 'WORKFLOW'
OR
:P1_JOB_TYPE_CHOOSER = 'DSS' AND data.INFA_TYPE_CODE = 'DSS'
OR
:P1_JOB_TYPE_CHOOSER = 'MTT' AND data.INFA_TYPE_CODE = 'MTT'
OR
:P1_JOB_TYPE_CHOOSER NOT IN ('Workflow','DSS','MTT')
)
group by tf.Time_Frame, tf.Row_number, data.State
I would like to build an SQL query which calculates the difference between 2 dates, without counting the week-end days in the result.
Is there any way to format the dates to obtain this result ? For example for Oracle database :
select sysdate - creation_dttm from the_table
You should try with a function :
CREATE FUNCTION TOTAL_WEEKDAYS(date1 DATE, date2 DATE)
RETURNS INT
RETURN ABS(DATEDIFF(date2, date1)) + 1
- ABS(DATEDIFF(ADDDATE(date2, INTERVAL 1 - DAYOFWEEK(date2) DAY),
ADDDATE(date1, INTERVAL 1 - DAYOFWEEK(date1) DAY))) / 7 * 2
- (DAYOFWEEK(IF(date1 < date2, date1, date2)) = 1)
- (DAYOFWEEK(IF(date1 > date2, date1, date2)) = 7);
Test :
SELECT TOTAL_WEEKDAYS('2013-08-03', '2013-08-21') weekdays1,
TOTAL_WEEKDAYS('2013-08-21', '2013-08-03') weekdays2;
Result :
| WEEKDAYS1 | WEEKDAYS2 |
-------------------------
| 13 | 13 |
I have found another way to do calculate the difference, by using only SQL :
select sysdate - creation_dttm
- 2 * (to_char(sysdate, 'WW') - to_char(creation_dttm, 'WW'))
from the_table
I have found several of the answers on this thread to not do what they claim. After some experimentation, testing and adjusting, I have this to contribute.
declare #firstdate Date
declare #seconddate Date
set #firstDate = convert(date, '2016-03-07')
set #seconddate = convert(date, '2016-04-04')
select (datediff(dd, #firstDate, #secondDate)) -
(( DateDiff(wk, #firstDate, #secondDate) * 2) -
case when datepart(dw, #FirstDate) = 7 then 1 else 0 end -
case when datepart(dw, #secondDate) = 7 then -1 else 0 end)
Test harness included - you can just adjust the two dates and run your own tests. This assumes that the difference between two adjacent weekday dates is 1. If your country uses different days to signify weekend, then you will have to set the date-base accordingly so your "Saturday" is 7, and your "sunday" is 1.
From a previous post:
DECLARE #StartDate DATETIME
DECLARE #EndDate DATETIME
SET #StartDate = '2008/10/01'
SET #EndDate = '2008/10/31'
SELECT
(DATEDIFF(dd, #StartDate, #EndDate) + 1)
-(DATEDIFF(wk, #StartDate, #EndDate) * 2)
-(CASE WHEN DATENAME(dw, #StartDate) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, #EndDate) = 'Saturday' THEN 1 ELSE 0 END)
Here is an example:
There are four variables, the first two are self-explanatory, just enter the date in YYYYMMDD format, the 3rd one is to set the number of normal work days in a given week, so if a site works 6 days a week, set it to 6, five days a week enter 5, etc. Finally, the
DATE_SEQ_NORML_FACTOR should be 1 when running against Oracle. This is to line up the Julian date to equal to 1 on Monday, 2 on Tuesday, etc when applying the MOD 7. Other DB will probably have different values between 0 and 6, so test it out before you use against other DBs.
Here are the limitations:
1. This formula assumes the first day of the week is MONDAY.
2. This formula assumes all days within the same week are CONTINUOUS.
3. This formula will work ONLY when the two dates involved in the calculation falls on a week day or work day, eg. the "Start Date" on a SATURDAY when the location works only MON-FRI will not work.
SELECT
&&START_DATE_YYYYMMDD "Start Date", --in YYYYMMDD format
&&END_DATE_YYYYMMDD "End Date", --in YYYYMMDD format
&&WK_WORK_DAY_CNT "Week Work Day Count", --Number of work day per week
&&DATE_SEQ_NORML_FACTOR "Normalization Factor", --set to 1 when run in Oracle
CASE
WHEN
FLOOR( TO_CHAR( TO_DATE( &&START_DATE_YYYYMMDD , 'YYYYMMDD') , 'J' ) + &&DATE_SEQ_NORML_FACTOR / 7 ) =
FLOOR( TO_CHAR( TO_DATE( &&END_DATE_YYYYMMDD , 'YYYYMMDD') , 'J' ) + &&DATE_SEQ_NORML_FACTOR / 7 )
THEN(
TO_CHAR( TO_DATE( &&END_DATE_YYYYMMDD , 'YYYYMMDD') , 'J' ) -
TO_CHAR( TO_DATE( &&START_DATE_YYYYMMDD , 'YYYYMMDD') , 'J' ) + 1
)
ELSE(
(
&&WK_WORK_DAY_CNT - MOD( TO_CHAR( TO_DATE( &&START_DATE_YYYYMMDD , 'YYYYMMDD') , 'J' ) + &&DATE_SEQ_NORML_FACTOR , 7 ) + 1
) +
MOD( TO_CHAR( TO_DATE( &&END_DATE_YYYYMMDD , 'YYYYMMDD') , 'J' ) + &&DATE_SEQ_NORML_FACTOR , 7 ) +
(
(
(
TO_CHAR( TO_DATE( &&END_DATE_YYYYMMDD , 'YYYYMMDD') , 'J' ) -
MOD( TO_CHAR( TO_DATE( &&END_DATE_YYYYMMDD , 'YYYYMMDD') , 'J' ) + &&DATE_SEQ_NORML_FACTOR , 7 )
) -
(
TO_CHAR( TO_DATE( &&START_DATE_YYYYMMDD , 'YYYYMMDD') , 'J' ) +
(
7 -
(
MOD( TO_CHAR( TO_DATE( &&START_DATE_YYYYMMDD , 'YYYYMMDD') , 'J' ) + &&DATE_SEQ_NORML_FACTOR , 7 )
)
)
)
) / 7 * &&WK_WORK_DAY_CNT
)
) END "Week Day Count"
FROM DUAL
We've incorporated the following logic into several reports with great success. Sorry, I no longer recall the source of this script to give them credit.
DECLARE #range INT;
SET #range = DATEDIFF(DAY, #FirstDate, #SecondDate);
SET #NumWorkDays = (
SELECT
#range / 7 * 5 + #range % 7 - (
SELECT COUNT(*)
FROM (
SELECT 1 AS d
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
UNION ALL SELECT 6
UNION ALL SELECT 7
) weekdays
WHERE d <= #range % 7
AND DATENAME(WEEKDAY, #SecondDate - d) IN ('Saturday', 'Sunday'))
);
I've updated #JOpuckman's function to take into account that different regions don't always have a weekend of Saturday and Sunday. Here's the code in case anyone else needs to apply this globally;
DECLARE #FirstDate DateTime
DECLARE #SecondDate DateTime
SET #FirstDate = '08-20-2012'
SET #SecondDate = '08-24-2012'
DECLARE #range INT;
DECLARE #WeekendDayNameStart VARCHAR(50)
DECLARE #WeekendDayNameEnd VARCHAR(50)
SET #WeekendDayNameStart = 'FRIDAY'
SET #WeekendDayNameEnd = (
SELECT CASE #WeekendDayNameStart
WHEN 'SUNDAY' THEN 'MONDAY'
WHEN 'MONDAY' THEN 'TUESDAY'
WHEN 'TUESDAY' THEN 'WEDNESDAY'
WHEN 'WEDNESDAY' THEN 'THURSDAY'
WHEN 'THURSDAY' THEN 'FRIDAY'
WHEN 'FRIDAY' THEN 'SATURDAY'
WHEN 'SATURDAY' THEN 'SUNDAY'
END
)
DECLARE #NumWorkDays INT
SET #range = DATEDIFF(DAY, #FirstDate, #SecondDate);
SET #NumWorkDays = (
SELECT
#range / 7 * 5 + #range % 7 - (
SELECT COUNT(*)
FROM (
SELECT 1 AS d
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
UNION ALL SELECT 6
UNION ALL SELECT 7
) weekdays
WHERE d <= #range % 7
AND DATENAME(WEEKDAY, #SecondDate - d) IN (#WeekendDayNameStart, #WeekendDayNameEnd))
);
-- Calculate whether the current date is a working day
DECLARE #CurDateExtra INT
SET #CurDateExtra =
(
CASE DATENAME(WEEKDAY, #SecondDate)
WHEN #WeekendDayNameStart THEN 0
WHEN #WeekendDayNameEnd THEN 0
ELSE 1
END
)
SET #NumWorkDays = #NumWorkDays + #CurDateExtra
SELECT #NumWorkDays
Calculates the difference in days between the two dates
Calculates the difference in week numbers and year numbers, subtracts the week numbers and then multiplies the result by 2 to calculate number of non-workdays between the two dates. If year numbers are different calculation of 52 * year difference + week number.
((sysdate - ced.created_dt) + ((((to_char(ced.created_dt,'IW') - ((to_char(sysdate,'YY') - to_char(ced.created_dt,'YY'))* 52))
- to_char(to_char(sysdate,'IW')))) * 2)) duration_in_weekdays
You can try this:
SELECT
Id,
DATEDIFF(d, datefrom, dateto) AS TotDays,
DATEDIFF(wk, datefrom, dateto) AS Wkds,
DATEDIFF(d, datefrom, dateto) - DATEDIFF(wk, datefrom, dateto) AS Days
FROM
YOURTABLE
If your company has a DATES table listing the date and relative work day, as most companies do, you could build a temp table that excludes duplicate relative work days that will also give you the ability to exclude holidays from your calculations as well as weekends.
I would like to build an SQL query which calculates the difference between 2 dates, without counting the week-end days in the result.
Is there any way to format the dates to obtain this result ? For example for Oracle database :
select sysdate - creation_dttm from the_table
You should try with a function :
CREATE FUNCTION TOTAL_WEEKDAYS(date1 DATE, date2 DATE)
RETURNS INT
RETURN ABS(DATEDIFF(date2, date1)) + 1
- ABS(DATEDIFF(ADDDATE(date2, INTERVAL 1 - DAYOFWEEK(date2) DAY),
ADDDATE(date1, INTERVAL 1 - DAYOFWEEK(date1) DAY))) / 7 * 2
- (DAYOFWEEK(IF(date1 < date2, date1, date2)) = 1)
- (DAYOFWEEK(IF(date1 > date2, date1, date2)) = 7);
Test :
SELECT TOTAL_WEEKDAYS('2013-08-03', '2013-08-21') weekdays1,
TOTAL_WEEKDAYS('2013-08-21', '2013-08-03') weekdays2;
Result :
| WEEKDAYS1 | WEEKDAYS2 |
-------------------------
| 13 | 13 |
I have found another way to do calculate the difference, by using only SQL :
select sysdate - creation_dttm
- 2 * (to_char(sysdate, 'WW') - to_char(creation_dttm, 'WW'))
from the_table
I have found several of the answers on this thread to not do what they claim. After some experimentation, testing and adjusting, I have this to contribute.
declare #firstdate Date
declare #seconddate Date
set #firstDate = convert(date, '2016-03-07')
set #seconddate = convert(date, '2016-04-04')
select (datediff(dd, #firstDate, #secondDate)) -
(( DateDiff(wk, #firstDate, #secondDate) * 2) -
case when datepart(dw, #FirstDate) = 7 then 1 else 0 end -
case when datepart(dw, #secondDate) = 7 then -1 else 0 end)
Test harness included - you can just adjust the two dates and run your own tests. This assumes that the difference between two adjacent weekday dates is 1. If your country uses different days to signify weekend, then you will have to set the date-base accordingly so your "Saturday" is 7, and your "sunday" is 1.
From a previous post:
DECLARE #StartDate DATETIME
DECLARE #EndDate DATETIME
SET #StartDate = '2008/10/01'
SET #EndDate = '2008/10/31'
SELECT
(DATEDIFF(dd, #StartDate, #EndDate) + 1)
-(DATEDIFF(wk, #StartDate, #EndDate) * 2)
-(CASE WHEN DATENAME(dw, #StartDate) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, #EndDate) = 'Saturday' THEN 1 ELSE 0 END)
Here is an example:
There are four variables, the first two are self-explanatory, just enter the date in YYYYMMDD format, the 3rd one is to set the number of normal work days in a given week, so if a site works 6 days a week, set it to 6, five days a week enter 5, etc. Finally, the
DATE_SEQ_NORML_FACTOR should be 1 when running against Oracle. This is to line up the Julian date to equal to 1 on Monday, 2 on Tuesday, etc when applying the MOD 7. Other DB will probably have different values between 0 and 6, so test it out before you use against other DBs.
Here are the limitations:
1. This formula assumes the first day of the week is MONDAY.
2. This formula assumes all days within the same week are CONTINUOUS.
3. This formula will work ONLY when the two dates involved in the calculation falls on a week day or work day, eg. the "Start Date" on a SATURDAY when the location works only MON-FRI will not work.
SELECT
&&START_DATE_YYYYMMDD "Start Date", --in YYYYMMDD format
&&END_DATE_YYYYMMDD "End Date", --in YYYYMMDD format
&&WK_WORK_DAY_CNT "Week Work Day Count", --Number of work day per week
&&DATE_SEQ_NORML_FACTOR "Normalization Factor", --set to 1 when run in Oracle
CASE
WHEN
FLOOR( TO_CHAR( TO_DATE( &&START_DATE_YYYYMMDD , 'YYYYMMDD') , 'J' ) + &&DATE_SEQ_NORML_FACTOR / 7 ) =
FLOOR( TO_CHAR( TO_DATE( &&END_DATE_YYYYMMDD , 'YYYYMMDD') , 'J' ) + &&DATE_SEQ_NORML_FACTOR / 7 )
THEN(
TO_CHAR( TO_DATE( &&END_DATE_YYYYMMDD , 'YYYYMMDD') , 'J' ) -
TO_CHAR( TO_DATE( &&START_DATE_YYYYMMDD , 'YYYYMMDD') , 'J' ) + 1
)
ELSE(
(
&&WK_WORK_DAY_CNT - MOD( TO_CHAR( TO_DATE( &&START_DATE_YYYYMMDD , 'YYYYMMDD') , 'J' ) + &&DATE_SEQ_NORML_FACTOR , 7 ) + 1
) +
MOD( TO_CHAR( TO_DATE( &&END_DATE_YYYYMMDD , 'YYYYMMDD') , 'J' ) + &&DATE_SEQ_NORML_FACTOR , 7 ) +
(
(
(
TO_CHAR( TO_DATE( &&END_DATE_YYYYMMDD , 'YYYYMMDD') , 'J' ) -
MOD( TO_CHAR( TO_DATE( &&END_DATE_YYYYMMDD , 'YYYYMMDD') , 'J' ) + &&DATE_SEQ_NORML_FACTOR , 7 )
) -
(
TO_CHAR( TO_DATE( &&START_DATE_YYYYMMDD , 'YYYYMMDD') , 'J' ) +
(
7 -
(
MOD( TO_CHAR( TO_DATE( &&START_DATE_YYYYMMDD , 'YYYYMMDD') , 'J' ) + &&DATE_SEQ_NORML_FACTOR , 7 )
)
)
)
) / 7 * &&WK_WORK_DAY_CNT
)
) END "Week Day Count"
FROM DUAL
We've incorporated the following logic into several reports with great success. Sorry, I no longer recall the source of this script to give them credit.
DECLARE #range INT;
SET #range = DATEDIFF(DAY, #FirstDate, #SecondDate);
SET #NumWorkDays = (
SELECT
#range / 7 * 5 + #range % 7 - (
SELECT COUNT(*)
FROM (
SELECT 1 AS d
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
UNION ALL SELECT 6
UNION ALL SELECT 7
) weekdays
WHERE d <= #range % 7
AND DATENAME(WEEKDAY, #SecondDate - d) IN ('Saturday', 'Sunday'))
);
I've updated #JOpuckman's function to take into account that different regions don't always have a weekend of Saturday and Sunday. Here's the code in case anyone else needs to apply this globally;
DECLARE #FirstDate DateTime
DECLARE #SecondDate DateTime
SET #FirstDate = '08-20-2012'
SET #SecondDate = '08-24-2012'
DECLARE #range INT;
DECLARE #WeekendDayNameStart VARCHAR(50)
DECLARE #WeekendDayNameEnd VARCHAR(50)
SET #WeekendDayNameStart = 'FRIDAY'
SET #WeekendDayNameEnd = (
SELECT CASE #WeekendDayNameStart
WHEN 'SUNDAY' THEN 'MONDAY'
WHEN 'MONDAY' THEN 'TUESDAY'
WHEN 'TUESDAY' THEN 'WEDNESDAY'
WHEN 'WEDNESDAY' THEN 'THURSDAY'
WHEN 'THURSDAY' THEN 'FRIDAY'
WHEN 'FRIDAY' THEN 'SATURDAY'
WHEN 'SATURDAY' THEN 'SUNDAY'
END
)
DECLARE #NumWorkDays INT
SET #range = DATEDIFF(DAY, #FirstDate, #SecondDate);
SET #NumWorkDays = (
SELECT
#range / 7 * 5 + #range % 7 - (
SELECT COUNT(*)
FROM (
SELECT 1 AS d
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
UNION ALL SELECT 6
UNION ALL SELECT 7
) weekdays
WHERE d <= #range % 7
AND DATENAME(WEEKDAY, #SecondDate - d) IN (#WeekendDayNameStart, #WeekendDayNameEnd))
);
-- Calculate whether the current date is a working day
DECLARE #CurDateExtra INT
SET #CurDateExtra =
(
CASE DATENAME(WEEKDAY, #SecondDate)
WHEN #WeekendDayNameStart THEN 0
WHEN #WeekendDayNameEnd THEN 0
ELSE 1
END
)
SET #NumWorkDays = #NumWorkDays + #CurDateExtra
SELECT #NumWorkDays
Calculates the difference in days between the two dates
Calculates the difference in week numbers and year numbers, subtracts the week numbers and then multiplies the result by 2 to calculate number of non-workdays between the two dates. If year numbers are different calculation of 52 * year difference + week number.
((sysdate - ced.created_dt) + ((((to_char(ced.created_dt,'IW') - ((to_char(sysdate,'YY') - to_char(ced.created_dt,'YY'))* 52))
- to_char(to_char(sysdate,'IW')))) * 2)) duration_in_weekdays
You can try this:
SELECT
Id,
DATEDIFF(d, datefrom, dateto) AS TotDays,
DATEDIFF(wk, datefrom, dateto) AS Wkds,
DATEDIFF(d, datefrom, dateto) - DATEDIFF(wk, datefrom, dateto) AS Days
FROM
YOURTABLE
If your company has a DATES table listing the date and relative work day, as most companies do, you could build a temp table that excludes duplicate relative work days that will also give you the ability to exclude holidays from your calculations as well as weekends.