SQL - Convert results into comma separated string - sql-server

Using another article on StackOverflow (How to split date ranges based on months in SQL Server 2005) I have run a SELECT statement which splits up a date range by month and returns 2 columns (DateFrom, DateTo) in SQL.
DECLARE #SDate DATE = '2012/08/01'
DECLARE #EDate DATE = '2013/09/01'
SELECT
DATEADD(MONTH, n.Number, #SDate) as DateFrom,
DATEADD(day, -1, DATEADD(MONTH, n.Number, DATEADD(YEAR,-1,#EDate))) as DateTo
FROM
master.dbo.spt_values n
WHERE
n.Number < DATEDIFF(MONTH, #SDate, #EDate)
AND n.Type = 'P'
I now need to add each of the returned rows into a string separating the columns by | (Dateto|Datefrom) and each row by ,.
For example if your run the code above the result would be (just for this example im only using the first 4 rows but I need all of them in one string):
R | Date From | Date To
1 | 2012-08-01 | 2012-08-31
2 | 2012-09-01 | 2012-09-30
3 | 2012-10-01 | 2012-10-30
4 | 2012-11-01 | 2012-11-30
Code:
DECLARE #stralldates VarChar(MAX)
/* SET #stralldates = INSERTCODE */
PRINT #stralldates
What I need PRINT to return:
2012-08-01|2012-08-31,2012-10-01|2012-10-30,2012-10-01|2012-10-30,2012-11-01|2012-11-30
I have tried several suggestions from other similar questions on StackOverflow (such as CONCAT) with no success.
Any help or suggestions would be appreciated.

set #StrAllDates =
stuff((select ','+convert(char(10), SDate, 121)+'|'+convert(char(10), dateadd(day, -1, dateadd(month, 1, SDate)), 121)
from (
select dateadd(month, n.number, #SDate) as SDate
from master..spt_values as n
where n.number < datediff(month, #SDate, #EDate) and
n.type = 'P'
) as T
order by SDate
for xml path('')), 1, 1, '')

I only know Oracle which provides wm_concat (undocumented) or listagg depending on version.

You can use the below script to get the data in the format you want to. It basically uses the coalesce method for concatenanation. I created a temp table to hold the data which is then used to iterate over the rows.
DECLARE #SDate DATE = '2012/08/01'
DECLARE #EDate DATE = '2013/09/01'
SELECT
DATEADD(MONTH, n.Number, #SDate) as DateFrom,
DATEADD(day, -1, DATEADD(MONTH, n.Number, DATEADD(YEAR,-1,#EDate))) as DateTo
INTO #tmp_data
FROM master.dbo.spt_values n
WHERE
n.Number < DATEDIFF(MONTH, #SDate, #EDate)
AND n.Type = 'P'
declare #my_string varchar(8000);
select #my_string =
coalesce( #my_string + ',', '')
+ convert(varchar(10), d.DateFrom, 126)
+ '|' + convert(varchar(10), d.DateTo, 126)
from #tmp_data d
order by d.DateFrom
select #my_string
drop table #tmp_data
Also, if you want to use the row rumber, you can use use it by adding another column to the select clause - ROW_NUMBER() OVER(ORDER BY n.Number) as RowNum

The following query will give you the required comma seperated string:
DECLARE #Begin DATETIME
DECLARE #End DATETIME
Declare #test Table(startDate datetime, endDate datetime)
DECLARE #listStr VARCHAR(MAX)
SELECT #Begin = '20110101', #End = '20120101'
Insert into #test
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'
select #listStr = COALESCE(#listStr+',' ,'')+ CONVERT(VARCHAR(10), startDate, 120) + '|' + CONVERT(varchar(10),endDate,120) from #test
select #listStr

Related

Return next 10 days including weekday name

Looking for a query or function which, for a given date, will return next 10 days (including the given date as a parameter) as two columns:
- date
- weekday name
I am using SQL Server 2019.
UPDATE (#Dale K):
I have calculated dates and weekdays, but those are as two separate queries and in new row instead of multiple rows
declare #mydate datetime
set #mydate = '2020-1-1'
select #mydate + 0, #mydate + 1, #mydate + 2, #mydate + 3, #mydate + 4, #mydate + 5, #mydate + 6
select
datename(dw, #mydate + 0),
datename(dw, #mydate + 1),
datename(dw, #mydate + 2),
datename(dw, #mydate + 3),
datename(dw, #mydate + 4),
datename(dw, #mydate + 5),
datename(dw, #mydate + 6)
If you always need 10 days, you can use a function such as this:
CREATE FUNCTION dbo.GetNext10Days(#FromDate DATE)
RETURNS TABLE AS RETURN
SELECT DATEADD(DAY,n,#FromDate) AS TheDate,
DATENAME(WEEKDAY,DATEADD(DAY,n,#FromDate)) AS WeekDayName
FROM (VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) v(n)
GO
SELECT * FROM dbo.GetNext10Days(GETDATE())
If you might need a different number of days, you can create a function that returns a table of numbers and call that function instead of the VALUES clause (to generate the numbers, I prefer the method described in this answer: https://stackoverflow.com/a/1394239/1187211).
you can use dateadd and datename(weekday,date) function to do it.
create function dbo.getnext10days(#fromdate date)
returns table as return
with cte as (
select 1 val,dateadd(day,1,#fromdate) [date]
union all
select t2.val +1 as val,dateadd(day,t2.val+1,#fromdate) from (select 1 val) t1
inner join cte t2 on t2.val < 10
)
select
[date],datename(weekday,[date]) as [weekday name]
from cte;
online demo link
You can also use the inbuilt spt_values to generate the dates as shown below.
SELECT
DATEADD(DAY,number+1, getdate()) [Date],
datename(weekday, DATEADD(DAY,number+1, getdate())) [Week Day]
FROM master..spt_values
WHERE type = 'P'
AND DATEADD(DAY,number+1, getdate()) < DATEADD(day, 10, getdate())
Here is the db<>fiddle demo.

Get dates between 2 dates with equal intervals

I have 2 dates 01/04/2017 and 30/04/2017. I want all the dates between these 2 dates with 7 days interval.
Expected Output :
01/04/2017
08/04/2017
15/04/2017
22/04/2017
29/04/2017
Please help!!
DECLARE #StartDate DATETIME,
#EndDate DATETIME
SELECT #StartDate = '2017-04-01',
#EndDate = '2017-04-30'
SELECT DATEADD(DAY, number*7, #StartDate)
FROM master.dbo.spt_values
WHERE type='P'
AND #EndDate >= DATEADD(DAY, number*7, #StartDate)
One method would be to use a Calendar table. Then return the results from there using the modulus to get the 7th rows:
WITH Dates AS(
SELECT *,
ROW_NUMBER() OVER (ORDER BY [date]) AS RN
FROM DateTable
WHERE [Date] BETWEEN '20170401' AND '20170430')
SELECT *
FROM Dates
WHERE (RN - 1) % 7 = 0;
I've used this solution, as from your post you imply that you might supply any date range, and that the 1st day may not necessarily be a Monday (or other specific day).
Try this
DECLARE #STRT DATETIME='04/01/2017',#END DATETIME ='04/30/2017'
;WITH CTE
AS
(
SELECT
MyDate = CAST(#STRT AS DATETIME)
UNION ALL
SELECT
MyDate = CAST(MyDate AS DATETIME)+7
FROM CTE
WHERE CAST(MyDate AS DATETIME)+7 < CAST(#END AS DATETIME)
)
SELECT
*
FROM CTE
result
Declare #StartDate DATE=CONVERT(DATE,'01/04/2017',104),#EndDate DATE=CONVERT(DATE,'01/12/2017',104)
Declare #String NVARCHAR(MAX)=''
WHILE (#StartDate<=#EndDate AND DATEDIFF(wk,#StartDate,#EndDate)>=0)
BEGIN
SET #String=#String+CONVERT(NVARCHAR(100),#StartDate)+CHAR(10)+CHAR(13)
SET #StartDate=DATEADD(d,7,#StartDate)
END
PRINT #String
GO

SQL server find the date between two selected date [duplicate]

This question already has answers here:
Get a list of dates between two dates using a function
(21 answers)
Closed 8 years ago.
I need the sql query which gives result between all date by passing two dates. For example, suppose I sent 01/01/2015 and 10/01/2015
I need the date between passed dates
The result should be :
01/01/2015
02/01/2015
03/01/2015
04/01/2015
05/01/2015
..
10/01/2015
How can I achieve that?
You can use a recursive CTE for this:
DECLARE #startDate DATETIME = '2015-01-01',
#endDate DATETIME = '2015-01-10'
;WITH dates AS(
SELECT #startDate AS date
UNION ALL
SELECT DATEADD(dd,1,date)
FROM dates
WHERE date<#endDate
)
SELECT * FROM dates
Try this :
declare #strt date;
declare #end date;
select #strt = '20150101';
select #end = '20150110';
with dates as
(
select dt = dateadd(dd, 0, #strt)
where dateadd(dd, 1, #strt) <= #end
union all
select dateadd(dd, 1, dt)
from dates
where dateadd(dd, 1, dt) <= #end
)
select * from dates
Use a Numbers table to generate dates.
DECLARE #StartDate DATETIME = convert(date,'01/01/2015',103) -- First Calendar date to include in table
DECLARE #EndDate DATETIME = convert(date,'10/01/2015',103) --Last calendar date to include in the table
;WITH E00(N) AS (SELECT 1 UNION ALL SELECT 1),
E02(N) AS (SELECT 1 FROM E00 a, E00 b),
E04(N) AS (SELECT 1 FROM E02 a, E02 b),
E08(N) AS (SELECT 1 FROM E04 a, E04 b),
E16(N) AS (SELECT 1 FROM E08 a, E08 b),
E32(N) AS (SELECT 1 FROM E16 a, E16 b),
cteTally(N)
AS (SELECT Row_number()OVER ( ORDER BY N)
FROM E32),
CalendarBase
AS (SELECT CalendarDate = Dateadd(day, n - 1, #StartDate)
FROM cteTally
WHERE N <= Datediff(day, #StartDate, #EndDate + 1))
SELECT convert(varchar(30),CalendarDate ,103) as CalendarDate
FROM CalendarBase
Referred from this link
#Saurabh Dhakate
Use the below code:
declare #date1 date ='2015-01-10'
declare #date2 date ='2015-01-01'
declare #lv_table table (datepart1 date)
declare #count int
declare #count1 int = 1
set #count=(select day(#date1) )
print #count
while #count1<=#count
begin
insert into #lv_table
select dateadd(day,#count1,#date2)
set #count1=#count1+1
print #count1
end
select * from #lv_table

Passing in Week Day name to get nearest date in SQL

I'm working on a query that deals with a frequency value (i.e. Mondays, Tuesdays, etc. - Think assignments).
So in my query I currently have a result of
jobId:1, personId:100, frequencyVal: 'Mondays'
jobId:2, personId:101, frequencyVal: 'Saturdays'
What I need is the next the 4 future(or current) dates for the frequencyVal.
So if today is 1/3/2015
I would need my result set to be
jobId:1, personId:100, frequencyVal: 'Mondays', futureDates: '1/5,1/12,1/19,1/26'
jobId:2, personId:102, frequencyVal: 'Saturdays', futureDates: '1/3,1/10,1/17,1/24'
I was looking at the following post:
How to find the Nearest (day of the week) for a given date
But that sets it for a specific date. And I'm looking at this being a web application and I want the dates for the current date. So if I try to run this query next Tuesday the future dates for jobId:1 would remove the 1/5 and add the 2/2.
Is there a way to pass in a weekday value to get the next nearest date?
I prefer a calendar table for this kind of query. Actually, I prefer a calendar table over date functions for most queries. Here's a minimal one. The one I use in production has more columns and more rows. (100 years of data is only 37k rows.)
create table calendar (
cal_date date not null primary key,
day_of_week varchar(15)
);
insert into calendar (cal_date) values
('2015-01-01'), ('2015-01-02'), ('2015-01-03'), ('2015-01-04'),
('2015-01-05'), ('2015-01-06'), ('2015-01-07'), ('2015-01-08'),
('2015-01-09'), ('2015-01-10'), ('2015-01-11'), ('2015-01-12'),
('2015-01-13'), ('2015-01-14'), ('2015-01-15'), ('2015-01-16'),
('2015-01-17'), ('2015-01-18'), ('2015-01-19'), ('2015-01-20'),
('2015-01-21'), ('2015-01-22'), ('2015-01-23'), ('2015-01-24'),
('2015-01-25'), ('2015-01-26'), ('2015-01-27'), ('2015-01-28'),
('2015-01-29'), ('2015-01-30'), ('2015-01-31'),
('2015-02-01'), ('2015-02-02'), ('2015-02-03'), ('2015-02-04'),
('2015-02-05'), ('2015-02-06'), ('2015-02-07'), ('2015-02-08'),
('2015-02-09'), ('2015-02-10'), ('2015-02-11'), ('2015-02-12'),
('2015-02-13'), ('2015-02-14'), ('2015-02-15'), ('2015-02-16'),
('2015-02-17'), ('2015-02-18'), ('2015-02-19'), ('2015-02-20'),
('2015-02-21'), ('2015-02-22'), ('2015-02-23'), ('2015-02-24'),
('2015-02-25'), ('2015-02-26'), ('2015-02-27'), ('2015-02-28')
;
update calendar
set day_of_week = datename(weekday, cal_date);
alter table calendar
alter column day_of_week varchar(15) not null;
alter table calendar
add constraint cal_date_matches_dow
check (datename(weekday, cal_date) = day_of_week);
create index day_of_week_ix on calendar (day_of_week);
Set the privileges so that
everyone can select, but
almost nobody can insert new rows, and
even fewer people can delete rows.
(Or write a constraint that can guarantee there are no gaps. I think you can do that in SQL Server.)
You can select the next four Mondays after today with a very simple SQL statement. (The current date is 2015-01-05, which is a Monday.)
select top 4 cal_date
from calendar
where cal_date > convert(date, getdate())
and day_of_week = 'Monday'
order by cal_date;
CAL_DATE
--
2015-01-12
2015-01-19
2015-01-26
2015-02-02
For me, this is a huge advantage. No procedural code. Simple SQL that is obviously right. Big win.
Your sample table
create table #t
(
jobId int,
personId int,
frequencyVal varchar(10)
);
insert into #t values (1,100,'Mondays'),(2,101,'Saturdays');
QUERY 1 : Select nearest 4 week of days in current month for particular week day
-- Gets first day of month
DECLARE #FIRSTDAY DATE=DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0)
;WITH CTE as
(
-- Will find all dates in current month
SELECT CAST(#FIRSTDAY AS DATE) as DATES
UNION ALL
SELECT DATEADD(DAY,1,DATES)
FROM CTE
WHERE DATES < DATEADD(MONTH,1,#FIRSTDAY)
)
,CTE2 AS
(
-- Join the #t table with CTE on the datename+'s'
SELECT jobId,personId,frequencyVal,DATES,
-- Get week difference for each weekday
DATEDIFF(WEEK,DATES,GETDATE()) WEEKDIFF,
-- Count the number of weekdays in a month
COUNT(DATES) OVER(PARTITION BY DATENAME(WEEKDAY,CTE.DATES)) WEEKCOUNT
FROM CTE
JOIN #t ON DATENAME(WEEKDAY,CTE.DATES)+'s' = #t.frequencyVal
WHERE MONTH(DATES)= MONTH(GETDATE())
)
-- Converts to CSV and make sure that only nearest 4 week of days are generated for month
SELECT DISTINCT C2.jobId,C2.personId,frequencyVal,
SUBSTRING(
(SELECT ', ' + CAST(DATEPART(MONTH,DATES) AS VARCHAR(2)) + '/' +
CAST(DATEPART(DAY,DATES) AS VARCHAR(2))
FROM CTE2
WHERE C2.jobId=jobId AND C2.personId=personId AND C2.frequencyVal=frequencyVal AND
((WEEKDIFF<3 AND WEEKDIFF>-3 AND WEEKCOUNT = 5) OR WEEKCOUNT <= 4)
ORDER BY CTE2.DATES
FOR XML PATH('')),2,200000) futureDates
FROM CTE2 C2
SQL FIDDLE
For example, in Query2 the nearest date(here we take example as Saturday) of
2015-Jan-10 will be 01/03,01/10,01/17,01/24
2015-Jan-24 will be 01/10,01/17,01/24,01/31
QUERY 2 : Select next 4 week's dates for particular week day irrelevant of month
;WITH CTE as
(
-- Will find the next 4 week details
SELECT CAST(GETDATE() AS DATE) as DATES
UNION ALL
SELECT DATEADD(DAY,1,DATES)
FROM CTE
WHERE DATES < DATEADD(DAY,28,GETDATE())
)
,CTE2 AS
(
-- Join the #t table with CTE on the datename+'s'
SELECT jobId,personId,frequencyVal, DATES,
ROW_NUMBER() OVER(PARTITION BY DATENAME(WEEKDAY,CTE.DATES) ORDER BY CTE.DATES) DATECNT
FROM CTE
JOIN #t ON DATENAME(WEEKDAY,CTE.DATES)+'s' = #t.frequencyVal
)
-- Converts to CSV and make sure that only 4 days are generated for month
SELECT DISTINCT C2.jobId,C2.personId,frequencyVal,
SUBSTRING(
(SELECT ', ' + CAST(DATEPART(MONTH,DATES) AS VARCHAR(2)) + '/' +
CAST(DATEPART(DAY,DATES) AS VARCHAR(2))
FROM CTE2
WHERE C2.jobId=jobId AND C2.personId=personId AND C2.frequencyVal=frequencyVal
AND DATECNT < 5
ORDER BY CTE2.DATES
FOR XML PATH('')),2,200000) futureDates
FROM CTE2 C2
SQL FIDDLE
The following would be the output if the GETDATE() (if its Saturday) is
2015-01-05 - 1/10, 1/17, 1/24, 1/31
2015-01-24 - 1/24, 1/31, 2/7, 2/14
There's no built-in function to do it. But you can try this, you may place it inside a Scalar-Valued Function:
DECLARE #WeekDay VARCHAR(10) = 'Monday';
DECLARE #WeekDayInt INT;
SELECT #WeekDayInt = CASE #WeekDay
WHEN 'SUNDAY' THEN 1
WHEN 'MONDAY' THEN 2
WHEN 'TUESDAY' THEN 3
WHEN 'WEDNESDAY' THEN 4
WHEN 'THURSDAY' THEN 5
WHEN 'FRIDAY' THEN 6
WHEN 'SATURDAY' THEN 7 END
SELECT CONVERT(DATE, DATEADD(DAY, (DATEPART(WEEKDAY, GETDATE()) + #WeekDayInt) % 7, GETDATE())) AS NearestDate
UPDATE:
Looks like radar was right, here's the solution:
DECLARE #WeekDay VARCHAR(10) = 'Monday';
DECLARE #WeekDayInt INT;
DECLARE #Date DATETIME = GETDATE();
SELECT #WeekDayInt = CASE #WeekDay
WHEN 'SUNDAY' THEN 1
WHEN 'MONDAY' THEN 2
WHEN 'TUESDAY' THEN 3
WHEN 'WEDNESDAY' THEN 4
WHEN 'THURSDAY' THEN 5
WHEN 'FRIDAY' THEN 6
WHEN 'SATURDAY' THEN 7 END
DECLARE #Diff INT = DATEPART(WEEKDAY, #Date) - #WeekDayInt;
SELECT CONVERT(DATE, DATEADD(DAY, CASE WHEN #Diff >= 0 THEN 7 - #Diff ELSE ABS(#Diff) END, #Date)) AS NearestDate
Try this - based on king.code's answer to get the nearest date.
create table #t
(
jobId int,
personId int,
frequencyVal varchar(10)
);
insert into #t values (1,100,'Mondays'),(2,101,'Saturdays');
WITH cte(n) AS
(
SELECT 0
UNION ALL
SELECT n+1 FROM cte WHERE n < 3
)
select #t.jobId, #t.personId, #t.frequencyVal, STUFF(a.d, 1, 1, '') AS FutureDates
from #t
cross apply (SELECT CASE #t.frequencyVal
WHEN 'SUNDAYS' THEN 1
WHEN 'MONDAYS' THEN 2
WHEN 'TUESDAYS' THEN 3
WHEN 'WEDNESDAYS' THEN 4
WHEN 'THURSDAYS' THEN 5
WHEN 'FRIDAYS' THEN 6
WHEN 'SATURDAYS' THEN 7
END)tranlationWeekdays(n)
cross apply (select ',' + CONVERT(varchar(10), CONVERT(date,dateadd(WEEK, cte.n,CONVERT(DATE, DATEADD(DAY, (DATEPART(WEEKDAY, GETDATE()) + tranlationWeekdays.n) % 7, GETDATE()))))) from cte FOR XML PATH('')) a(d);
drop table #t;
Try this,
DECLARE #YEAR INT=2015
DECLARE #MONTH INT=1
DECLARE #DAY INT=1
DECLARE #DATE DATE = (SELECT DateFromParts(#Year, #Month, #Day))
DECLARE #TOTAL_DAYS INT =(SELECT DatePart(DY, #DATE));
WITH CTE1
AS (SELECT T_DAY=(SELECT DateName(DW, #DATE)),
#DATE AS T_DATE,
#DAY AS T_DDAY
UNION ALL
SELECT T_DAY=(SELECT DateName(DW, DateAdd(DAY, T_DDAY + 1, #DATE))),
DateAdd(DAY, T_DDAY + 1, #DATE) AS T_DATE,
T_DDAY + 1
FROM CTE1
WHERE T_DDAY + 1 <= 364)
SELECT DISTINCT T_DAY,
Stuff((SELECT ',' + CONVERT(VARCHAR(30), T_DATE)
FROM CTE1 A
WHERE A.T_DAY=CTE1.T_DAY AND A.T_DATE > GetDate() AND A.T_DATE<(DATEADD(WEEK,4,GETDATE()))
FOR XML PATH('')), 1, 1, '') AS FUTURE
FROM CTE1
ORDER BY T_DAY
OPTION (MAXRECURSION 365)
This is a simpler way I think, and I think it fits your requirements.
Note that I have changed your frequency_val column to an integer that represents the day of the week from SQL servers perspective and added a calculated column to illustrate how you can easily derive the day name from that.
declare #t table
(
jobId int,
personId int,
--frequencyVal varchar(10)
frequency_val int,
frequency_day as datename(weekday,frequency_val -1) + 's'
);
declare #num_occurances int = 4
declare #from_date date = dateadd(dd,3,getdate()) -- this will allow you to play with the date simply by changing the increment value
insert into #t
values
(1,100,1),--'Mondays'),
(2,101,6),--'Saturdays');
(3,101,7),--'Saturdays');
(4,100,2)--'Mondays'),
--select * from #t
;with r_cte (days_ahead, occurance_date)
as (select 0, convert(date,#from_date,121)
union all
select r_cte.days_ahead +1, convert(date,dateadd(DD, r_cte.days_ahead+1, #from_date),121)
from r_cte
where r_cte.days_ahead < 7 * #num_occurances
)
select t.*, r_cte.occurance_date
from
#t t
inner join r_cte
on DATEPART(WEEKDAY, dateadd(dd,##DATEFIRST - 1 ,r_cte.occurance_date)) = t.frequency_val
Having seen the use of DATENAME in some of the answers already given, I'd like to point out that return values of DATENAME might vary depending on your current language setting, but you can save the current language setting and ensure usage of us_english so you can be confident to use English weekday names.
Now here is my slightly different approach to get the 4 next dates that fall on a certain (known) weekday, using a user defined table valued function that allows to create a number sequence table (yes this is a pretty dull function, you have to pass MaxValue greater MinValue, but that could be easily enhanced, if needed, but hey, it does the job). Using that function span a table over 28 values (next 28 days should indeed include the next 4 relevant weekdays ;)), apply DATEADD on GETDATE and reduce the result set with WHERE to only those values that have the right weekday:
CREATE FUNCTION GetIntSequence(#MinValue INT, #MaxValue INT)
RETURNS #retSequence TABLE
(
IntValue INT NOT NULL
)
BEGIN
DECLARE #i INT = (SELECT #MinValue)
WHILE #i <= #MaxValue
BEGIN
INSERT INTO #retSequence (IntValue) SELECT #i
SELECT #i = #i + 1
END
RETURN
END
GO
DECLARE #weekDay NVARCHAR(MAX) = 'Monday' --(or Tuesday, wednesday, ...)
--save current language setting
DECLARE #languageBackup NVARCHAR(MAX) = (SELECT ##LANGUAGE)
--ensure us english language setting for reliable weekday names
SET LANGUAGE us_english;
SELECT FourWeeks.SomeDay FROM
(
SELECT
DATEADD(DAY, IntValue, GETDATE()) AS SomeDay
FROM dbo.GetIntSequence(1, 28)
) AS FourWeeks
WHERE DATENAME(WEEKDAY, SomeDay) = #weekDay
--restore old language setting
SET LANGUAGE #languageBackup;
GO
DROP FUNCTION dbo.GetIntSequence

Calculate 5 months before a date value

I have a query that outputs a date, and I'd like to add an additional column that represents the date 5 months prior to that date. So if the output value is 2012-06 then I want to show 2012-01.
SELECT
unnamed_date_column,
5_months_earlier = DATEADD(MONTH, -5, unnamed_date_column)
FROM dbo.unnamed_table;
If you are storing these as varchar (which you must be if they are in yyyy-mm, and you should stop doing that), then you can do this:
SELECT
unnamed_date_column,
5_months_earlier = DATEADD(MONTH, -5, unnamed_date_column)
FROM
(
SELECT unnamed_date_column = CONVERT(DATETIME, unnamed_varchar_column + '-01')
FROM dbo.unnamed_table
) AS x;
Of course, that could generate an error, because if you chose the wrong data type for this column, anybody could have entered 2013-13 or 1623-99 or who_dat into this column...
select [column]
from [table]
where [datecol] between DATEADD(month, -5, getdate()) and getdate()
After computing the start date of the first month (#Start) and the end date (#End) of the last month:
DECLARE #CurrentDate SMALLDATETIME; -- Or DATE[TIME][2][OFFSET]
SET #CurrentDate = GETDATE(); -- 2013-10-05
DECLARE #Start SMALLDATETIME, #End SMALLDATETIME;
SET #Start = DATEADD(MONTH, (DATEDIFF(MONTH, 0, #CurrentDate) - 4), 0);
SET #End = DATEADD(MONTH, (DATEDIFF(MONTH, 0, #CurrentDate) + 1), 0);
SELECT #Start AS [#Start], #End AS [#End];
/*
#Start #End
---------- ----------
2013-06-01 2013-11-01
*/
you could filter the rows using these predicates:
SELECT ...
FROM ...
WHERE SomeDateColumn >= #Start AND SomeDateColumn < #EndDate;
try this one:
DECLARE #DT DATETIME = GETUTCDATE()
SELECT CONVERT(VARCHAR(7),#DT, 120) AS TODAY_DATE, CONVERT(VARCHAR(7),DATEADD(MM,-5,#DT), 120 ) AS BEFORE_5_MONTHS

Resources