What does this SQL function do? - sql-server

I'm not sure if I get this right. Please someone explain to me. I don't know what deatiles should I add to shis function. I gues somwone who knows sql well will know this easily
declare #date datetime = '2016-05-01',
#ndays INT = 11,
#country NVARCHAR(2)
BEGIN
IF #date IS NULL
BEGIN
SET #date = GETDATE();
END
IF #country IS NULL
BEGIN
SET #country = 'HU';
END
DECLARE #count INT = 1
DECLARE #newdate datetime
DECLARE #firstdayofmonth date = DATEADD(month, DATEDIFF(month, 0, #date), 0)
WHILE DATEPART(weekday,#firstdayofmonth) in (7,1)
BEGIN
SET #firstdayofmonth = DATEADD(DAY, 1, #firstdayofmonth)
END;
SET #newdate = #firstdayofmonth
WHILE #count < #ndays
BEGIN
SET #newdate = DATEADD(DAY, 1, #newdate)
IF (DATEPART(WEEKDAY, #newdate) not in (1,7))
SET #count += 1;
END
select #newdate
END
I get that this is about declaring a date. The firstdayofmonth calculatio is confusing in it.

This is clearly no mysql code weekday goes from 0 to 6. Also you can't declare variables that way.
Also you should have posted the whole code.
AS for your code:
The first While Clause searches for the first Monday in a Month.
The second counts all Working Days (Monday till Friday) of that chosen Month.
With the first variables, you can manipulate which Month, but what that country has to do with it I can only guess that you have a list of all public holiday fur Hungary.

#newdate becomes the first weekday of the month (Monday-Friday). If the month starts on a weekend (Saturday or Sunday), it shifts up until Monday; otherwise it stays the same. As for the second part, #count looks like it ends up being the number of weekdays in the first eleven days since the start of the first weekday.

Related

Is there an easy way to determine the next business day from a date with weekends and holidays included in the calculation?

I have a future table which shows holidays and weekends along with calendar dates and I want to add a next business day field to that based on Holidays and Weekends.
For example: January 2nd 2020 is a holiday and so is January 1st. January 1st 2020 is a wednesday, so the next business day should be January 3rd. (skips the 2nd, friday is a business day).
Is there an easy function or loop which can do this simply? I only need to do it once so i'm not worried too much about not utilizing a set operation.
I had created what i assumed was the worlds worst case statement, but I realized that solution was just clunky and not supportable.
I don't have the reputation to comment but from what I have gathered... no, there is not a function provided by SQL Server but you can write a simple function like the one done in this post Declare date, then add next business day
Good luck!
Thanks , I just used a derived subquery to allow incorrect dates to populate when there was a holiday to consider, then rolled those up to another layer and added an extra day.
Not the most elegant, but worked for my scenario.
select
a.date
,a.day
,a.firstOfMonth
,a.MonthName
,a.week
,a.dayofWeek
,a.hldyInd
,a.weekendInd
,case when a.Nbdtemp IN ('2020-01-01','2020-01-02','2020-01-20','2020-05-25','2020-07-03','2020-11-26','2020-12-25') then dateadd(day,1,nbdtemp) else Nbdtemp end as NxtBusinessDay
into #final
from
(
select t.*,
case when t.dayofweek not in ('Friday','Saturday') and t.HldyInd = 'N' then DATEADD(day,1,date)
when t.dayofweek = 'Friday' and t.hldyind = 'N' then dateadd(day,3,date)
when t.dayofweek = 'Saturday' and t.hldyind = 'N' then dateadd(day,2,date)
when t.hldyind = 'Y' then dateadd(day,1,date) end as Nbdtemp
from #updtdim t
) as a
The easy way is create Holidays table, and enter each holiday every year. After that, you can easy to give a day and find the next working day.
Here is my function to get how many working days between start and end day. You can easy to modify and get next business day.
CREATE TABLE [dbo].[Holidays](
[Date] [date] NULL,
[Description] [varchar](100) NULL
) ON [PRIMARY]
GO
CREATE FUNCTION [dbo].[GetWorkingDays]
(
#StartDate date,
#EndDate date
)
RETURNS int
AS
BEGIN
-- Declare the return variable here
DECLARE #ResultVar int = 0;
DECLARE #dt date = #StartDate;
WHILE #EndDate >= #dt BEGIN
IF DATEPART(WEEKDAY,#dt) < 6 BEGIN
IF NOT EXISTS(SELECT Date FROM Holidays WHERE Date=#dt) BEGIN
SET #ResultVar = #ResultVar + 1;
END
END
SET #dt = DATEADD(DAY,1,#dt);
END
RETURN #ResultVar;
END
Try something like this:
create table dbo.HolidayList(Holiday date)
insert into HolidayList(Holiday)values
('2019-07-01T00:00:00.000'),('2019-07-09T00:00:00.000'),('2019-08-01T00:00:00.000'),
('2019-08-02T00:00:00.000'),('2019-08-05T00:00:00.000'),('2019-09-02T00:00:00.000'),
('2019-10-14T00:00:00.000'),('2019-11-11T00:00:00.000'),('2019-12-25T00:00:00.000'),
('2019-12-26T00:00:00.000'),('2020-01-01T00:00:00.000'),('2020-02-10T00:00:00.000'),
('2020-02-17T00:00:00.000'),('2020-03-17T00:00:00.000'),('2020-04-10T00:00:00.000'),
('2020-04-13T00:00:00.000'),('2020-04-23T00:00:00.000'),('2020-05-18T00:00:00.000'),
('2020-05-25T00:00:00.000'),('2020-06-24T00:00:00.000'),('2020-07-01T00:00:00.000'),
('2020-07-09T00:00:00.000'),('2020-07-30T00:00:00.000'),('2020-07-31T00:00:00.000')
go
create function dbo.IsWeekday(#Date date) returns bit
begin
return case when DATEDIFF(day,'0001-01-01T00:00:00.000',#Date)
% 7 < 5 then 1 else 0 end
end
go
create function dbo.IsHoliday(#Date date)returns bit
begin
return case when #Date in(select Holiday from HolidayList) then 1 else 0 end
end
go
create function dbo.IsWorkDay(#Date date)returns bit
begin
return case when dbo.IsWeekday(#Date)=1 and dbo.IsHoliday(#Date)=0 then 1 else 0 end
end
go
create function dbo.WorkdayFollowing(#Date date)returns date
begin
declare #D date = DATEADD(day,1,#date)
while dbo.isworkday(#D)=0
begin
set #D = DATEADD(day,1,#D)
end
return #D
end
go
declare #d date = '2019-06-01T00:00:00.000'
while #d < '2019-09-01T00:00:00.000'
begin
set #d=DATEADD(day,1,#d)
select #d, dbo.workdayfollowing(#d)
end

SSIS For Loop with DATEADD in assignexpression

I have an SSIS for loop and in the assign expression part of the for loop I need to increment with a DATEADD function but the date part needs to be dependent on my variable:
#DateStart = DATEADD(#TypeIncrement,#DayIncrement,#DateStart)
If i change it ,it will work:
#DateStart = DATEADD(dd,#Increment,#DateStart)
but if I try to do it this way its just giving me an error saying The date part parameter specified for function "DATEADD" is not valid.
I have also tried changing it to be a case statement with different date parts but that wouldn't work either.
Any ideas?
Thanks.
----------------EDIT
a lot of ppl are posting sql server answers. but i need it working here:
Example
Declare #TypeIncrement varchar(10) = 'MM'
Declare #DayIncrement int = 5
Declare #DateStart date = '2017-03-15'
Select Case #TypeIncrement
When 'YY' then DateAdd(YY, #DayIncrement, #DateStart)
When 'QQ' then DateAdd(QQ, #DayIncrement, #DateStart)
When 'MM' then DateAdd(MM, #DayIncrement, #DateStart)
When 'WK' then DateAdd(WK, #DayIncrement, #DateStart)
When 'DD' then DateAdd(DD, #DayIncrement, #DateStart)
End
Returns
2017-08-15
The first parameter doesn't accept a variable as an input. One alternate option to a CASE might be dynamic SQL:
DECLARE #IncrementType nvarchar(10), #Increment int, #DateStart date;
SET #IncrementType = N'DAY';
SET #Increment = 5;
SET #DateStart = GETDATE();
IF #IncrementType NOT IN (N'YEAR',N'QUARTER',N'MONTH',N'DAYOFYEAR',N'DAY',N'WEEK',N'WEEKDAY',N'HOUR',N'MINUTE',N'SECOND',N'MILLISECOND',N'MICROSECOND',N'NANOSECOND') BEGIN
DECLARE #Error nvarchar(500) = 'Invalid input for Increment Type(''' + #IncrementType + N'''. Valid options are: YEAR, QUARTER, MONTH, DAYOFYEAR, DAY, WEEK, WEEKDAY, HOUR, MINUTE, SECOND, MILLISECOND, MICROSECOND, NANOSECOND.'
RAISERROR(#Error,11,-1);
END ELSE BEGIN
DECLARE #SQL nvarchar(MAX);
SET #SQL = N'SET #dDateStart = DATEADD(' + #IncrementType + N',#dIncrement,#dDateStart)'
PRINT #SQL; --Your best friend
EXEC sp_executesql #SQL, N'#dDateStart date OUTPUT, #dIncrement int', #dDateStart = #DateStart OUTPUT, #dIncrement = #Increment;
END
SELECT #DateStart;
This might be over complicating it, but it's an alternate to the CASE anyway.
implementing inside SSIS:
to get this:
#DateStart = DATEADD(dd,#Increment,#DateStart)
Try this:
#DateStart = #TypeIncrement=="dd" ? DATEADD(dd,#Increment,#DateStart)
: #TypeIncrement=="mm" ? DATEADD(MM,#Increment,#DateStart)
and so on...
If then else is in the format of:
Test ? true part : false part

Creating and executing the function in SQL Server

Im trying to complete this function that will take an input date and return a date that is a Sunday 3 weeks ago.
For example: If my input date is 5/25/2016, then the result should be 5/1/2016
I have put together most of the function, just stumped as to what to do next.
IF OBJECT_ID (N'dbo.ufnSundayThreeWeeksBack', N'FN') IS NOT NULL
DROP FUNCTION ufnSundayThreeWeeksBack;
GO
CREATE FUNCTION dbo.ufnSundayThreeWeeksBack(#SOMEDATE datetime)
RETURNS date
AS
BEGIN
IF #SOMEDATE IS NULL
RETURN NULL;
DECLARE #result date;
SELECT #result = DATEADD(WEEK, -7, DATEADD(DAY, 1 - DATEPART(WEEKDAY, #SOMEDATE), #SOMEDATE))
RETURN #result;
END;
GO
Try this:
IF OBJECT_ID(N'dbo.ufnSundayThreeWeeksBack', N'FN') IS NOT NULL
DROP FUNCTION ufnSundayThreeWeeksBack;
GO
CREATE FUNCTION dbo.ufnSundayThreeWeeksBack ( #SOMEDATE DATETIME )
RETURNS DATE
AS
BEGIN
DECLARE #DateMinus3Weeks DATE = DATEADD(WEEK, -3, #SOMEDATE);
RETURN DATEADD(DAY, -(DATEPART(WEEKDAY, #DateMinus3Weeks)-1), #DateMinus3Weeks);
END;
GO
Basically subtracting 3 weeks from the given date and then subtracting the weekdaynumber to get to the sunday.

Compare SQL server datetime column to year month?

SELECT * FROM TABLE
WHERE YEAR(MDTFlgtStart)=YEAR(GETDATE()) AND MONTH(MDTFlgtStart)=MONTH(GETDATE())
Above code it compares with present year and month with the column year and month.
But do we have any chance we can give year=2012 month =3
or year =2011 month=5
You could declare variables:
DECLARE #YEAR AS INT
DECLARE #MONTH AS INT
SET #YEAR = 2012
SET #MONTH = 3
SELECT *
FROM TABLE
WHERE YEAR(MDTFlgtStart)=#YEAR AND MONTH(MDTFlgtStart)=#MONTH
You can wrap the above in a procedure for re-usability....
You can just use parameters for those values. As a bonus, avoiding functions against the column will help assist a seek if an index exists on the column (of course SELECT * means it will likely end up as a full scan anyway, or a range scan and a bunch of lookups)...
-- these would be input parameters for your stored procedure
DECLARE #y INT = 2011, #m INT = 5;
-- now have a date variable:
DECLARE #dt DATE = DATEADD(MONTH, #m-1, DATEADD(YEAR, #y-1900, 0));
SELECT ... FROM dbo.tablename
WHERE MDTFlgtStart >= #dt
AND MDTFlgtStart < DATEADD(MONTH, 1, #dt);
Also you should stop inviting whoever named these columns to lunch, because I have to assume they're not very nice.

Efficent way to set date using week of month value

I have a week of month in sql and i need to generate a datetime varible from that.. fields i have are dayofweek, weekofmonth and month values. anyone know of a quick effective way to calculate this in mssql 2005? Thanks
Keep in mind. if week of month is set to 5 it is the last week of the month
Examples are i have DayOfWeek, month, year, weekofmonth..
so lets say i have DayOfWeek = 2 (monday)
month = 5 ( may)
year = 2009
weekofmonth = 5
i would expect monday may 25th 2009
DayOfWeek = 1, Month = 5, Week = 1, year = 2009 = Sunday, May 3rd 2009
DayOfWeek = 5, Month = 4, Week = 3, Year = 2009 = Thursday, April 16th 2009
Additional Info:
I am using the .net TimezoneInfo.TransitionTime class library to help me store some stuff in the db.. they say:
The Month property defines the month in which the time change occurs. The Day property defines the day of the week on which the transition occurs. The Week property determines which week of the month the time change occurs in. Valid values of the Week property can range from 1 to 5. A value of 5 indicates the last week of the month.
so far i have this:
declare #IsFixedDateRule bit
declare #Day tinyint
declare #DayOfweek tinyint
declare #Week tinyint
declare #Month tinyint
declare #Year int
declare #TimeofDay int -- SECONDS
set #IsFixedDateRule = 0
set #Day = 1
set #DayOfweek = 1
set #Week = 5
set #Month = 4
set #year = 2008
set #TimeofDay = 7200
declare #date datetime
if (#IsFixedDateRule = 1)
begin
set #date = convert(char(4),#Year) + '/' + convert(char(2),#Month) + '/' + convert(char(2),#Day) -- Set Year/Month
end
else
begin
set #date = convert(char(4),#Year) + '/' + convert(char(2),#Month) + '/01' -- Set Year/Month
declare #datepart tinyint
set #datepart = datepart(weekday ,#date)
set #date = dateadd(week, #week - 1, dateadd(weekday, #Dayofweek - case when #datepart = 7 then 0 else #datepart end, #date))-- get the day
end
select dateadd(second, #TimeofDay, #date) -- Add Time Of Day
anything cleaner?
This is fairly simple, and really just adds days and weeks to the first day of that month. It assumes you're using the current year, and won't really handle things like the 5th week of February. (Example: 5th week, 3rd day of February gives 03/11/2009)
DECLARE #CalculatedDate DATETIME;
-- Assuming DayOfWeek and WeekOfMonth are 1-based
SELECT #CalculatedDate = DATEADD(DAY, #DayOfWeek - 1, DATEADD(WEEK, #WeekOfMonth - 1, '2009-' + STR(#Month) + '-01'));
-- Assuming DayOfWeek and WeekOfMonth are 0-based
SELECT #CalculatedDate = DATEADD(DAY, #DayOfWeek, DATEADD(WEEK, #WeekOfMonth, '2009-' + STR(#Month) + '-01'))
It also assumes that DayOfWeek == 1 for the first day of the month, so it's almost definitely wrong. Can we see some sample data and expected outputs?
The first week of May starts on Friday. So what date would be dayofweek=1, weekofmonth=1, month=5? Is that Monday April 27th?
/*
* Assuming #year is this year
* #day_of_week starts from Sunday = 1, Monday = 2 etc
*/
declare #week_of_month int,
#day_of_week int,
#month int,
#year int,
#derived_date datetime
set dateformat dmy
select #year = datepart(year, getdate()),
#day_of_week = 2,
#week_of_month = 2,
#month = 5
select #derived_date = convert(varchar,#year) + '-01-' + convert(varchar,#month)
select #derived_date
select #derived_date = dateadd(dd, #day_of_week - datepart(dw, #derived_date), dateadd(week, #week_of_month-1, #derived_date))
select #year, #month, #day_of_week, #week_of_month, #derived_date
/* Test */
declare #date datetime
set #date = '04-MAY-2009'
select #date, cast(datename(week,#date) as int)- cast( datename(week,dateadd(dd,1-day(#date),#date)) as int)+1 week_of_month, datepart(dw, #date) day_of_weekhere
EDIT - amended to handle different values of ##datefirst
My guess based on the data available so far.
This will work if you SQL server installation has ##datefirst set to Sunday(7) or Monday(1).
The test data is set up to return 01-May-2009
declare #dayofweek int
declare #weekofmonth int
declare #month int
declare #datefirst_adjustment int
select #datefirst_adjustment = case ##datefirst when 1 then 0
when 7 then 1
end
declare #firstofyear datetime
set #firstofyear = '20090101'
set #dayofweek = 5
set #month = 5
set #weekofmonth = 1
select dateadd(ww,#weekofmonth - 1,dateadd(mm,#month - 1,#firstofyear)) - datepart(dw,dateadd(mm,#month - 1,#firstofyear)) + #dayofweek + #datefirst_adjustment

Resources