Fill in the date gaps from the stuff - sql

I have this result, [year.month week] with my query below
[2021.12 51],[2021.12 53],[2022.01 1],[2022.01 2],[2022.01 3],[2022.01 5],[2022.01 6],[2022.02 10]
My goal is to fill in the gaps of the week, for example:
[2021.12 51],**[2021.12 52]**,[2021.12 53],[2022.01 1],[2022.01 2],[2022.01 3],**[2022.01 4]**,[2022.01 5],[2022.01 6],**[2022.01 7]**,**[2022.01 8]**,**[2022.01 9]**,[2022.02 10]
How could I do this with my query below:
DECLARE
#startdate datetime,
#enddate datetime,
#paramdef nvarchar(max)
set #startdate = '2021-01-01 00:00:00.000';
set #enddate = GETDATE();
set #paramdef = '#startdate datetime, #enddate datetime';
SELECT STUFF
(
(
SELECT
',' + QUOTENAME( S_FORMATTED_WEEK_MONTH )
FROM
MONITORING
WHERE
S_DATE_TO >= #startdate AND
S_DATE_TO <= #enddate
GROUP BY
S_FORMATTED_WEEK_MONTH
ORDER BY
CAST( REPLACE( SUBSTRING(S_FORMATTED_WEEK_MONTH, 1, 7), '.', '' ) AS INT ),
CAST( REPLACE( SUBSTRING(S_FORMATTED_WEEK_MONTH, 8, 9), '.', '' ) AS INT )
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)') ,1,1,''
)

you can use the below calendar table approach to get the list of weeknumbers as per your format.
DECLARE #StartDate DATE = '2021-01-01'
DECLARE #EndDate DATE = getdate()
;WITH Cal(n) AS
(
SELECT 0 UNION ALL SELECT n + 1 FROM Cal
WHERE n < DATEDIFF(DAY, #StartDate, #EndDate)
),
FnlDt(d,y,m,w) AS
(
SELECT DATEADD(DAY, n, #StartDate)
, year(DATEADD(DAY, n, #StartDate))
, month(DATEADD(DAY, n, #StartDate))
, datepart(week,DATEADD(DAY, n, #StartDate)) FROM Cal
)
select
string_agg(weekarr,',') as concat_weekarr
from
(SELECT concat('[',y,'.',m,' ',w,']') as weekarr
FROM fnlDt
group by y,m,w
) as dt
option(maxrecursion 32767)
[2021.1 1],[2021.1 2],[2021.1 3],[2021.1 4],...

Related

An SQL query to show the last BUSINESS day of the month

Here is my query:
CREATE FUNCTION dbo.ufn_LastBusinessDayOfMonth (#Dt datetime)
RETURNS datetime
AS
BEGIN
DECLARE #dt2 datetime
DECLARE #Df int
DECLARE #dSat int
DECLARE #dSun int
SELECT
#dt2 = DATEADD(D, -1, DATEADD(m, 1 + DATEDIFF(m, 0, #Dt), 0))
SELECT
#dSat = DATEPART(dw, '2018-01-06') -- Known Saturday
SELECT
#dSun = (#dSat % 7) + 1
SELECT
#dt2 = (
CASE
WHEN DATEPART(dw, #dt2) = #dSun THEN DATEADD(DAY, -2, #dt2)
WHEN DATEPART(dw, #dt2) = #dSat THEN DATEADD(DAY, -1, #dt2)
ELSE #dt2
END)
RETURN #dt2
END
DECLARE #Dt datetime
SET #Dt = '03/21/2018'
DECLARE #lastOfMonth datetime, #3DaysBeforeTheEnd DATETIME
set #lastOfMonth = DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,#Dt)+1,0))
SET #3DaysBeforeTheEnd = DATEADD(d,-2,#lastOfMonth)
select top 1 DATENAME(weekday, x.[Date]), x.[Date]
from (
SELECT TOP (DATEDIFF(DAY, #3DaysBeforeTheEnd, #lastOfMonth) + 1)
[Date] = DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY a.object_id) - 1, #3DaysBeforeTheEnd)
FROM sys.all_objects a
CROSS JOIN sys.all_objects b
)x
WHERE DATENAME(weekday, x.[Date]) NOT IN ('Saturday','sunday')
order by x.[Date] desc

A string of quarterly dates between a start and end date

I've got a recursive cte working to generate a list of dates between #startDate and #endDate, incrementing by quarters.
declare #startDate datetime
declare #endDate datetime
set #startDate= '01-jan-2014'
set #endDate= '01-jul-2017'
;With cte
As
( Select #startDate date1
Union All
Select DateAdd(Month,3,date1) From cte where date1 < #endDate
) select cast(cast( Year(date1)*10000 + MONTH(date1)*100 + 1 as
varchar(255)) as date) quarterlyDates From cte
This yields:
quarterlyDates
--------------
2014-01-01
2014-04-01
2014-07-01
2014-10-01 ...
I'd like to concatenate the output of the cte into a single string as follows:
"'01-jan-2014', '01-apr-2014, '01-jul-2014'..."
etc. I'm baffled by this last step - any help would be greatly appreciated!
Not sure why you want to... but just wrap that bottom cte and use stuff.
declare #table table(quarterlyDates date)
insert into #table
values
('2014-01-01'),
('2014-04-01'),
('2014-07-01'),
('2014-10-01')
SELECT stuff((
SELECT ', ' + cast(quarterlyDates as varchar(max))
FROM #table
FOR XML PATH('')
), 1, 2, '')
And in your code... though the second CTE isn't necessary I leave it for clarity.
declare #startDate datetime
declare #endDate datetime
set #startDate= '01-jan-2014'
set #endDate= '01-jul-2017'
;With cte
As
( Select #startDate date1
Union All
Select DateAdd(Month,3,date1) From cte where date1 < #endDate
),
cte2 as(
select cast(cast( Year(date1)*10000 + MONTH(date1)*100 + 1 as
varchar(255)) as date) quarterlyDates From cte)
SELECT stuff((
SELECT ', ' + cast(quarterlyDates as varchar(max))
FROM cte2
FOR XML PATH('')
), 1, 2, '');
use FOR XML Path with type directive to avoid encoding of illegal characters in result
;WITH cte
AS (SELECT #startDate date1
UNION ALL
SELECT Dateadd(month, 3, date1)
FROM cte
WHERE date1 < #endDate)
SELECT Stuff((SELECT ',' + CONVERT(VARCHAR(15), date1, 106) quarterlyDates
FROM cte
FOR xml path, type).value('.[1]', 'nvarchar(max)'), 1, 1, '');
Note : I have altered the unwanted manipulating in the final select. Use style 106 in Convert function to get the required output format
Late answer and just for fun.
Example
declare #startDate datetime = '01-jan-2014'
declare #endDate datetime = '01-jul-2017'
;With cte
As
( Select date1 = #startDate
,dates = ''''+convert(varchar(max),convert(varchar(11),#startDate,113))+''''
Union All
Select DateAdd(Month,3,date1)
,cte.dates+','''+convert(varchar(11),DateAdd(Month,3,date1) ,106)+''''
From cte where date1 < #endDate
)
Select Top 1 with ties
Dates=lower(replace(Dates,' ','-') )
From cte
Order By Date1 Desc
Returns
'01-jan-2014','01-apr-2014','01-jul-2014','01-oct-2014','01-jan-2015','01-apr-2015','01-jul-2015','01-oct-2015','01-jan-2016','01-apr-2016','01-jul-2016','01-oct-2016','01-jan-2017','01-apr-2017','01-jul-2017'

Find Count With Pivot Data SQL Server

I have been displaying Day Wise Attendance Data with Pivot SQL.
declare #startdate datetime = '2016-09-26'
declare #enddate datetime = '2016-10-01'
declare #CompanyID int = 1
DECLARE #COLUMN VARCHAR(MAX), #SQL NVARCHAR(MAX);
SET #COLUMN = N'';
DECLARE #DATERANGE TABLE (DateToCheck DATE)
;WITH Temp
AS
(
SELECT DT =DATEADD(DD,0, #startdate)
WHERE DATEADD(DD, 1, #startdate) <= #enddate
UNION ALL
SELECT DATEADD(DD, 1, DT)
FROM Temp
WHERE DATEADD(DD, 1, DT) <= #enddate
)
INSERT INTO #DATERANGE
SELECT DT From Temp
SELECT #COLUMN += N', T.' + QUOTENAME(DateRanges) FROM (SELECT CAST(CONVERT(DATE, T.DateToCheck) AS VARCHAR(10)) AS DateRanges FROM #DATERANGE T group by T.DateToCheck) AS A;
SET #SQL = '
DECLARE #DATERANGE TABLE (DateToCheck DATE)
;WITH Temp
AS
(
SELECT DT =DATEADD(DD,0, #startdate)
WHERE DATEADD(DD, 1, #startdate) <= #enddate
UNION ALL
SELECT DATEADD(DD, 1, DT)
FROM Temp
WHERE DATEADD(DD, 1, DT) <= #enddate
)
INSERT INTO #DATERANGE
SELECT DT From Temp
SELECT *
FROM (
SELECT E.FirstName, E.LastName, E.Email, T.DateToCheck, COALESCE(A.val, L.val, H.val, ''Absent'') val
FROM AspNetUsers E
CROSS APPLY (
SELECT DateToCheck FROM #DATERANGE
) T--(DateToCheck)
LEFT JOIN (SELECT ''Holiday'' val, HolidayDate, CompanyID FROM Holidays) H ON H.HolidayDate = T.DateToCheck AND H.CompanyID = #CompanyID
LEFT JOIN (SELECT ''In : '' + CONVERT(VARCHAR, MIN(AttendanceDateTime), 108) + '' / Out : '' + CONVERT(VARCHAR, MAX(AttendanceDateTime), 108) val, CAST(AttendanceDateTime As DATE) As AttendanceDate, UserID FROM Attendances GROUP BY CAST(AttendanceDateTime As DATE), UserID) A ON A.AttendanceDate = T.DateToCheck AND A.UserID = E.Id
LEFT JOIN (SELECT ''Leave'' val, LeaveDate, UserID FROM LeaveApplications) L ON L.LeaveDate = T.DateToCheck AND L.UserID = E.Id
WHERE E.CompanyID = #CompanyID
) T
PIVOT (MAX(val) FOR DateToCheck IN (' + STUFF(REPLACE(#COLUMN, ', T.[', ',['), 1, 1, '') + ')) P';
EXEC sp_executesql #SQL, N'#startdate DATE, #enddate DATE, #CompanyID INT', #startdate, #enddate, #CompanyID
And below is the result set of how it's now
Now I wish to add more field to the above SQL to display counts like PresentCount, AbsentCount, HolidayCount and LeaveCount
I have already written a SQL where I could easily display these counts but, I'm unable to make it work with the above PIVOT SQL.
So in this case, the result for first row would be PresentCount = 0, AbsentCount = 6, HolidayCount = 0 and LeaveCount = 0. For Row 2 it would be PresentCount = 4, AbsentCount = 2, LeaveCount and HolidayCount both is 0.

SQL Query for getting nth Weekday date between two dates

My scenario is as below:
#StartDate = 13th of current month
#EndDate = 12th of next month.
I want to get all the date with the day-name for Mondays, Tuesdays, Wednesdays, Thursdays, Fridays, Saturdays and Sundays lying between the start and end date.
Try this:
declare #startDate datetime = '2016-01-13'
declare #endDate datetime = '2016-02-12'
;with dateRange as
(
select [Date] = dateadd(dd, 1, #startDate)
where dateadd(dd, 1, #startDate) < #endDate
union all
select dateadd(dd, 1, [Date])
from dateRange
where dateadd(dd, 1, [Date]) < #endDate
)
select [Date], datename(dw,[Date])
from dateRange
To count the number of each day as per your comment (this should be part of the question really), change the last part of James' answer to this:
select datename(dw,[Date]) as day_name, count([Date]) as number_days
from dateRange group by datename(dw,[Date]), datepart(DW,[Date])
order by datepart(DW,[Date]);
You can try something like this :
DECLARE #StartDate DATETIME
DECLARE #StartDateFixed DATETIME
DECLARE #EndDate DATETIME
DECLARE #NumberOfDays int
SET #StartDate = '2016/01/01'
SET #EndDate = '2016/01/02'
SET #NumberOfDays = DATEDIFF(DAY,#StartDate,#EndDate) + 1
SET #StartDateFixed = DATEADD(DD,-1,#StartDate)
SELECT WeekDay , COUNT(WeekDay)
FROM (
SELECT TOP (#NumberOfDays) WeekDay = DATENAME(DW , DATEADD(DAY,ROW_NUMBER() OVER(ORDER BY spt.name), #StartDateFixed))
FROM [master].[dbo].[spt_values] spt
) A
GROUP BY WeekDay
The output will be
WeekDay
------------------------------ -----------
Friday 1
Saturday 1
(2 row(s) affected)
In case if you need to get current and next date from date number specified such as 13 and 12
Current Month
DECLARE #cur_mont INT = (SELECT MONTH(GETDATE()))
Current Year
DECLARE #cur_year INT = (SELECT YEAR(GETDATE()))
Next Month
DECLARE #nxt_mont INT = (SELECT MONTH(DATEADD(month, 1, GETDATE())))
Next Month year (In case of December year change)
DECLARE #nxt_year INT = (SELECT YEAR(DATEADD(month, 1, GETDATE())))
Create start date
DECLARE #startDate DATETIME = (SELECT CAST(CAST(#cur_year AS varchar) + '-' + CAST(#cur_mont AS varchar) + '-' + CAST(13 AS varchar) AS DATETIME))
Create end date
DECLARE #endDate DATETIME = (SELECT CAST(CAST(#nxt_year AS varchar) + '-' + CAST(#nxt_mont AS varchar) + '-' + CAST(12 AS varchar) AS DATETIME))
Dates between start and end date
SELECT TOP (DATEDIFF(DAY, #startDate, #endDate) + 1)
DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY a.object_id) - 1, #startDate) AS Date,
DATENAME(DW, DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY a.object_id) - 1, #startDate)) AS Day
FROM sys.all_objects a CROSS JOIN sys.all_objects b;
DECLARE #dayStart int = 13, --The day of current month
#dayEnd int = 12, --The day of another month
#howManyMonth int = 1, --How many month to take
#dateStart date,
#dateEnd date
--Here we determine range of the dates
SELECT #dateStart = CONVERT (date,
CAST(DATEPART(Year,GETDATE()) as nvarchar(5))+ '-' +
CASE WHEN LEN(CAST(DATEPART(Month,GETDATE()) as nvarchar(5))) = 1
THEN '0'+CAST(DATEPART(Month,GETDATE()) as nvarchar(5))
ELSE CAST(DATEPART(Month,GETDATE()) as nvarchar(5)) END + '-' +
CAST (#dayStart as nvarchar(5))),
#dateEnd = CONVERT (date,
CAST(DATEPART(Year,DATEADD(Month,#howManyMonth,GETDATE())) as nvarchar(5))+ '-' +
CASE WHEN LEN(CAST(DATEPART(Month,DATEADD(Month,#howManyMonth,GETDATE())) as nvarchar(5))) = 1
THEN '0'+CAST(DATEPART(Month,DATEADD(Month,#howManyMonth,GETDATE())) as nvarchar(5))
ELSE CAST(DATEPART(Month,DATEADD(Month,#howManyMonth,GETDATE())) as nvarchar(5)) END + '-' +
CAST (#dayEnd as nvarchar(5)))
;WITH cte AS (
SELECT #dateStart as date_
UNION ALL
SELECT DATEADD(day,1,date_)
FROM cte
WHERE DATEADD(day,1,date_) <= #dateEnd
)
--Get results
SELECT DATENAME(WEEKDAY,date_) as [DayOfWeek],
COUNT(*) as [DaysCount]
FROM cte
GROUP BY DATEPART(WEEKDAY,date_),
DATENAME(WEEKDAY,date_)
ORDER BY DATEPART(WEEKDAY,date_)
OPTION (MAXRECURSION 0)
Output:
DayOfWeek DaysCount
----------- -----------
Sunday 4
Monday 4
Tuesday 4
Wednesday 5
Thursday 5
Friday 4
Saturday 4
(7 row(s) affected

How to split date ranges based on months in SQL Server 2005

Ex: date range is 01-01-2011 to 01-01-2012, I want the output like this :
01-01-2011 31-01-2011
01-02-2011 28-02-2011
How can I do this ? I'm using SQL Server 2005..
Thanks
Using CTE:
DECLARE #Begin DATETIME
DECLARE #End DATETIME
SELECT #Begin = '20110101', #End = '20120101'
;WITH ranges(DateFrom, DateTo) AS
(
SELECT #Begin, DATEADD(DAY, -1, DATEADD(MONTH, 1, #begin))
UNION ALL
SELECT DATEADD(month, 1, DateFrom), DATEADD(DAY, -1, DATEADD(MONTH, 2, DateFrom))
FROM ranges
WHERE DateFrom < #End
)
SELECT * FROM ranges
OPTION(MAXRECURSION 0)
And not using CTE:
DECLARE #Begin DATETIME
DECLARE #End DATETIME
SELECT #Begin = '20110101', #End = '20120101'
SELECT DATEADD(MONTH, n.Number, #Begin) DateFrom, DATEADD(day, -1, DATEADD(MONTH, n.Number+1, #Begin)) DateTo
FROM master.dbo.spt_values n
WHERE
n.Number < DATEDIFF(MONTH, #begin, #end)
AND n.Type = 'P'
If you need to include January 2012 too, use this
DECLARE #Begin DATETIME
DECLARE #End DATETIME
SELECT #Begin = '20110101', #End = '20120101'
SELECT DATEADD(MONTH, n.Number, #Begin) DateFrom, DATEADD(day, -1, DATEADD(MONTH, n.Number+1, #Begin)) DateTo
FROM master.dbo.spt_values n
WHERE
n.Number <= DATEDIFF(MONTH, #begin, #end)
AND n.Type = 'P'
And CTE:
DECLARE #Begin DATETIME
DECLARE #End DATETIME
SELECT #Begin = '20110101', #End = '20120101'
;WITH ranges(DateFrom, DateTo) AS
(
SELECT #Begin, DATEADD(DAY, -1, DATEADD(MONTH, 1, #begin))
UNION ALL
SELECT DATEADD(month, 1, DateFrom), DATEADD(DAY, -1, DATEADD(MONTH, 2, DateFrom))
FROM ranges
WHERE DATEADD(month, 1, DateFrom) < #End
)
SELECT * FROM ranges
OPTION(MAXRECURSION 0)
>On Providing the Start and End Date range, it can be split into months. This might help.
DECLARE #StartDate datetime
DECLARE #EndDate datetime
DECLARE #tmpStart datetime
DECLARE #tmpEnd datetime
Select #StartDate = '2012-01-01'
Select #EndDate = '2009-01-01'
Select #StartDate = DATEADD(MONTH,1,Convert(DATETIME,Convert(VARCHAR(25), Datepart (YEAR,#StartDate)) + '-' + Convert(VARCHAR(25), Datepart(MONTH, #StartDate)) + '-' + Convert(VARCHAR(25), 1)))
Select #EndDate = DATEADD(MONTH,1,Convert(DATETIME,Convert(VARCHAR(25), Datepart(YEAR, #EndDate)) + '-' + Convert(VARCHAR(25), Datepart(MONTH, #EndDate)) + '-' + Convert(VARCHAR(25), 1)))
Select #EndDate = DATEADD(DD,-1, DATEADD(MM,1,#EndDate))
Select #tmpEnd = #EndDate
Select #tmpStart = Convert(DATETIME,Convert(VARCHAR(25), Datepart(YEAR, #tmpEnd)) + '-' +
Convert(VARCHAR(25), Datepart(MONTH, #tmpEnd)) + '-' + Convert(VARCHAR(25), 1))
Select #StartDate 'Start' , #EndDate 'End'
While #tmpStart <= #StartDate
BEGIN
Select #tmpStart 'tmpStart' , #tmpEnd 'tmpEnd'
Select #tmpStart = DATEADD(MM,1,#tmpStart)
Select #tmpEnd = DATEADD(DD,-1,DATEADD (MM, 1 , #tmpStart))
END