While loop to populate a table - sql-server

I am trying to use a while loop to populate a table in SQL Server. The data is to be in 5 minute increments from 8:00 am to 7:00 pm for Monday through Friday.
Below is the code that I have in place when I try to pass the variable #Beg to #Temp I get an error:
Msg 102, Level 15, State 1, Line 85
Incorrect syntax near '#Temp'.
Msg 102, Level 15, State 1, Line 90
Incorrect syntax near '#Beg'.
My code:
Create Table TIMESLOT
(
TIMESLOTID int not null identity(1,1),
Beg_Time datetime not null,
End_Time datetime not null,
TimeDayOFWeek varChar(25) not null
);
DECLARE #Beg as Time;
DECLARE #Temp as Time;
DECLARE #End as Time;
DECLARE #Day as dayofweek;
set #Beg = '08:00 AM';
Set #End = '07:00 PM';
set #Day = 'Monday';
While (#Day != 'Saturday' )
Begin
While (#Beg <= #End)
Begin
#Temp = #Beg;
DateAdd(minute,5,#Temp)
Insert into TIMESLOT (Beg_Time, End_Time, TimeDay0fWeek)
Values (#Beg, #Temp, #Day)
if (#Beg <= #End)
#Beg = #Temp
Else
#Beg = '08:00 AM'
#Day = Datadd(day, 1, #Day)
End
End
End

try the below. Your syntax was not quite correct
Create Table TIMESLOT
(
TIMESLOTID int not null identity(1,1),
Beg_Time datetime not null,
End_Time datetime not null,
TimeDayOFWeek varChar(25) not null
);
DECLARE #Beg as Time;
DECLARE #Temp as Time;
DECLARE #End as Time;
DECLARE #Day as dayofweek;
set #Beg = '08:00 AM';
Set #End = '07:00 PM';
set #Day = 'Monday';
While (#Day != 'Saturday' )
Begin
While (#Beg <= #End)
Begin
Set #Temp = #Beg;
Set #Temp = DateAdd(MINUTE,5,#Temp)
Insert into TIMESLOT (Beg_Time, End_Time, TimeDayOFWeek)
Values (#Beg, #Temp, #Day)
If (#Beg <= #End)
Begin
Set #Beg = #Temp
End
Else
Begin
Set #Beg = '08:00 AM'
Set #Day = DateAdd(day,1, #Day)
End
End
End

This is the code that finally fixed the issue, Wheels73 was correct my syntax was wrong. But I also had the if statement and the variable #beg reset in the wrong area.
While (#Day != 'Saturday' ) -- first end
Begin
While (#Beg < #End)
Begin--Second
Set #Temp = #Beg
Set #Temp = DateAdd(MINUTE,5,#Temp)
Insert into TIMESLOT (Beg_Time, End_Time, TimeDayOFWeek)
Values (#Beg, #Temp, #Day)
Set #Beg = #Temp
End--Second
Set #Beg = '08:00 AM'
if(#Day = 'Monday')
Begin
Set #Day = 'Tuesday'
End
Else if(#Day = 'Tuesday')
Begin
Set #Day = 'Wednesday'
End
Else if (#Day = 'Wednesday')
Begin
Set #Day = 'Thursday'
End
Else if (#Day = 'Thursday')
Begin
Set #Day = 'Friday'
End
Else
Begin
Set #Day = 'Saturday'
End
End--firstenter code here

Related

Create a function that return total Working days between two dates

I would like to create a function in SQL Server that would return the no of working days after checking the day from the dimension table dimcalender which has all the working days from 2020 up until 2040
My Code:
Create FUNCTION [udf_WorkingDays]
(
-- Add the parameters for the function here
#StartDate DATETIME,
#EndDate DATETIME
)
RETURNS INT
AS
BEGIN
DECLARE #TotalDays INT
SET #StartDate = '2022/06/01'
SET #EndDate = '2022/06/07'
SET #TotalDays = 0
--SET #TotalDays =(
WHILE (#StartDate <= #EndDate)
BEGIN
sum(select WorkingDay
FROM [XS].[dimCalendar]
where [Date] >= #StartDate
and [Date] <= #EndDate)
set #StartDate = DATEADD(day, 1, #StartDate)
--set #TotalDays = dss;)
END;
RETURN #TotalDays
END;
[dimCalendar] is where all UK working days are recorded.
WorkingDay is just a flag to say 0,1 (if its a working day or not.)
TotalDays is a variable that will have total no. of working days that will be returned.
DECLARE #StartDate DATETIME
DECLARE #EndDate DATETIME
DECLARE #TotalDays INT
DECLARE #DDays INT
SET #StartDate = '2022/06/01'
SET #EndDate = '2022/06/06'
SET #TotalDays = 0
SET #TotalDays = (
SELECT a.toti
FROM (
SELECT SUM(WorkingDay) AS toti
FROM [dimCalendar]
WHERE [Date] >= #StartDate
AND [Date] <= #EndDate
) AS a
)
RETURN #TotalDays;

Generate a stock position report as at each month with a date variable set at a specific month

I am trying to generate a stock position report as at each month. within my query i have a date variable set at a specific month:
declare #date datetime = CONVERT(DATETIME, '2019-08-13 00:00:00', 121)
declare #lastmonth datetime = (select cast(dateadd(day, -day(getdate()), getdate()) as date))
declare #m int = 0
--**my aim is to ensure that #date = #lastmonth**
while #date<= #lastmonth
Begin
set #m = #m + 1
while #m < 12
Begin
set #date = (select dateadd(mm, #m, #date))
End
End
select

Calculate off days between 2 dates in sql

I have a function that calculate the number of working days between 2 dates. What I want is to convert this existing function into something like it will calculate the number of holidays in month or let's say in between 2 dates.
My existing function is something like this.
CREATE FUNCTION [dbo].[fnGetDaysWorked] (#StartDate datetime, #EndDate datetime)
RETURNS int
AS
BEGIN
DECLARE #dateFrom datetime = '2018/01/01'
DECLARE #dateTo datetime = '2018/01/31'
SET #StartDate = #dateFrom
SET #EndDate = #dateTo
DECLARE #WORKDAYS INT
SELECT #WORKDAYS = (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)
RETURN #WORKDAYS
END
One more thing, I am unable to handle the situation in which there is some sort of public holiday in the month like Independence day or something. I have a table named calendar that handles the situation but I'm not able to integrate that here. Table structure is provided below.
CREATE TABLE Calendar
(
ID Int,
[DayName] Varchar(25),
Holiday datetime,
PublicHoliday Binary,
OffDay Binary,
Active Binary
);
Any help would be appreciated.
This will count the number of saturdays and sundays between 2 dates:
DECLARE #from date = '2018-02-03'
DECLARE #to date = '2018-02-13'
SELECT
datediff(day, -2, #to)/7-datediff(day, -1, #from)/7 -- saturdays
+ datediff(day, -1, #to)/7-datediff(day, 0, #from)/7 -- sundays
Holidays are different from country to country.
This function will determine when Easter starts for a specific year:
CREATE FUNCTION [dbo].[f_EasterByYear] (#Year SMALLINT) RETURNS DATE AS
BEGIN
DECLARE
#c INT,
#n INT,
#k INT,
#i INT,
#j INT,
#l INT,
#m INT,
#d INT,
#Easter DATE
SET #c = (#Year / 100)
SET #n = #Year - 19 * (#Year / 19)
SET #k = (#c - 17) / 25
SET #i = #c - #c / 4 - ( #c - #k) / 3 + 19 * #n + 15
SET #i = #i - 30 * ( #i / 30 )
SET #i = #i - (#i / 28) * (1 - (#i / 28) *
(29 / (#i + 1)) * ((21 - #n) / 11))
SET #j = #Year + #Year / 4 + #i + 2 - #c + #c / 4
SET #j = #j - 7 * (#j / 7)
SET #l = #i - #j
SET #m = 3 + (#l + 40) / 44
SET #d = #l + 28 - 31 * ( #m / 4 )
SET #Easter = DATEADD(month, #m, DATEADD(year, #Year- 1900,
DATEADD(d, #d, '1899-11-30')))
RETURN #Easter
END
This function will return 1 for workday otherwise 0:
CREATE FUNCTION [dbo].[f_IsWorkDay] (#Date DATE) RETURNS BIT AS
BEGIN
DECLARE #IsWorkDay BIT = 1
SELECT #IsWorkDay =
CASE
--Exclude Saturday and Sunday (Datefirst-independent)
WHEN DATEDIFF(d, 0, #Date) % 7 IN (5,6) THEN 0
WHEN MONTH(#Date)=12 AND DAY(#Date) IN (24,25,26,31) THEN 0
--Exclude New Years
WHEN MONTH(#Date)=1 AND DAY(#Date)=1 THEN 0
--Exclude Easter, Pentecost and Ascension of Jesus
WHEN #Date IN (
DATEADD(DAY,-3,dbo.f_EasterByYear(YEAR(#Date))),
DATEADD(DAY,-2,dbo.f_EasterByYear(YEAR(#Date))),
DATEADD(DAY,1, dbo.f_EasterByYear(YEAR(#Date))),
DATEADD(DAY,26,dbo.f_EasterByYear(YEAR(#Date))),
DATEADD(DAY,39,dbo.f_EasterByYear(YEAR(#Date))),
DATEADD(DAY,50,dbo.f_EasterByYear(YEAR(#Date)))
) THEN 0
ELSE 1
END
RETURN #IsWorkDay
END
You can test if a day is a workday this way:
SELECT dbo.f_Isworkday(date) isWorkDay, date
FROM (values('2018-02-09'),('2018-02-10'),('2018-02-11'),('2018-02-12')) x(date)
Advanced test giving an interval as input:
DECLARE
#from DATE = '2018-02-09',
#to DATE = '2018-02-13'
;WITH N(N)AS
(SELECT 1 FROM(VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1))M(N)),
tally(N)AS(SELECT ROW_NUMBER()OVER(ORDER BY N.N)FROM N,N a,N b,N c,N d,N e)
SELECT
dbo.f_Isworkday(dateadd(d, N-1, #from)) isworkday,
dateadd(d, N-1, #from) date
FROM tally
WHERE N <= datediff(d, #from, #to) + 1
Use this Function, It will work with your Calendar table too. All Active entries in the Calendar table will not be counted as working days
CREATE FUNCTION [dbo].[fnGetDaysWorked2] (#StartDate datetime, #EndDate datetime)
RETURNS int
BEGIN
DECLARE #tblNonWorking TABLE(dt DATETIME,dtw varchar(30))
While (#StartDate<=#EndDate)
BEGIN
INSERT INTO #tblNonWorking(dt,dtw) VALUES (#StartDate,Lower(DATENAME(dw, #StartDate)))
SET #StartDate=Dateadd(day,1,#StartDate)
END
DECLARE #WORKDAYS INT
SET #WORKDAYS=0
SELECT #WORKDAYS=COUNT(1)
FROM #tblNonWorking a
LEFT JOIN Calendar c ON a.dt=c.Holiday AND c.Active=1
WHERE a.dtw NOT IN ('saturday','sunday')
AND c.ID IS NULL
RETURN #WORKDAYS
END

Find Mondays between 2 dates

I need to display dates of all Mondays in the given date range.
For example, if my start date is 01/05/2015 and end date is 31/05/2015, I need to show
04/05/2015
11/05/2015
18/05/2015
25/05/2015
How is it possible?
This procedure is independent from regions and languages.
Please note the first line with SET DATEFIRST 1.
SET DATEFIRST 1; -- First day of the week is set to monday
DECLARE #DateFrom DateTime ='20150601', #DateTo DateTime = '20150630' ;
WITH CTE(dt)
AS
(
SELECT #DateFrom
UNION ALL
SELECT DATEADD(d, 1, dt) FROM CTE
WHERE dt < #DateTo
)
SELECT dt FROM CTE where datepart ("dw", dt) = 1;
Using a CTE it is possible this way..
DECLARE #DateFrom DateTime ='2015-05-01',
#DateTo DateTime = '2015-05-31'
;WITH CTE(dt)
AS
(
SELECT #DateFrom
UNION ALL
SELECT DATEADD(d, 1, dt) FROM CTE
WHERE dt < #DateTo
)
SELECT 'Monday', dt FROM CTE
WHERE DATENAME(dw, dt) In ('Monday')
Refer: Select dates of a day between two dates.
SELECT [Day],[Dt] FROM dbo.fnGetDatesforAday('7/1/2008','8/31/2008','Sunday')
CREATE FUNCTION fnGetDatesforAday
(
-- Add the parameters for the function here
#DtFrom DATETIME,
#DtTo DATETIME,
#DayName VARCHAR(12)
)
RETURNS #DateList TABLE ([Day] varchar(20),Dt datetime)
AS
BEGIN
IF NOT (#DayName = 'Monday' OR #DayName = 'Sunday' OR #DayName = 'Tuesday' OR #DayName = 'Wednesday' OR #DayName = 'Thursday' OR #DayName = 'Friday' OR #DayName = 'Saturday')
BEGIN
--Error Insert the error message and return
INSERT INTO #DateList
SELECT 'Invalid Day',NULL AS DAT
RETURN
END
DECLARE #TotDays INT
DECLARE #CNT INT
SET #TotDays = DATEDIFF(DD,#DTFROM,#DTTO)-- [NO OF DAYS between two dates]
SET #CNT = 0
WHILE #TotDays >= #CNT -- repeat for all days
BEGIN
-- Pick each single day and check for the day needed
IF DATENAME(DW, (#DTTO - #CNT)) = #DAYNAME
BEGIN
INSERT INTO #DateList
SELECT #DAYNAME,(#DTTO - #CNT) AS DAT
END
SET #CNT = #CNT + 1
END
RETURN
END
SET DATEFIRST 7; -- Set's sunday as first day of week, won't work otherwise
DECLARE #StartDate DATE = '06/01/2015'
DECLARE #EndDate DATETIME = '06/30/2015'
DECLARE #TableOfDates TABLE(DateValue DATETIME)
DECLARE #CurrentDate DATETIME
SET #CurrentDate = #startDate
WHILE #CurrentDate <= #endDate
BEGIN
INSERT INTO #TableOfDates(DateValue) VALUES (#CurrentDate)
SET #CurrentDate = DATEADD(DAY, 1, #CurrentDate)
END
SELECT * FROM #TableOfDates WHERE DATEPART(weekday,Datevalue) = 2

Extract amount of years, month and days from a date-range in SQL Server

I am looking for a possibility to extract years, months and days from a date range.
Example:
From: 01/01/2012 To: 08/17/2014
Result: 2 years, 8 month and 17 days
I know how to code this but maybe someone has a genius solution how to do this in SQL with built in commands. Or already made a fast and good working function.
If not I will need to code a sql inline function and present this for documentation later here as answer.
So first of all I was thinking about the approach to change the orbit around the sun to correct it to exact 360 days a year. But this would probably ends in some bad side effects...
As I want the exact amount I write this (see below) and it seems to work as intended for my needs. I share this for discussions, improvements and to share if anyone need this, too.
DECLARE #start datetime;
DECLARE #end datetime;
DECLARE #current datetime;
DECLARE #year int
DECLARE #month int
DECLARE #days int;
DECLARE #daytmp int;
-- note start date earliest: 1/1/1753
SET #start = CAST('28.02.1753' AS datetime)
SET #end = GETDATE() --CAST('31.12.2016' AS datetime)
SET #current = #start
SET #days = (SELECT DATEDIFF(day, #start, #end))
SET #year = 0;
WHILE #days>365
BEGIN
SET #days = #days - (SELECT DATEDIFF(day, #current, DATEADD(YEAR, 1, #current)))
SET #current = DATEADD(YEAR, 1, #current)
SET #year = #year + 1
END
SET #month = 0;
SET #daytmp = #days
WHILE #daytmp>28
BEGIN
SET #daytmp = #days - (SELECT DATEDIFF(day, #current, DATEADD(MONTH, 1, #current)))
IF (#daytmp>0) BEGIN
SET #days = #daytmp
SET #current = DATEADD(MONTH, 1, #current)
SET #month = #month + 1
END
END
PRINT #year
PRINT #month
PRINT #days
I moved this in to table function that returns 3 values with position 1,2,3 so I can use it inside select statements.
CREATE FUNCTION dbo.sf_GetYearMonthDayFromRange(#start datetime, #end datetime)
RETURNS #result TABLE ([value] int, [position] int)
AS
BEGIN
DECLARE #current datetime;
DECLARE #year int
DECLARE #month int
DECLARE #days int;
DECLARE #daytmp int;
SET #current = #start
SET #days = (SELECT DATEDIFF(day, #start, #end))
SET #year = 0;
WHILE #days>365
BEGIN
SET #days = #days - (SELECT DATEDIFF(day, #current, DATEADD(YEAR, 1, #current)))
SET #current = DATEADD(YEAR, 1, #current)
SET #year = #year + 1
END
SET #month = 0;
SET #daytmp = #days
WHILE #daytmp>28
BEGIN
SET #daytmp = #days - (SELECT DATEDIFF(day, #current, DATEADD(MONTH, 1, #current)))
IF (#daytmp>0) BEGIN
SET #days = #daytmp
SET #current = DATEADD(MONTH, 1, #current)
SET #month = #month + 1
END
END
INSERT INTO #result SELECT #year, 1
INSERT INTO #result SELECT #month, 2
INSERT INTO #result SELECT #days, 3
RETURN
END
how about this one query
Declare #FDate DateTime = '01/01/2012',
#TDate DateTime = '08/17/2014'
Select Convert(Varchar,(TotDays/365)) + 'years, ' + Convert(Varchar,(TotDays%365)/30) + ' month and ' + Convert(Varchar,(TotDays%365%30)) + ' days'
From (
Select DATEDIFF(DAY,#FDate, #TDate) TotDays
) As DCal
and output above this query is :
Descr
---------------------------
2years, 7 month and 19 days

Resources