I have the following stored procedure which will generate mon to sun and then creates a temp table with a series of 'weeks' (start and end weeks) :
USE [test_staff]
GO
/****** Object: StoredProcedure [dbo].[sp_timesheets_all_staff_by_week_by_job_grouping_by_site] Script Date: 03/21/2012 09:04:49 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[sp_timesheets_all_staff_by_week_by_job_grouping_by_site]
(
#grouping_ref int,
#week_ref int
)
AS
CREATE TABLE #WeeklyList
(
Start_Week date,
End_Week date,
week_ref int
--month_name date
)
DECLARE #REPORT_DATE DATETIME, #WEEK_BEGINING VARCHAR(10)
SELECT #REPORT_DATE = '2011-01-19T00:00:00'
--SELECT #REPORT_DATE = GETDATE() -- should grab the date now.
SELECT #WEEK_BEGINING = 'MONDAY'
IF #WEEK_BEGINING = 'MONDAY'
SET DATEFIRST 1
ELSE IF #WEEK_BEGINING = 'TUESDAY'
SET DATEFIRST 2
ELSE IF #WEEK_BEGINING = 'WEDNESDAY'
SET DATEFIRST 3
ELSE IF #WEEK_BEGINING = 'THURSDAY'
SET DATEFIRST 4
ELSE IF #WEEK_BEGINING = 'FRIDAY'
SET DATEFIRST 5
ELSE IF #WEEK_BEGINING = 'SATURDAY'
SET DATEFIRST 6
ELSE IF #WEEK_BEGINING = 'SUNDAY'
SET DATEFIRST 7
DECLARE #WEEK_START_DATE DATETIME, #WEEK_END_DATE DATETIME
--GET THE WEEK START DATE
SELECT #WEEK_START_DATE = #REPORT_DATE - (DATEPART(DW, #REPORT_DATE) - 1)
--GET THE WEEK END DATE
SELECT #WEEK_END_DATE = #REPORT_DATE + (7 - DATEPART(DW, #REPORT_DATE))
PRINT 'Week Start: ' + CONVERT(VARCHAR, #WEEK_START_DATE)
PRINT 'Week End: ' + CONVERT(VARCHAR, #WEEK_END_DATE)
DECLARE #Interval int = datediff(WEEK,getdate(),#WEEK_START_DATE)+1
--SELECT Start_Week=#WEEK_START_DATE
--, End_Week=#WEEK_END_DATE
--INTO #WeekList
INSERT INTO #WeeklyList
SELECT Start_Week=#WEEK_START_DATE, End_Week=#WEEK_END_DATE
WHILE #Interval <= 0
BEGIN
set #WEEK_START_DATE=DATEADD(WEEK,1,#WEEK_START_DATE)
set #WEEK_END_DATE=DATEADD(WEEK,1,#WEEK_END_DATE)
INSERT INTO #WeeklyList values (#WEEK_START_DATE,#WEEK_END_DATE)
SET #Interval += 1;
END
SELECT
CONVERT(VARCHAR(11), Start_Week, 106) AS 'month_name',
CONVERT(VARCHAR(11), End_Week, 106) AS 'End',
DATEDIFF(DAY, 0, Start_Week) / 7 AS week_ref -- create the unique week reference number
--'VIEW' AS month_name
FROM #WeeklyList
In this section i am creating the week_ref
DATEDIFF(DAY, 0, Start_Week) / 7 AS week_ref -- create the unique week reference number
I then need to combine it with this select code:
DECLARE #YearString char(3) = CONVERT(char(3), SUBSTRING(CONVERT(char(5), #week_ref), 1, 3))
DECLARE #MonthString char(2) = CONVERT(char(2), SUBSTRING(CONVERT(char(5), #week_ref), 4, 2))
--Convert:
DECLARE #Year int = CONVERT(int, #YearString) + 1200
DECLARE #Month int = CONVERT(int, #MonthString)
**--THIS FILTERS THE REPORT**
SELECT ts.staff_member_ref, sm.common_name, sm.department_name, DATENAME(MONTH, ts.start_dtm) + ' ' + DATENAME(YEAR, ts.start_dtm) AS month_name,
ts.timesheet_cat_ref, cat.desc_long AS timesheet_cat_desc, grps.grouping_ref, grps.description AS grouping_desc, ts.task_ref, tsks.task_code,
tsks.description AS task_desc, ts.site_ref, sits.description AS site_desc, ts.site_ref AS Expr1,
CASE WHEN ts .status = 0 THEN 'Pending' WHEN ts .status = 1 THEN 'Booked' WHEN ts .status = 2 THEN 'Approved' ELSE 'Invalid Status' END AS site_status,
ts.booked_time AS booked_time_sum,
start_dtm, CONVERT(varchar(20), start_dtm, 108) + ' ' + CONVERT(varchar(20), start_dtm, 103) AS start_dtm_text, booked_time,
end_dtm, CONVERT(varchar(20), end_dtm, 108) + ' ' + CONVERT(varchar(20), end_dtm, 103) AS end_dtm_text
FROM timesheets AS ts INNER JOIN
timesheet_categories AS cat ON ts.timesheet_cat_ref = cat.timesheet_cat_ref INNER JOIN
timesheet_tasks AS tsks ON ts.task_ref = tsks.task_ref INNER JOIN
timesheet_task_groupings AS grps ON tsks.grouping_ref = grps.grouping_ref INNER JOIN
timesheet_sites AS sits ON ts.site_ref = sits.site_ref INNER JOIN
vw_staff_members AS sm ON ts.staff_member_ref = sm.staff_member_ref
WHERE (ts.status IN (1, 2)) AND (cat.is_leave_category = 0)
GROUP BY ts.staff_member_ref, sm.common_name, sm.department_name, DATENAME(MONTH, ts.start_dtm), DATENAME(YEAR, ts.start_dtm), ts.timesheet_cat_ref,
cat.desc_long, grps.grouping_ref, grps.description, ts.status, ts.booked_time, ts.task_ref, tsks.task_code, tsks.description, ts.site_ref, sits.description, ts.start_dtm,
ts.end_dtm
ORDER BY sm.common_name, timesheet_cat_desc, tsks.task_code, site_desc
DROP TABLE #WeeklyList
GO
I want to pass the week_ref into the SELECT statement (refer to comment - THIS FILTERS THE REPORT) but the problem is week_ref isnt a valid column as its derived by code.
Any ideas?
Just perform an INNER JOIN to your weeklylist temp table on the date you need to filter.
I am not sure that I really understand the problem but I found 2 problems in the code you posted.
The inserts you make on the #WeeklyList temporary table, are missing one column in the selected values that I assume you wanted to be your variable #week_ref
I I change this, I get to the point of the final table select that I dont have.
hope this is a start to solve your problem
Related
I have a field named 'AirDate' which is in mm/dd/yyyy format. I'd like to create a 'WeekOf' field which uses the AirDate field to give me the WeekOf date using Tuesday as the start of the week.
AirDate = 11/11/2019, WeekOf = 11/5/2019
AirDate = 11/12/2019, WeekOf = 11/12/2019
AirDate = 11/13/2019, WeekOf = 11/12/2019
etc.
What's the proper way to write the query to return the 'WeekOf' date in this format?
sql server you can use datefirst to set tuesday. See documentation
set datefirst 2
select wkTuesday = dateadd(dd, (-1)* (datepart(dw,'11/11/2019')-1), '11/11/2019')
set datefirst 7
Try this
and replace getdate() with the date that you want
SELECT dateadd(dd, (-1 * DATEPART(WEEKDAY, getdate())) + 1, getdate())
EDIT
declare #YourDate date = '19 NOv 2019'
declare #DayNo int
SET #DayNo = CASE WHEN DATEPART(WEEKDAY, #YourDate) < 3 THEN DATEPART(WEEKDAY, #YourDate) + 5 ELSE DATEPART(WEEKDAY, #YourDate) - 2 END
SELECT 'AirDate = ' + cast(#YourDate as varchar(100)) + ' , WeekOf = ' + cast( dateadd(dd, (-1 * #DayNo) + 1, #YourDate) as varchar(100))
Is it possible to find the closest future date (datetime) by a date varchar value?
Given,
DECLARE #DayValue VARCHAR(3)
, #DateValue DATETIME
SET #DayValue = 'Tue' -- Values could be 'Mon', 'Tue', 'Wed' and etc.
SET #DateValue = '10/15/2014' -- Format is MM/dd/yyyy
I want to get:
Oct 21 2014 12:00AM
Using Loop,
DECLARE #DayValue VARCHAR(3)
,#DateValue DATETIME
SET #DayValue = 'tue'
SET #DateValue = '10/15/2014'
declare #i int= 1 ,#day varchar(3) = null
while (#i<=7 )
begin
Select #day = left(datename (dw,#DateValue),3)
if #day = #DayValue
begin
Select #DateValue
break
end
Select #DateValue = #DateValue+ 1
Select #i = #i+1
end
You could use this function if you had a date-table:
CREATE FUNCTION [dbo].[GetNextDayOfWeek]
( #DayOfWeek VARCHAR(3),
#DateValue datetime
)
RETURNS SmallDateTime
AS
BEGIN
DECLARE #NextDayOfWeek smalldatetime
SET #NextDayOfWeek = (
SELECT
MIN(d.Date)
FROM
tDefDate d
WHERE
d.Date > #DateValue
AND LEFT(DATENAME(Weekday, d.Date), 3) = #DayOfWeek);
RETURN #NextDayOfWeek
END
Then it's simple as:
select [dbo].[GetNextDayOfWeek]('Tue', Getdate()) -- next tuesday=> 2014-10-21
Note that it takes the language of the database into account. So if it's in german:
select [dbo].[GetNextDayOfWeek]('Die', Getdate()) -- next tuesday(Dienstag)
Here's a version that works also without a date-table (but is less efficient).
CREATE FUNCTION [dbo].[GetNextDayOfWeek]
( #DayOfWeek VARCHAR(3),
#DateValue datetime
)
RETURNS SmallDateTime
AS
BEGIN
DECLARE #NextDayOfWeek smalldatetime
;WITH CTE as
(
SELECT GetDate() DateValue, DayNum=0
UNION ALL
SELECT DateValue + 1, DayNum=DayNum+1
FROM CTE
WHERE DayNum <=7
)
SELECT #NextDayOfWeek = (
SELECT
MIN(d.DateValue)
FROM
CTE d
WHERE d.DateValue > #DateValue
AND LEFT(DATENAME(Weekday, d.DateValue), 3) = #DayOfWeek
)OPTION (MAXRECURSION 8);
RETURN #NextDayOfWeek
END
If you could define DayValue as an integer, you solve this problem with more elegant way:
DECLARE #DayValue int, #DateValue DATETIME
SET #DayValue = 3 -- Values could be 1-Sun, 2-Mon, 3-Tue, 4-Wed and etc.
SET #DateValue = '10/15/2014' -- Format is MM/dd/yyyy
select dateadd(day,(7 + #DayValue - datepart(w,#DateValue)), #DateValue)
TRY SQL FIDDLE DEMO
No loops and will work in selects with multiple rows. :)
DECLARE #DayValue CHAR(3)
DECLARE #DateValue DATETIME
DECLARE #FutureDate DATE
SET #DayValue='MON'
SET #DateValue='10/12/2014'
DECLARE #Days TABLE
(
[DayOfWeek] TINYINT,
[DayValue] CHAR(3)
)
INSERT INTO #Days([DayOfWeek],[DayValue])
SELECT 0,'SUN' UNION
SELECT 1,'MON' UNION
SELECT 2,'TUE' UNION
SELECT 3,'WED' UNION
SELECT 4,'THU' UNION
SELECT 5,'FRI' UNION
SELECT 6,'SAT'
SET #FutureDate=
DATEADD(DAY,
--Skip to next week if we are already on the desired day or past it
+ CASE WHEN ((SELECT [DayOfWeek] FROM #Days WHERE [DayValue]=#DayValue)<DATEPART(WEEKDAY,#DateValue)) THEN 7 ELSE 0 END
--reset to start of week (add one as DATEPART is base 1, not base 0)
- DATEPART(WEEKDAY,#DateValue) + 1
--Add the desired day of the week
+ (SELECT [DayOfWeek] FROM #Days WHERE [DayValue]=#DayValue)
,#DateValue)
SELECT #FutureDate
This is a bit chunky solution, but it works. :)
SET DATEFIRST 1
DECLARE #DateValue DateTime
, #DayValue VARCHAR(3)
, #tmp INT
SET #DateValue = '09/30/2014'
SET #DayValue = 'wed'
SET #tmp = CASE #DayValue
WHEN 'Mon' THEN (1 - DATEPART(dw, #DateValue) + 7) % 7
WHEN 'Tue' THEN (2 - DATEPART(dw, #DateValue) + 7) % 7
WHEN 'Wed' THEN (3 - DATEPART(dw, #DateValue) + 7) % 7
WHEN 'Thu' THEN (4 - DATEPART(dw, #DateValue) + 7) % 7
WHEN 'Fri' THEN (5 - DATEPART(dw, #DateValue) + 7) % 7
WHEN 'Sat' THEN (6 - DATEPART(dw, #DateValue) + 7) % 7
WHEN 'Sun' THEN (7 - DATEPART(dw, #DateValue) + 7) % 7
END
SELECT
CASE
WHEN #tmp = 0 THEN DATEADD (DAY, 7, #DateValue)
ELSE DATEADD (DAY, #tmp, #DateValue)
END
IF OBJECT_ID('dbo.DimensionDate', 'U') IS NOT NULL
DROP TABLE dbo.DimensionDate
/**********************************************************************************/
CREATE TABLE [dbo].[DimensionDate]
( [DateKey] INT primary key,
[Date] DATETIME,
[FullDate] CHAR(10),-- Date in dd-MM-yyyy format
[DayOfMonth] VARCHAR(2), -- Field will hold day number of Month
[DaySuffix] VARCHAR(4), -- Apply suffix as 1st, 2nd ,3rd etc
[DayName] VARCHAR(9), -- Contains name of the day, Sunday, Monday
[DayOfWeekIRE] CHAR(1),-- First Day Monday=1 and Sunday=7
[DayOfWeekInMonth] VARCHAR(2), --1st Monday or 2nd Monday in Month
[DayOfWeekInYear] VARCHAR(2),
[DayOfQuarter] VARCHAR(3),
[DayOfYear] VARCHAR(3),
[WeekOfMonth] VARCHAR(1),-- Week Number of Month
[WeekOfQuarter] VARCHAR(2), --Week Number of the Quarter
[WeekOfYear] VARCHAR(2),--Week Number of the Year
[Month] VARCHAR(2), --Number of the Month 1 to 12
[MonthName] VARCHAR(9),--January, February etc
[MonthOfQuarter] VARCHAR(2),-- Month Number belongs to Quarter
[Quarter] CHAR(1),
[QuarterName] VARCHAR(9),--First,Second..
[Year] CHAR(4),-- Year value of Date stored in Row
[YearName] CHAR(7), --CY 2012,CY 2013
[MonthYear] CHAR(10), --Jan-2013,Feb-2013
[MMYYYY] CHAR(6),
[FirstDayOfMonth] DATE,
[LastDayOfMonth] DATE,
[FirstDayOfQuarter] DATE,
[LastDayOfQuarter] DATE,
[FirstDayOfYear] DATE,
[LastDayOfYear] DATE,
[IsHolidayIRE] BIT,-- Flag 1=National Holiday, 0-No National Holiday
[IsWeekday] BIT,-- 0=Week End ,1=Week Day
[HolidayIRE] VARCHAR(50),--Name of Holiday in US
[IsHolidayUK] BIT Null,-- Flag 1=National Holiday, 0-No National Holiday
[HolidayUK] VARCHAR(50) Null, --Name of Holiday in UK
[PastOrFuture] BIT Null -- Flag 0=Past, 1=Future
)
GO
TRUNCATE Table Dbo.DimensionDate
/********************************************************************************************/
--Specify Start Date and End date here
--Value of Start Date Must be Less than Your End Date
DECLARE #StartDate DATETIME = '04/01/2012' --Starting value of Date Range
DECLARE #EndDate DATETIME = '04/01/2015' --End Value of Date Range
--Temporary Variables To Hold the Values During Processing of Each Date of Year
DECLARE
#DayOfWeekInMonth INT,
#DayOfWeekInYear INT,
#DayOfQuarter INT,
#WeekOfMonth INT,
#CurrentYear INT,
#CurrentMonth INT,
#CurrentQuarter INT
/*Table Data type to store the day of week count for the month and year*/
DECLARE #DayOfWeek TABLE (DOW INT, MonthCount INT, QuarterCount INT, YearCount INT)
INSERT INTO #DayOfWeek VALUES (1, 0, 0, 0)
INSERT INTO #DayOfWeek VALUES (2, 0, 0, 0)
INSERT INTO #DayOfWeek VALUES (3, 0, 0, 0)
INSERT INTO #DayOfWeek VALUES (4, 0, 0, 0)
INSERT INTO #DayOfWeek VALUES (5, 0, 0, 0)
INSERT INTO #DayOfWeek VALUES (6, 0, 0, 0)
INSERT INTO #DayOfWeek VALUES (7, 0, 0, 0)
--Extract and assign various parts of Values from Current Date to Variable
DECLARE #CurrentDate AS DATETIME = #StartDate
SET #CurrentMonth = DATEPART(MM, #CurrentDate)
SET #CurrentYear = DATEPART(YY, #CurrentDate)
SET #CurrentQuarter = DATEPART(QQ, #CurrentDate)
SET #startDate = GETDATE()
/********************************************************************************************/
--Proceed only if Start Date(Current date ) is less than End date you specified above
WHILE #CurrentDate < #EndDate
BEGIN
/*Begin day of week logic*/
/*Check for Change in Month of the Current date if Month changed then
Change variable value*/
IF #CurrentMonth != DATEPART(MM, #CurrentDate)
BEGIN
UPDATE #DayOfWeek
SET MonthCount = 0
SET #CurrentMonth = DATEPART(MM, #CurrentDate)
END
/* Check for Change in Quarter of the Current date if Quarter changed then change
Variable value*/
IF #CurrentQuarter != DATEPART(QQ, #CurrentDate)
BEGIN
UPDATE #DayOfWeek
SET QuarterCount = 0
SET #CurrentQuarter = DATEPART(QQ, #CurrentDate)
END
/* Check for Change in Year of the Current date if Year changed then change
Variable value*/
IF #CurrentYear != DATEPART(YY, #CurrentDate)
BEGIN
UPDATE #DayOfWeek
SET YearCount = 0
SET #CurrentYear = DATEPART(YY, #CurrentDate)
END
-- Set values in table data type created above from variables
UPDATE #DayOfWeek
SET
MonthCount = MonthCount + 1,
QuarterCount = QuarterCount + 1,
YearCount = YearCount + 1
WHERE DOW = DATEPART(DW, #CurrentDate)
SELECT
#DayOfWeekInMonth = MonthCount,
#DayOfQuarter = QuarterCount,
#DayOfWeekInYear = YearCount
FROM #DayOfWeek
WHERE DOW = DATEPART(DW, #CurrentDate)
/End day of week logic/
/* Populate Your Dimension Table with values*/
INSERT INTO [dbo].[DimensionDate]
SELECT
CONVERT (char(8),#CurrentDate,112) as DateKey,
#CurrentDate AS Date,
CONVERT (char(10),#CurrentDate,103) as FullDate,
DATEPART(DD, #CurrentDate) AS DayOfMonth,
--Apply Suffix values like 1st, 2nd 3rd etc..
CASE
WHEN DATEPART(DD,#CurrentDate) IN (11,12,13)
THEN CAST(DATEPART(DD,#CurrentDate) AS VARCHAR) + 'th'
WHEN RIGHT(DATEPART(DD,#CurrentDate),1) = 1
THEN CAST(DATEPART(DD,#CurrentDate) AS VARCHAR) + 'st'
WHEN RIGHT(DATEPART(DD,#CurrentDate),1) = 2
THEN CAST(DATEPART(DD,#CurrentDate) AS VARCHAR) + 'nd'
WHEN RIGHT(DATEPART(DD,#CurrentDate),1) = 3
THEN CAST(DATEPART(DD,#CurrentDate) AS VARCHAR) + 'rd'
ELSE CAST(DATEPART(DD,#CurrentDate) AS VARCHAR) + 'th'
END AS DaySuffix,
DATENAME(DW, #CurrentDate) AS DayName,
-- check for day of week as Per US and change it as per UK format
CASE DATEPART(DW, #CurrentDate)
WHEN 1 THEN 7
WHEN 2 THEN 1
WHEN 3 THEN 2
WHEN 4 THEN 3
WHEN 5 THEN 4
WHEN 6 THEN 5
WHEN 7 THEN 6
END
AS DayOfWeekIRE,
#DayOfWeekInMonth AS DayOfWeekInMonth,
#DayOfWeekInYear AS DayOfWeekInYear,
#DayOfQuarter AS DayOfQuarter,
DATEPART(DY, #CurrentDate) AS DayOfYear,
DATEPART(WW, #CurrentDate) + 1 - DATEPART(WW, CONVERT(VARCHAR,
DATEPART(MM, #CurrentDate)) + '/1/' + CONVERT(VARCHAR,
DATEPART(YY, #CurrentDate))) AS WeekOfMonth,
(DATEDIFF(DD, DATEADD(QQ, DATEDIFF(QQ, 0, #CurrentDate), 0),
#CurrentDate) / 7) + 1 AS WeekOfQuarter,
DATEPART(WW, #CurrentDate) AS WeekOfYear,
DATEPART(MM, #CurrentDate) AS Month,
DATENAME(MM, #CurrentDate) AS MonthName,
CASE
WHEN DATEPART(MM, #CurrentDate) IN (1, 4, 7, 10) THEN 1
WHEN DATEPART(MM, #CurrentDate) IN (2, 5, 8, 11) THEN 2
WHEN DATEPART(MM, #CurrentDate) IN (3, 6, 9, 12) THEN 3
END AS MonthOfQuarter,
DATEPART(QQ, #CurrentDate) AS Quarter,
CASE DATEPART(QQ, #CurrentDate)
WHEN 1 THEN 'First'
WHEN 2 THEN 'Second'
WHEN 3 THEN 'Third'
WHEN 4 THEN 'Fourth'
END AS QuarterName,
DATEPART(YEAR, #CurrentDate) AS Year,
'CY ' + CONVERT(VARCHAR, DATEPART(YEAR, #CurrentDate)) AS YearName,
LEFT(DATENAME(MM, #CurrentDate), 3) + '-' + CONVERT(VARCHAR,
DATEPART(YY, #CurrentDate)) AS MonthYear,
RIGHT('0' + CONVERT(VARCHAR, DATEPART(MM, #CurrentDate)),2) +
CONVERT(VARCHAR, DATEPART(YY, #CurrentDate)) AS MMYYYY,
CONVERT(DATETIME, CONVERT(DATE, DATEADD(DD, - (DATEPART(DD,
#CurrentDate) - 1), #CurrentDate))) AS FirstDayOfMonth,
CONVERT(DATETIME, CONVERT(DATE, DATEADD(DD, - (DATEPART(DD,
(DATEADD(MM, 1, #CurrentDate)))), DATEADD(MM, 1,
#CurrentDate)))) AS LastDayOfMonth,
DATEADD(QQ, DATEDIFF(QQ, 0, #CurrentDate), 0) AS FirstDayOfQuarter,
DATEADD(QQ, DATEDIFF(QQ, -1, #CurrentDate), -1) AS LastDayOfQuarter,
CONVERT(DATETIME, '01/01/' + CONVERT(VARCHAR, DATEPART(YY,
#CurrentDate))) AS FirstDayOfYear,
CONVERT(DATETIME, '12/31/' + CONVERT(VARCHAR, DATEPART(YY,
#CurrentDate))) AS LastDayOfYear,
NULL AS IsHolidayIRE,
CASE DATEPART(DW, #CurrentDate)
WHEN 1 THEN 0
WHEN 2 THEN 1
WHEN 3 THEN 1
WHEN 4 THEN 1
WHEN 5 THEN 1
WHEN 6 THEN 1
WHEN 7 THEN 0
END AS IsWeekday,
NULL AS HolidayIRE, Null, Null
UPDATE
DimensionDate
SET [PastOrFuture] =
CASE
WHEN #StartDate <= [DATE] THEN 0
ELSE 1
END
SET #CurrentDate = DATEADD(DD, 1, #CurrentDate)
END
SELECT * FROM DimensionDate
Msg 213, Level 16, State 1, Line 99 Column name or number of supplied values does not match table definition.
I just want to fix the update in at the bottom of this code its not letting me update PastOrFuture Column to 0 or 1 depending on the date
It works perfect if i take out my update and put back in the null.
Try removing your update statement and replace the following code at the and check?
.... NULL AS HolidayIRE, Null, Null,
CASE
WHEN #StartDate <= [DATE] THEN 0
ELSE 1
END
FROM DimensionDate
I think you are trying to update in insert. You can calculate past of future in the select statement itself
Your INSERT into DimensionDate is short a column.
You have 3 columns after HolidayIRE, but your insert only has 2 NULLS after the case for HolidayIRE
Either add a column list to the insert, or add another NULL to the end of the insert.
For that matter, no need to UPDATE just tack your case on the end of the INSERT and make the case the last column and insert the PastOrFuture on the fly...
CASE
WHEN #StartDate <= [DATE] THEN 0
ELSE 1
END
You did not supply pastorfuture, count your fields vs the table. you have HolidayIRE, null, null and the table reads HolidayIRE, IsHolidayUK, HolidayUK, PastOrFuture
I need an algorithm for calculating the number of the day of the week in the month. Like 1st Friday of the month, 3rd Monday of the month, etc.)
Any ideas are appreciated.
Here is the final result:
declare #dt date = GetDate()
declare #DayOfWeek tinyint = datepart(weekday,#dt)
declare #DayOfMonth smallint = day(#dt)
declare #FirstDayOfMonth date = dateadd(month,datediff(month,0,#dt),0)
declare #DayOfWeekInMonth tinyint = #DayOfMonth / 7 + 1 -
(case when day(#FirstDayOfMonth) > day(#dt) then 1 else 0 end)
declare #Suffix varchar(2) =
case
when #DayOfWeekInMonth = 1 then 'st'
when #DayOfWeekInMonth = 2 then 'nd'
when #DayOfWeekInMonth = 3 then 'rd'
when #DayOfWeekInMonth > 3 then 'th'
end
select
cast(#DayOfWeekInMonth as varchar(2))
+ #Suffix
+ ' '
+ datename(weekday,#Dt)
+ ' of '
+ datename(month,#dt)
+ ', '
+ datename(year,#Dt)
PS: And if you can think of a better way to state the problem, please do.
Followint code will give you 1st Wednesday of April 2014 for today:
SELECT cast((DATEPART(d, GETDATE() - 1) / 7) + 1 as varchar(12))
+ 'st ' + DATENAME(WEEKDAY, getdate()) + ' of ' +
DATENAME(month, getdate()) + ' ' + DATENAME(year, getdate());
For any date use the code below. It gives 5th Tuesday of April 2014 for #mydate = '2014-04-29' in the example:
DECLARE #mydate DATETIME;
SET #mydate = '2014-04-29';
SELECT
case
when DATEPART(d, #mydate) = 1 then cast((DATEPART(d, #mydate ) / 7) + 1 as varchar(12))
else cast((DATEPART(d, #mydate - 1) / 7) + 1 as varchar(12))
end
+
case
when (DATEPART(d, #mydate - 1) / 7) + 1 = 1 then 'st '
when (DATEPART(d, #mydate - 1) / 7) + 1 = 2 then 'nd '
when (DATEPART(d, #mydate - 1) / 7) + 1 = 3 then 'rd '
else 'th '
end
+ DATENAME(WEEKDAY, #mydate) + ' of ' +
DATENAME(month, #mydate) + ' ' + DATENAME(year, #mydate) as [Long Date Name]
Okeeeey my tuuuurn ,
Please rate my answer Metaphor hhh, Here's the cooode :
declare #v_month nvarchar(2) = '04'
,#v_annee nvarchar(4) = '2014'
declare #v_date date = convert(date,#v_annee+'-'+#v_month+'-01')
declare #v_date_2 date = dateadd(M,1,#v_date)
if OBJECT_ID('temp') is not null
drop table temp
create table temp(_date date, _DayOfMonth nvarchar(20), _order int)
while (#v_date<#v_date_2)
begin
set #v_date =#v_date;
WITH _DayOfWeek AS (
SELECT 1 id, 'monday' Name UNION ALL
SELECT 2 id, 'tuesday' Name UNION ALL
SELECT 3 id, 'wednesday' Name UNION ALL
SELECT 4 id, 'thursday' Name UNION ALL
SELECT 5 id, 'friday' Name UNION ALL
SELECT 6 id, 'saturday' Name UNION ALL
SELECT 7 id, 'sunday' Name)
insert into temp(_date,_DayOfMonth)
SELECT
#v_date
,(select Name from _DayOfWeek where id = DATEPART(WEEKDAY,#v_date))
SET #v_date = DATEADD(DAY,1,#v_date)
END
UPDATE tmp1
SET _order = _order_2
FROM temp tmp1
INNER JOIN
(SELECT *, ROW_NUMBER() OVER(PARTITION BY _DayOfMonth ORDER BY _date ASC) AS _order_2 FROM temp) tmp2
ON tmp1._date = tmp2._date
SELECT * FROM temp
SELECT *
FROM temp
WHERE _DayOfMonth = 'thursday'
AND _order = 3
I hope this will help you :)
Good Luck
OK, here's what I came up with, I'll +1 everyone who answered anyway:
declare #dt date = GetDate()
declare #DayOfWeek tinyint = datepart(weekday,#dt)
declare #DayOfMonth smallint = day(#dt)
declare #FirstDayOfMonth date = dateadd(month,datediff(month,0,#dt),0)
declare #DayOfWeekInMonth tinyint =
#DayOfMonth / 7 + 1
- (case when day(#FirstDayOfMonth) > day(#dt) then 1 else 0 end)
declare #Suffix varchar(2) =
case
when #DayOfWeekInMonth = 1 then 'st'
when #DayOfWeekInMonth = 2 then 'nd'
when #DayOfWeekInMonth = 3 then 'rd'
when #DayOfWeekInMonth > 3 then 'th'
end
select
cast(#DayOfWeekInMonth as varchar(2))
+ #Suffix
+ ' '
+ datename(weekday,#Dt)
+ ' of '
+ datename(month,#dt)
+ ', '
+ datename(year,#Dt)
declare #dt date = getdate()
declare #DayOfMonth smallint = datepart(d, #dt)
declare #Suffix varchar(2) =
case
when floor((#DayOfMonth - 1) / 7.0) = 0 then 'st' -- implies there were no such days previously in the month
when floor((#DayOfMonth - 1) / 7.0) = 1 then 'nd'
when floor((#DayOfMonth - 1) / 7.0) = 2 then 'rd'
else 'th'
end
select cast(floor((#DayOfMonth - 1) / 7.0) + 1 as varchar(1)) + #Suffix +
' ' + datename(weekday, #dt) + ' of ' + datename(month, #dt) +
', ' + datename(year, #dt)
DECLARE #dt DATETIME
SET #dt = DATEADD(d, 6, GETDATE())
SELECT #dt,
CAST((DAY(#dt) / 7) + CASE WHEN DATEPART(weekday, #dt) >= DATEPART(weekday, CAST(MONTH(#dt) AS NVARCHAR) + '/01/' + CAST(YEAR(#dt) AS NVARCHAR)) THEN 1 ELSE 0 END AS NVARCHAR)
+ '' + CASE (DAY(#dt) / 7) + CASE WHEN DATEPART(weekday, #dt) >= DATEPART(weekday, CAST(MONTH(#dt) AS NVARCHAR) + '/01/' + CAST(YEAR(#dt) AS NVARCHAR)) THEN 1 ELSE 0 END
WHEN 1 THEN N'st'
WHEN 2 THEN N'nd'
WHEN 3 THEN N'rd'
ELSE N'th'
END
+ ' ' + DATENAME(dw, #dt)
+ ' of ' + DATENAME(M, #dt)
+ ', ' + CAST(YEAR(#dt) AS NVARCHAR)
Result is a single SELECT (provided the assignment of #dt happened earlier) but is, essentially, the same logic as yours.
This following code will give you DATE for any day of the week in any month or year that you specify. All the variables that I have are to reduce repeating logic to improve code speed.
This code gives you date for 1st Monday in February in 2013
DECLARE #DayNumber INT = 1
,#DayWeekNumber INT = 2
,#MonthNumber INT = 2
,#YearNumber INT = 2013
,#FoM DATE
,#FoMWD INT;
SET #FoM = DATEFROMPARTS(#YearNumber,#MonthNumber,1)
SET #fomwd = DATEPART(WEEKDAY, #FoM);
SELECT CASE WHEN #fomwd = #DayWeekNumber THEN DATEADD(WEEK, #DayNumber - 1, #FoM)
WHEN #fomwd < #DayWeekNumber THEN DATEADD(DAY, #DayWeekNumber - #fomwd, DATEADD(WEEK, #DayNumber - 1, #FoM))
WHEN #fomwd > #DayWeekNumber THEN DATEADD(DAY, #DayWeekNumber - #fomwd, DATEADD(WEEK, #DayNumber, #FoM))
END AS DateOfDay;
I want to calculate the number of working days between 2 given dates. For example if I want to calculate the working days between 2013-01-10 and 2013-01-15, the result must be 3 working days (I don't take into consideration the last day in that interval and I subtract the Saturdays and Sundays). I have the following code that works for most of the cases, except the one in my example.
SELECT (DATEDIFF(day, '2013-01-10', '2013-01-15'))
- (CASE WHEN DATENAME(weekday, '2013-01-10') = 'Sunday' THEN 1 ELSE 0 END)
- (CASE WHEN DATENAME(weekday, DATEADD(day, -1, '2013-01-15')) = 'Saturday' THEN 1 ELSE 0 END)
How can I accomplish this? Do I have to go through all the days and check them? Or is there an easy way to do this.
Please, please, please use a calendar table. SQL Server doesn't know anything about national holidays, company events, natural disasters, etc. A calendar table is fairly easy to build, takes an extremely small amount of space, and will be in memory if it is referenced enough.
Here is an example that creates a calendar table with 30 years of dates (2000 -> 2029) but requires only 200 KB on disk (136 KB if you use page compression). That is almost guaranteed to be less than the memory grant required to process some CTE or other set at runtime.
CREATE TABLE dbo.Calendar
(
dt DATE PRIMARY KEY, -- use SMALLDATETIME if < SQL Server 2008
IsWorkDay BIT
);
DECLARE #s DATE, #e DATE;
SELECT #s = '2000-01-01' , #e = '2029-12-31';
INSERT dbo.Calendar(dt, IsWorkDay)
SELECT DATEADD(DAY, n-1, '2000-01-01'), 1
FROM
(
SELECT TOP (DATEDIFF(DAY, #s, #e)+1) ROW_NUMBER()
OVER (ORDER BY s1.[object_id])
FROM sys.all_objects AS s1
CROSS JOIN sys.all_objects AS s2
) AS x(n);
SET DATEFIRST 1;
-- weekends
UPDATE dbo.Calendar SET IsWorkDay = 0
WHERE DATEPART(WEEKDAY, dt) IN (6,7);
-- Christmas
UPDATE dbo.Calendar SET IsWorkDay = 0
WHERE MONTH(dt) = 12
AND DAY(dt) = 25
AND IsWorkDay = 1;
-- continue with other holidays, known company events, etc.
Now the query you're after is quite simple to write:
SELECT COUNT(*) FROM dbo.Calendar
WHERE dt >= '20130110'
AND dt < '20130115'
AND IsWorkDay = 1;
More info on calendar tables:
http://web.archive.org/web/20070611150639/http://sqlserver2000.databases.aspfaq.com/why-should-i-consider-using-an-auxiliary-calendar-table.html
More info on generating sets without loops:
http://www.sqlperformance.com/tag/date-ranges
Also beware of little things like relying on the English output of DATENAME. I've seen several applications break because some users had a different language setting, and if you're relying on WEEKDAY be sure you set your DATEFIRST setting appropriately...
For stuff like this i tend to maintain a calendar table that also includes bank holidays etc.
The script i use for this is as follows (Note that i didnt write it # i forget where i found it)
SET DATEFIRST 1
SET NOCOUNT ON
GO
--Create ISO week Function (thanks BOL)
CREATE FUNCTION ISOweek ( #DATE DATETIME )
RETURNS INT
AS
BEGIN
DECLARE #ISOweek INT
SET #ISOweek = DATEPART(wk, #DATE) + 1 - DATEPART(wk, CAST(DATEPART(yy, #DATE) AS CHAR(4)) + '0104')
--Special cases: Jan 1-3 may belong to the previous year
IF ( #ISOweek = 0 )
SET #ISOweek = dbo.ISOweek(CAST(DATEPART(yy, #DATE) - 1 AS CHAR(4)) + '12' + CAST(24 + DATEPART(DAY, #DATE) AS CHAR(2))) + 1
--Special case: Dec 29-31 may belong to the next year
IF ( ( DATEPART(mm, #DATE) = 12 )
AND ( ( DATEPART(dd, #DATE) - DATEPART(dw, #DATE) ) >= 28 )
)
SET #ISOweek = 1
RETURN(#ISOweek)
END
GO
--END ISOweek
--CREATE Easter algorithm function
--Thanks to Rockmoose (http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=45689)
CREATE FUNCTION fnDLA_GetEasterdate ( #year INT )
RETURNS CHAR(8)
AS
BEGIN
-- Easter date algorithm of Delambre
DECLARE #A INT ,
#B INT ,
#C INT ,
#D INT ,
#E INT ,
#F INT ,
#G INT ,
#H INT ,
#I INT ,
#K INT ,
#L INT ,
#M INT ,
#O INT ,
#R INT
SET #A = #YEAR % 19
SET #B = #YEAR / 100
SET #C = #YEAR % 100
SET #D = #B / 4
SET #E = #B % 4
SET #F = ( #B + 8 ) / 25
SET #G = ( #B - #F + 1 ) / 3
SET #H = ( 19 * #A + #B - #D - #G + 15 ) % 30
SET #I = #C / 4
SET #K = #C % 4
SET #L = ( 32 + 2 * #E + 2 * #I - #H - #K ) % 7
SET #M = ( #A + 11 * #H + 22 * #L ) / 451
SET #O = 22 + #H + #L - 7 * #M
IF #O > 31
BEGIN
SET #R = #O - 31 + 400 + #YEAR * 10000
END
ELSE
BEGIN
SET #R = #O + 300 + #YEAR * 10000
END
RETURN #R
END
GO
--END fnDLA_GetEasterdate
--Create the table
CREATE TABLE MyDateTable
(
FullDate DATETIME NOT NULL
CONSTRAINT PK_FullDate PRIMARY KEY CLUSTERED ,
Period INT ,
ISOWeek INT ,
WorkingDay VARCHAR(1) CONSTRAINT DF_MyDateTable_WorkDay DEFAULT 'Y'
)
GO
--End table create
--Populate table with required dates
DECLARE #DateFrom DATETIME ,
#DateTo DATETIME ,
#Period INT
SET #DateFrom = CONVERT(DATETIME, '20000101')
--yyyymmdd (1st Jan 2000) amend as required
SET #DateTo = CONVERT(DATETIME, '20991231')
--yyyymmdd (31st Dec 2099) amend as required
WHILE #DateFrom <= #DateTo
BEGIN
SET #Period = CONVERT(INT, LEFT(CONVERT(VARCHAR(10), #DateFrom, 112), 6))
INSERT MyDateTable
( FullDate ,
Period ,
ISOWeek
)
SELECT #DateFrom ,
#Period ,
dbo.ISOweek(#DateFrom)
SET #DateFrom = DATEADD(dd, +1, #DateFrom)
END
GO
--End population
/* Start of WorkingDays UPDATE */
UPDATE MyDateTable
SET WorkingDay = 'B' --B = Bank Holiday
--------------------------------EASTER---------------------------------------------
WHERE FullDate = DATEADD(dd, -2, CONVERT(DATETIME, dbo.fnDLA_GetEasterdate(DATEPART(yy, FullDate)))) --Good Friday
OR FullDate = DATEADD(dd, +1, CONVERT(DATETIME, dbo.fnDLA_GetEasterdate(DATEPART(yy, FullDate))))
--Easter Monday
GO
UPDATE MyDateTable
SET WorkingDay = 'B'
--------------------------------NEW YEAR-------------------------------------------
WHERE FullDate IN ( SELECT MIN(FullDate)
FROM MyDateTable
WHERE DATEPART(mm, FullDate) = 1
AND DATEPART(dw, FullDate) NOT IN ( 6, 7 )
GROUP BY DATEPART(yy, FullDate) )
---------------------MAY BANK HOLIDAYS(Always Monday)------------------------------
OR FullDate IN ( SELECT MIN(FullDate)
FROM MyDateTable
WHERE DATEPART(mm, FullDate) = 5
AND DATEPART(dw, FullDate) = 1
GROUP BY DATEPART(yy, FullDate) )
OR FullDate IN ( SELECT MAX(FullDate)
FROM MyDateTable
WHERE DATEPART(mm, FullDate) = 5
AND DATEPART(dw, FullDate) = 1
GROUP BY DATEPART(yy, FullDate) )
--------------------AUGUST BANK HOLIDAY(Always Monday)------------------------------
OR FullDate IN ( SELECT MAX(FullDate)
FROM MyDateTable
WHERE DATEPART(mm, FullDate) = 8
AND DATEPART(dw, FullDate) = 1
GROUP BY DATEPART(yy, FullDate) )
--------------------XMAS(Move to next working day if on Sat/Sun)--------------------
OR FullDate IN ( SELECT CASE WHEN DATEPART(dw, FullDate) IN ( 6, 7 ) THEN DATEADD(dd, +2, FullDate)
ELSE FullDate
END
FROM MyDateTable
WHERE DATEPART(mm, FullDate) = 12
AND DATEPART(dd, FullDate) IN ( 25, 26 ) )
GO
---------------------------------------WEEKENDS--------------------------------------
UPDATE MyDateTable
SET WorkingDay = 'N'
WHERE DATEPART(dw, FullDate) IN ( 6, 7 )
GO
/* End of WorkingDays UPDATE */
--SELECT * FROM MyDateTable ORDER BY 1
DROP FUNCTION fnDLA_GetEasterdate
DROP FUNCTION ISOweek
--DROP TABLE MyDateTable
SET NOCOUNT OFF
Once you have created the table, finding the number of working days is easy peasy:
SELECT COUNT(FullDate) AS WorkingDays
FROM dbo.tbl_WorkingDays
WHERE WorkingDay = 'Y'
AND FullDate >= CONVERT(DATETIME, '10/01/2013', 103)
AND FullDate < CONVERT(DATETIME, '15/01/2013', 103)
Note that this script includes UK bank holidays, i'm not sure what region you're in.
Here's a simple function that counts working days not including Saturday and Sunday (when counting holidays isn't necessary):
CREATE FUNCTION dbo.udf_GetBusinessDays (
#START_DATE DATE,
#END_DATE DATE
)
RETURNS INT
WITH EXECUTE AS CALLER
AS
BEGIN
DECLARE #NUMBER_OF_DAYS INT = 0;
DECLARE #DAY_COUNTER INT = 0;
DECLARE #BUSINESS_DAYS INT = 0;
DECLARE #CURRENT_DATE DATE;
DECLARE #DAYNAME NVARCHAR(9)
SET #NUMBER_OF_DAYS = DATEDIFF(DAY, #START_DATE, #END_DATE);
WHILE #DAY_COUNTER <= #NUMBER_OF_DAYS
BEGIN
SET #CURRENT_DATE = DATEADD(DAY, #DAY_COUNTER, #START_DATE)
SET #DAYNAME = DATENAME(WEEKDAY, #CURRENT_DATE)
SET #DAY_COUNTER += 1
IF #DAYNAME = N'Saturday' OR #DAYNAME = N'Sunday'
BEGIN
CONTINUE
END
ELSE
BEGIN
SET #BUSINESS_DAYS += 1
END
END
RETURN #BUSINESS_DAYS
END
GO
This is the method I normally use (When not using a calendar table):
DECLARE #T TABLE (Date1 DATE, Date2 DATE);
INSERT #T VALUES ('20130110', '20130115'), ('20120101', '20130101'), ('20120611', '20120701');
SELECT Date1, Date2, WorkingDays
FROM #T t
CROSS APPLY
( SELECT [WorkingDays] = COUNT(*)
FROM Master..spt_values s
WHERE s.Number BETWEEN 1 AND DATEDIFF(DAY, t.date1, t.Date2)
AND s.[Type] = 'P'
AND DATENAME(WEEKDAY, DATEADD(DAY, s.number, t.Date1)) NOT IN ('Saturday', 'Sunday')
) wd
If like I do you have a table with holidays in you can add this in too:
SELECT Date1, Date2, WorkingDays
FROM #T t
CROSS APPLY
( SELECT [WorkingDays] = COUNT(*)
FROM Master..spt_values s
WHERE s.Number BETWEEN 1 AND DATEDIFF(DAY, t.date1, t.Date2)
AND s.[Type] = 'P'
AND DATENAME(WEEKDAY, DATEADD(DAY, s.number, t.Date1)) NOT IN ('Saturday', 'Sunday')
AND NOT EXISTS
( SELECT 1
FROM HolidayTable ht
WHERE ht.Date = DATEADD(DAY, s.number, t.Date1)
)
) wd
The above will only work if your dates are within 2047 days of each other, if you are likely to be calculating larger date ranges you can use this:
SELECT Date1, Date2, WorkingDays
FROM #T t
CROSS APPLY
( SELECT [WorkingDays] = COUNT(*)
FROM ( SELECT [Number] = ROW_NUMBER() OVER(ORDER BY s.number)
FROM Master..spt_values s
CROSS JOIN Master..spt_values s2
) s
WHERE s.Number BETWEEN 1 AND DATEDIFF(DAY, t.date1, t.Date2)
AND DATENAME(WEEKDAY, DATEADD(DAY, s.number, t.Date1)) NOT IN ('Saturday', 'Sunday')
) wd
I did my code in SQL SERVER 2008 (MS SQL) . It works fine for me. I hope it will help you.
DECLARE #COUNTS int,
#STARTDATE date,
#ENDDATE date
SET #STARTDATE ='01/21/2013' /*Start date in mm/dd/yyy */
SET #ENDDATE ='01/26/2013' /*End date in mm/dd/yyy */
SET #COUNTS=0
WHILE (#STARTDATE<=#ENDDATE)
BEGIN
/*Check for holidays*/
IF ( DATENAME(weekday,#STARTDATE)<>'Saturday' and DATENAME(weekday,#STARTDATE)<>'Sunday')
BEGIN
SET #COUNTS=#COUNTS+1
END
SET #STARTDATE=DATEADD(day,1,#STARTDATE)
END
/* Display the no of working days */
SELECT #COUNTS
By Combining #Aaron Bertrand's answer and the Easter Calculation from #HeavenCore's and adding some code of my own, this code creates a calendar from 2000 to 2049 that includes UK (England) Bank Holidays. Usage and notes as per Aaron's answer:
DECLARE #s DATE, #e DATE;
SELECT #s = '2000-01-01' , #e = '2049-12-31';
-- Insert statements for procedure here
CREATE TABLE dbo.Calendar
(
dt DATE PRIMARY KEY, -- use SMALLDATETIME if < SQL Server 2008
IsWorkDay BIT
);
INSERT dbo.Calendar(dt, IsWorkDay)
SELECT DATEADD(DAY, n-1, '2000-01-01'), 1
FROM
(
SELECT TOP (DATEDIFF(DAY, #s, #e)+1) ROW_NUMBER()
OVER (ORDER BY s1.[object_id])
FROM sys.all_objects AS s1
CROSS JOIN sys.all_objects AS s2
) AS x(n);
SET DATEFIRST 1;
-- weekends
UPDATE dbo.Calendar SET IsWorkDay = 0
WHERE DATEPART(WEEKDAY, dt) IN (6,7);
-- Christmas
UPDATE dbo.Calendar SET IsWorkDay = 0
WHERE IsWorkDay = 1 and MONTH(dt) = 12 and
(DAY(dt) in (25,26) or
(DAY(dt) in (27, 28) and DATEPART(WEEKDAY, dt) IN (1,2)) );
-- New Year
UPDATE dbo.Calendar SET IsWorkDay = 0
WHERE IsWorkDay = 1 and MONTH(dt) = 1 AND
( DAY(dt) = 1 or (DAY(dt) IN (2,3) AND DATEPART(WEEKDAY, dt)=1 ));
-- Easter
UPDATE dbo.Calendar SET IsWorkDay = 0
WHERE dt = DATEADD(dd, -2, CONVERT(DATETIME, dbo.fnDLA_GetEasterdate(DATEPART(yy, dt)))) --Good Friday
OR dt = DATEADD(dd, +1, CONVERT(DATETIME, dbo.fnDLA_GetEasterdate(DATEPART(yy, dt)))) --Easter Monday
-- May Day (first Monday in May)
UPDATE dbo.Calendar SET IsWorkDay = 0
WHERE MONTH(dt) = 5 AND DATEPART(WEEKDAY, dt)=1 and DAY(DT)<8;
-- Spring Bank Holiday (last Monday in May apart from 2022 when moved to include Platinum Jubilee bank holiday)
UPDATE dbo.Calendar SET IsWorkDay = 0
WHERE
(YEAR(dt)=2022 and MONTH(dt) = 6 AND DAY(dt) IN (2,3)) OR
(YEAR(dt)<>2022 and MONTH(dt) = 5 AND DATEPART(WEEKDAY, dt)=1 and DAY(DT)>24);
-- Summer Bank Holiday (last Monday in August)
UPDATE dbo.Calendar SET IsWorkDay = 0
WHERE MONTH(dt) = 8 AND DATEPART(WEEKDAY, dt)=1 and DAY(DT)>24;