Display the month names available in quarters - sql

I want to display the month names available in the Quarters.
Means like we have four quarters 1,2,3,4 in a year. I have following query.
select datename(month,(DATEADD(QUARTER, DATEDIFF(QUARTER, 0, GETDATE()), 0)) )
Output is :October
But How should I modify this query so that I should get the output as:
October
November
December

declare #quarter datetime
set #quarter = DATEADD(QUARTER, DATEDIFF(QUARTER, 0, GETDATE()), 0)
select datename(month, #quarter)
union all
select datename(month, (DATEADD(month, 1, #quarter) ) )
union all
select datename(month, (DATEADD(month, 2, #quarter) ) )

Try this
DECLARE #d datetime = Dateadd(mm,0,getdate())
-- set #d = Dateadd(mm,-3,getdate())
;With Dates
AS
(
SELECT DATEADD(qq,DATEDIFF(qq,0,#d),0) AS StartDt,DATEPART(qq,#d) AS Qr
UNION ALL
SELECT DATEADD(mm,1,StartDt),DATEPART(qq,DATEADD(mm,1,StartDt+1)-1)
FROM Dates
WHERE DATEPART(qq,DATEADD(mm,1,StartDt+1)-1) = DATEPART(qq,#d)
)
SELECT
datename(month,StartDt) Mnth, Qr,StartDt
FROM Dates

SELECT DATENAME(m,DATEADD(qq, DATEDIFF(qq,0,getdate()), 0)) AS MonthsInQuarter
UNION ALL
SELECT DATENAME(m,DATEADD(mm,1,DATEADD(qq,DATEDIFF(qq,0,getdate()),0)))
UNION ALL
SELECT DATENAME(m,DATEADD(mm,2,DATEADD(qq,DATEDIFF(qq,0,getdate()),0)))

Related

How to get the last sunday of the year using TSQL?

I need to check if a given day is the last sunday of any year, if yes the return 1 using TSQL only.
I do not have much idea about TSQL.
SQL Server has a problem with weekdays, because they can be affected by internationalization settings. Assuming the defaults, you can do:
select dateadd(day,
1 - datepart(weekday, datefromparts(#year, 12, 31)),
datefromparts(#year, 12, 31)
)
Otherwise, you'll need to do a case expression to turn the day of the week into a number.
In an older version of SQL Server, you could do:
select dateadd(day,
1 - datepart(weekday, cast(#year + '0101' as date)),
cast(#year + '0101' as date)
)
I haven't worked with tsql specifically but if my sql knowledge and googling is good enough then something like this should do the trick:
... WHERE DATEPART(dw, date) = 7 and DATEDIFF (d, date, DATEFROMPARTS (DATEPART(yyyy, date), 12, 31)) <= 6
Basically we check if that day is Sunday at first and then if it's less than week away from last day of the year
Using Mr. Gordon's query, following IIF() returns 1 if given day is last Sunday of the year, returns 0 if it is not.
Using 2018 as year and 2018-12-30 as given date. You can replace values with variables.
select IIF( DATEDIFF(DAY,'2018-12-30',
DATEADD(day,
1 - datepart(weekday, datefromparts(2018, 12, 31)),
datefromparts(2018, 12, 31)
)) = 0, 1, 0)
You can use this function
Function Code :
create FUNCTION CheckIsSaturday
(
#date DATETIME
)
RETURNS int
AS
BEGIN
-- Declare the return variable here
DECLARE #result INT
DECLARE #DayOfWeek NVARCHAR(22)
DECLARE #LastDayOfYear DATETIME
select #LastDayOfYear=DATEADD(yy, DATEDIFF(yy, 0, #date) + 1, -1)
SELECT #DayOfWeek=DATENAME(dw, #date)
IF(#DayOfWeek='Saturday' AND DATEDIFF(dd,#date,#LastDayOfYear)<7)
RETURN 1;
RETURN 0;
END
GO
function Usage:
SELECT dbo.CheckIsSaturday('2017-12-23')
This becomes quite trivial if you have a Calendar Table
DECLARE #CheckDate DATE = '20181230'
;WITH cteGetDates AS
(
SELECT
[Date], WeekDayName, WeekOfMonth, [MonthName], [Year]
,LastDOWInMonth = ROW_NUMBER() OVER
(
PARTITION BY FirstDayOfMonth, [Weekday]
ORDER BY [Date] DESC
)
FROM
dbo.DateDimension
)
SELECT * FROM cteGetDates D
WHERE D.LastDOWInMonth = 1 AND D.WeekDayName = 'Sunday' and D.MonthName = 'December' AND D.[Date] = #CheckDate
You can also use this one to get every last day of the year:
;WITH getlastdaysofyear ( LastDay, DayCnt ) AS (
SELECT DATEADD(dd, -DAY(DATEADD(mm, 1, DATEADD(yy, DATEDIFF(yy, 0, GETDATE()) + 1, -1))),
DATEADD(mm, 1, DATEADD(yy, DATEDIFF(yy, 0, GETDATE()) + 1, -1))),
0 AS DayCnt
UNION ALL
SELECT LastDay,
DayCnt + 1
FROM getlastdaysofyear
)
SELECT *
FROM ( SELECT TOP 7 DATEADD(DD, -DayCnt, LastDay) LastDate,
'Last ' + DATENAME(Weekday,DATEADD(DD, -DayCnt, LastDay)) AS DayStatus
FROM getlastdaysofyear ) T
ORDER BY DATEPART(Weekday, LastDate)
Hope you like it :)

Get first day and month for last x calendar weeks

I want to get last 8 week starting from today ( GETDATE() )
So the format must be dd/mm for all 8 weeks.
I tried something like this
select "start_of_week" = cast(datepart(dd,dateadd(week, datediff(week, 0, getdate()), 0)) as CHAR(2))+'/'+cast(datepart(mm,dateadd(week, datediff(week, 0, getdate()), 0)) as CHAR(2));
and this is good only for the current week, but how to put this in query and return for curr-1,curr-2,...curr-7 weeks. The final result must be table with some amounts for one player and each week in format dd/mm
Maybe as easy as this?
WITH EightNumbers(Nmbr) AS
(
SELECT 0
UNION SELECT -1
UNION SELECT -2
UNION SELECT -3
UNION SELECT -4
UNION SELECT -5
UNION SELECT -6
UNION SELECT -7
UNION SELECT -8
)
SELECT CONVERT(VARCHAR(5),GETDATE()+(Nmbr*7),103)
FROM EightNumbers
ORDER BY Nmbr DESC
If you need (as the title suggests) the "first day" of the week, you might change the select to:
SELECT CONVERT(VARCHAR(5),GETDATE()+(Nmbr*7)-DATEPART(dw,GETDATE())+##DATEFIRST,103)
FROM EightNumbers
ORDER BY Nmbr DESC
Be aware that the "first day of week" depends on your system's culture. Have a look on ##DATEFIRST!
The result:
28/12
21/12
14/12
07/12
30/11
23/11
16/11
09/11
02/11
Here you go:
DECLARE #DateTable TABLE ( ADate DATETIME )
DECLARE #CurrentDate DATETIME
SET #CurrentDate = GETDATE()
WHILE (SELECT COUNT(*) FROM #DateTable WHERE DATEPART( dw, ADate ) = 2) <= 7
BEGIN
INSERT INTO #DateTable
SELECT #CurrentDate
SET #CurrentDate = DATEADD( dd, -1, #CurrentDate )
END
SELECT "start_of_week" = cast(datepart(dd,dateadd(week, datediff(week, 0, ADate), 0)) as CHAR(2))
+'/'+cast(datepart(mm,dateadd(week, datediff(week, 0, ADate), 0)) as CHAR(2))
FROM #DateTable
WHERE DATEPART( dw, ADate ) = 2
DELETE #DateTable
OUTPUT
start_of_week
28/12
21/12
14/12
7 /12
30/11
23/11
16/11
9 /11
Syntax :
select "start_of_week" =
cast(datepart(dd,dateadd(week, datediff(week, 0, getdate()) - X, 0)) as CHAR(2))
select "start_of_week" =
cast(datepart(dd,dateadd(week, datediff(week, 0, getdate()) - 0, 0)) as CHAR(2)) ,
"previous_week1" =
+'/'+cast(datepart(mm,dateadd(week, datediff(week, 0, getdate()) - 1, 0)) as CHAR(2)),
"previous_week2" =
+'/'+cast(datepart(mm,dateadd(week, datediff(week, 0, getdate()) - 2, 0)) as CHAR(2)),
"previous_week3" =
+'/'+cast(datepart(mm,dateadd(week, datediff(week, 0, getdate()) - 3, 0)) as CHAR(2));
and so on.... thank you
Assuming sys.all_objects has at least 8 rows and you want the first day of the week (which you did not specify in your question:
select top 8 convert(varchar(5),
dateadd(WEEK,
1-1* ROW_NUMBER() over(order by newid()),
dateadd(DD,
1-datepart(dw,getdate()),
getdate())),
1) as [FirstDayOfWeek]
from sys.all_objects
The convert just gives the month/day. The row number is used to give the numbers 1-8. I multiplied the row number by -1 and added 1 to get the numbers 0,-1,-2,...-7 and date added those (by day) to the first day of this week. I found the first day of this week by taking getdate and date adding the negative version of the day of the week + 1.

Find missing period and determine whether consecutive before

I am currently working on a requirement to find the missing period and then determine whether it was consecutive before the missing period
Following is my sample table structure.
First step: In the following sample table look at last 6 months (2014 7 - 2014 12). Its missing two months 8 & 11. Take the first instance 8.
Second step: Go back 6 months from the first instance missing - (2014 2- 2014 7) - see whether they are missing any months. If No (everything is consecutive) - Select/Include this record if Yes (missing some months) - don't select this record.
Year Month
2014 1
2014 2
2014 3
2014 4
2014 5
2014 6
2014 7
2014 9
2014 10
2014 12
I can select last 6 records and partition by row number and see whether its missing any. But I am not sure how to find if its consecutive and also select the missing period.
I am trying to do as much filtration in Transact-SQL so that I can focus on other validations on c#.
Query I created to find first period missing(not complete)
SELECT f.TYEAR,f.TMONTH, f.TMONTH+1 AS MISSING FROM #TEMPTABLE AS F
LEFT OUTER JOIN #TEMPTABLE AS F2 ON f.TMONTH+1 = f2.TMONTH
WHERE f2.TAXPERIOD IS NULL
Note: The above example can span b/w two calendar years. 2013 mm - 2014 mm
This one has been tested, I've spent some time on it, please let me know if you're happy with the result and vote if yes, cheers :-) PS: The table dbo.Months_and_Years contains your data (with the 2 missing months)
CREATE TABLE dbo.Test_Table (
[Year] SMALLINT,
[Month] TINYINT
);
INSERT INTO dbo.Test_Table
VALUES
(2014, 1),
(2014, 2),
(2014, 3),
(2014, 4),
(2014, 5),
(2014, 6),
(2014, 7),
(2014, 9),
(2014, 10),
(2014, 12);
DECLARE #MinValue TINYINT = 1
DECLARE #MaxValue TINYINT = 100
WHILE #MinValue < = #MaxValue
BEGIN
DECLARE #Missing_Month TINYINT = (
SELECT TOP 1 A.RowID
FROM (
SELECT DENSE_RANK() OVER ( ORDER BY [month]) AS RowID ,
*
FROM dbo.Test_Table
) AS A
WHERE A.RowID <> A.[Month]
)
SELECT #Missing_Month
IF #Missing_Month IS NULL
BREAK
ELSE
INSERT INTO dbo.Test_Table
VALUES (2014, #Missing_Month)
SET #MinValue = #MinValue + 1
END
-- Check your results ---
SELECT A.*
FROM dbo.Test_Table AS A
LEFT JOIN dbo.Months_and_Years AS B ON A.[Month] = B.[Month]
WHERE B.[Month] IS NULL;
I think below code should work, though I've not tested it properly. But you will get the idea -
DECLARE #TmpBaseTable TABLE ([Year] SMALLINT, [Month] TINYINT)
DECLARE #TmpSixMonthTable TABLE (TmpYear SMALLINT, TmpMonth TINYINT)
DECLARE #TmpDate DATE
DECLARE #MissingYear SMALLINT
DECLARE #MissingMonth TINYINT
DECLARE #TmpCount TINYINT
INSERT INTO #TmpBaseTable ([Year], [Month])
SELECT 2014, 1 UNION ALL
SELECT 2014, 2 UNION ALL
SELECT 2014, 3 UNION ALL
SELECT 2014, 4 UNION ALL
SELECT 2014, 5 UNION ALL
SELECT 2014, 6 UNION ALL
SELECT 2014, 7 UNION ALL
SELECT 2014, 8 UNION ALL
SELECT 2014, 9 UNION ALL
SELECT 2014, 10 UNION ALL
SELECT 2014, 11 UNION ALL
SELECT 2014, 12 UNION ALL
SELECT 2015, 1 UNION ALL
SELECT 2015, 3 UNION ALL
SELECT 2015, 4
SELECT TOP 1 #TmpDate = CAST(CAST(tmpYear AS VARCHAR) + '-' + CAST(tmpMonth AS VARCHAR) + '-' + CAST(1 AS VARCHAR) AS DATE)
FROM
(
SELECT ROW_NUMBER() OVER(ORDER BY [Year], [Month]) AS RowID, [Month] AS tmpMonth, [Year] AS tmpYear
FROM #TmpBaseTable
)
tmp ORDER BY RowID DESC
INSERT INTO #TmpSixMonthTable (TmpMonth, TmpYear)
SELECT DATEPART(MONTH, DATEADD (MONTH, -5, #TmpDate)), DATEPART(YEAR, DATEADD (MONTH, -5, #TmpDate)) UNION ALL
SELECT DATEPART(MONTH, DATEADD (MONTH, -4, #TmpDate)), DATEPART(YEAR, DATEADD (MONTH, -4, #TmpDate)) UNION ALL
SELECT DATEPART(MONTH, DATEADD (MONTH, -3, #TmpDate)), DATEPART(YEAR, DATEADD (MONTH, -3, #TmpDate)) UNION ALL
SELECT DATEPART(MONTH, DATEADD (MONTH, -2, #TmpDate)), DATEPART(YEAR, DATEADD (MONTH, -2, #TmpDate)) UNION ALL
SELECT DATEPART(MONTH, DATEADD (MONTH, -1, #TmpDate)), DATEPART(YEAR, DATEADD (MONTH, -1, #TmpDate)) UNION ALL
SELECT DATEPART(MONTH, DATEADD (MONTH, -0, #TmpDate)), DATEPART(YEAR, DATEADD (MONTH, -0, #TmpDate))
SELECT TOP 1 #MissingMonth = tmpSix.TmpMonth, #MissingYear = tmpSix.TmpYear FROM #TmpSixMonthTable tmpSix
LEFT OUTER JOIN #TmpBaseTable tmpBase ON tmpSix.TmpMonth = tmpBase.[Month] AND tmpSix.TmpYear = tmpBase.[Year]
WHERE tmpBase.[Year] IS NULL
SET #TmpDate = CAST(CAST(#MissingYear AS VARCHAR) + '-' + CAST(#MissingMonth AS VARCHAR) + '-' + CAST(1 AS VARCHAR) AS DATE)
DELETE FROM #TmpSixMonthTable
INSERT INTO #TmpSixMonthTable (TmpMonth, TmpYear)
SELECT DATEPART(MONTH, DATEADD (MONTH, -6, #TmpDate)), DATEPART(YEAR, DATEADD (MONTH, -6, #TmpDate)) UNION ALL
SELECT DATEPART(MONTH, DATEADD (MONTH, -5, #TmpDate)), DATEPART(YEAR, DATEADD (MONTH, -5, #TmpDate)) UNION ALL
SELECT DATEPART(MONTH, DATEADD (MONTH, -4, #TmpDate)), DATEPART(YEAR, DATEADD (MONTH, -4, #TmpDate)) UNION ALL
SELECT DATEPART(MONTH, DATEADD (MONTH, -3, #TmpDate)), DATEPART(YEAR, DATEADD (MONTH, -3, #TmpDate)) UNION ALL
SELECT DATEPART(MONTH, DATEADD (MONTH, -2, #TmpDate)), DATEPART(YEAR, DATEADD (MONTH, -2, #TmpDate)) UNION ALL
SELECT DATEPART(MONTH, DATEADD (MONTH, -1, #TmpDate)), DATEPART(YEAR, DATEADD (MONTH, -1, #TmpDate))
SELECT #TmpCount = COUNT(1) FROM #TmpSixMonthTable tmp1
INNER JOIN #TmpBaseTable tmp2 ON tmp1.TmpMonth = tmp2.[Month] AND tmp1.TmpYear = tmp2.[Year]
IF(#TmpCount = 6)
BEGIN
SELECT tmp2.[Month], tmp2.[Year] FROM #TmpSixMonthTable tmp1
INNER JOIN #TmpBaseTable tmp2 ON tmp1.TmpMonth = tmp2.[Month] AND tmp1.TmpYear = tmp2.[Year]
END
There can be a smarter way than this :)

How to get all the weekend dates of the current year in SQL?

I tried but could not get the right solution. I want an SQL query that lists all the weekend dates of the current year.
I tried this SQL query:
WITH hier(num, lvl) AS (
SELECT 0, 1
UNION ALL
SELECT 100, 1
UNION ALL
SELECT num + 1, lvl + 1
FROM hier
WHERE lvl < 100
)
SELECT lvl [Week],
convert(date,DATEADD(dw, -DATEPART(dw, DATEADD(wk,DATEDIFF(wk,0,'12/31/'+convert(nvarchar,YEAR(getdate()))), 0)+6 ),
DATEADD(wk, DATEDIFF(wk,0,'12/31/'+convert(nvarchar,YEAR(getdate()))), 0)+6 ) - num * 7,101) [End Date]
FROM hier a
where num < 52
ORDER BY [End Date] asc
Its output is like this:
Week End date
52 2012-01-14
51 2012-01-21
50 2012-01-28
49 2012-02-04
I want the dates to start from the beginning – so, the above is missing one weekend, which is 2012-07-01. Also, I want the week numbers to show as 1, 2, 3... instead of 52, 51....
Check out this blog post.
Your question is explained in detail.
DECLARE #Year AS INT,
#FirstDateOfYear DATETIME,
#LastDateOfYear DATETIME
-- You can change #year to any year you desire
SELECT #year = 2010
SELECT #FirstDateOfYear = DATEADD(yyyy, #Year - 1900, 0)
SELECT #LastDateOfYear = DATEADD(yyyy, #Year - 1900 + 1, 0)
-- Creating Query to Prepare Year Data
;WITH cte AS (
SELECT 1 AS DayID,
#FirstDateOfYear AS FromDate,
DATENAME(dw, #FirstDateOfYear) AS Dayname
UNION ALL
SELECT cte.DayID + 1 AS DayID,
DATEADD(d, 1 ,cte.FromDate),
DATENAME(dw, DATEADD(d, 1 ,cte.FromDate)) AS Dayname
FROM cte
WHERE DATEADD(d,1,cte.FromDate) < #LastDateOfYear
)
SELECT FromDate AS Date, Dayname
FROM CTE
WHERE DayName IN ('Saturday','Sunday') -- For Weekend
/*
WHERE DayName LIKE 'Sunday'
WHERE DayName NOT IN ('Saturday','Sunday') -- For Weekday
WHERE DayName LIKE 'Monday' -- For Monday
WHERE DayName LIKE 'Sunday' -- For Sunday
*/
OPTION (MaxRecursion 370)
Will this help
DECLARE #startDate DATETIME, #endDate DATETIME
SELECT #startDate = '2012-01-01', #endDate = '2012-12-31'
;WITH Calender AS (
SELECT #startDate AS dt
UNION ALL
SELECT dt + 1 FROM Calender
WHERE dt + 1 <= #endDate
)
SELECT
dt
,NameMonth = DATENAME(Month, dt)
,NameDay = DATENAME (Weekday,dt)
,WeekofYr = DATEPART(WEEK, dt) FROM Calender
WHERE DATENAME (Weekday,dt) IN ('Sunday')
Option(MaxRecursion 0)
Result(Partial)
dt NameMonth NameDay WeekofYr
2012-01-01 00:00:00.000 January Sunday 1
2012-01-08 00:00:00.000 January Sunday 2
...............................................
...............................................
2012-12-30 00:00:00.000 December Sunday 53
you can try this
DECLARE #FirstDateOfYear DATETIME
SET #FirstDateOfYear = ’2010-01-01′
SELECT DISTINCT DATEADD(d, number, #FirstDateOfYear),
CASE DATEPART(dw, DATEADD(d, number, #FirstDateOfYear))
WHEN 7 THEN ‘Saturday’
WHEN 1 THEN ‘Sunday’
ELSE ‘Work Day’
END
FROM master..spt_values
WHERE number BETWEEN 0 AND 364
AND (DATEPART(dw, DATEADD(d, number, #FirstDateOfYear)) = 1 OR DATEPART(dw, DATEADD(d, number, #FirstDateOfYear)) = 7)
ORDER BY DATEADD(d, number, #FirstDateOfYear)
Try to find the first Saturday by doing this:
Start on 2012-01-01
If it's not a Saturday, add a day
Goto 2
Then, into a temporary table, add that date and the following date (Sunday).
After that, loop the following:
Add 7 and 8 days to the last Saturday you found (you get the following Saturday and Sunday)
Check whether they are still in 2012
If they are, store them in temp table and goto 1
There may be more elegant ways, but that's my quick & dirty solution. As you didn't post any code of what you've tried, I'll leave the implementation up to you.
this also works
declare #dat datetime, #add int
set #dat = '20120101'
set #add = datepart(w,#dat)
set #add = 5 - #add -- friday
set #dat = dateadd(d,#add,#dat)
while #dat <= '20121231'
begin
print #dat
set #dat = dateadd(d,7,#dat)
end
;with AllDaysOfYear (Day) as (
select DATEADD(year,DATEDIFF(year,0,CURRENT_TIMESTAMP),0) --Jan 1st
union all
select DATEADD(day,1,Day) from AllDaysOfYear
where DATEPART(year,DATEADD(day,1,Day)) = DATEPART(year,CURRENT_TIMESTAMP)
)
select
ROW_NUMBER() OVER (ORDER BY Day) as WeekNo,
Day
from
AllDaysOfYear
where
DATEPART(weekday,Day) = DATEPART(weekday,'20120714')
option (maxrecursion 0)
First, generate a set of all of the days in the current year (AllDaysInYear). Then, select those whose weekday is a saturday. The value I've used ('20120714') isn't terribly important - it just has to be any saturday, from any year. I'm just using it to avoid needing to have particular DATEFIRST or language settings.
This query shows how to get the first day of this year and the first day of the next year in the first part. The first day of the next year is calculated once so as not to keep getting and comparing the year parts.
;WITH cte(TheDate,NextYear) AS
(
SELECT CAST(CONVERT(CHAR(4),GETDATE(),112)+'0101' AS DATETIME),
CAST(YEAR(GETDATE())*10000+10101 AS CHAR(8))
UNION ALL
SELECT DateAdd(d,1,TheDate),NextYear
FROM cte
WHERE DateAdd(d,1,TheDate)<NextYear
)
SELECT Week = DatePart(wk,TheDate),
TheDate
FROM cte
WHERE DateName(dw,TheDate) in ('Saturday')
ORDER BY TheDate
OPTION (MAXRECURSION 366)
with t as
(
select 1 b
union all
select 1 b
union all
select 1 b
union all
select 1 b
union all
select 1 b
union all
select 1 b
union all
select 1 b
union all
select 1 b
)
select * from
(
select
current_timestamp
-datepart(dy,current_timestamp)
+row_number() over (order by t.b) d
from t, t t1, t t2
) tmp
where datepart(yyyy,d)=datepart(yyyy,current_timestamp)
and
DATENAME(dw,d)='sunday'
DECLARE #Year AS INT
SELECT #Year = 2020
;WITH weekends AS (
SELECT DATEFROMPARTS(#Year, 1, 1) AS dt
UNION ALL
SELECT DATEADD(DAY, 1, dt)
FROM weekends
WHERE dt < DATEFROMPARTS(#Year, 12, 31)
)
SELECT dt, DATENAME(MONTH, dt), DATENAME(DW, dt)
FROM weekends
WHERE DATEPART(DW, dt) IN (1, 7)
OPTION(MaxRecursion 366)

Getting Number of weeks in a Month from a Datetime Column

I have a table called FcData and the data looks like:
Op_Date
2011-02-14 11:53:40.000
2011-02-17 16:02:19.000
2010-02-14 12:53:40.000
2010-02-17 14:02:19.000
I am looking to get the Number of weeks in That Month from Op_Date. So I am looking for output like:
Op_Date Number of Weeks
2011-02-14 11:53:40.000 5
2011-02-17 16:02:19.000 5
2010-02-14 12:53:40.000 5
2010-02-17 14:02:19.000 5
This page has some good functions to figure out the last day of any given month: http://www.sql-server-helper.com/functions/get-last-day-of-month.aspx
Just wrap the output of that function with a DATEPART(wk, last_day_of_month) call. Combining it with an equivalent call for the 1st-day-of-week will let you get the number of weeks in that month.
Use this to get the number of week for ONE specific date. Replace GetDate() by your date:
declare #dt date = cast(GetDate() as date);
declare #dtstart date = DATEADD(day, -DATEPART(day, #dt) + 1, #dt);
declare #dtend date = dateadd(DAY, -1, DATEADD(MONTH, 1, #dtstart));
WITH dates AS (
SELECT #dtstart ADate
UNION ALL
SELECT DATEADD(day, 1, t.ADate)
FROM dates t
WHERE DATEADD(day, 1, t.ADate) <= #dtend
)
SELECT top 1 DatePart(WEEKDAY, ADate) weekday, COUNT(*) weeks
FROM dates d
group by DatePart(WEEKDAY, ADate)
order by 2 desc
Explained: the CTE creates a result set with all dates for the month of the given date. Then we query the result set, grouping by week day and count the number of occurrences. The max number will give us how many weeks the month overlaps (premise: if the month has 5 Mondays, it will cover five weeks of the year).
Update
Now, if you have multiple dates, you should tweak accordingly, joining your query with the dates CTE.
Here is my take on it, might have missed something.
In Linq:
from u in TblUsers
let date = u.CreateDate.Value
let firstDay = new DateTime(date.Year, date.Month, 1)
let lastDay = firstDay.AddMonths(1)
where u.CreateDate.HasValue
select Math.Ceiling((lastDay - firstDay).TotalDays / 7)
And generated SQL:
-- Region Parameters
DECLARE #p0 Int = 1
DECLARE #p1 Int = 1
DECLARE #p2 Float = 7
-- EndRegion
SELECT CEILING(((CONVERT(Float,CONVERT(BigInt,(((CONVERT(BigInt,DATEDIFF(DAY, [t3].[value], [t3].[value2]))) * 86400000) + DATEDIFF(MILLISECOND, DATEADD(DAY, DATEDIFF(DAY, [t3].[value], [t3].[value2]), [t3].[value]), [t3].[value2])) * 10000))) / 864000000000) / #p2) AS [value]
FROM (
SELECT [t2].[createDate], [t2].[value], DATEADD(MONTH, #p1, [t2].[value]) AS [value2]
FROM (
SELECT [t1].[createDate], CONVERT(DATETIME, CONVERT(NCHAR(2), DATEPART(Month, [t1].[value])) + ('/' + (CONVERT(NCHAR(2), #p0) + ('/' + CONVERT(NCHAR(4), DATEPART(Year, [t1].[value]))))), 101) AS [value]
FROM (
SELECT [t0].[createDate], [t0].[createDate] AS [value]
FROM [tblUser] AS [t0]
) AS [t1]
) AS [t2]
) AS [t3]
WHERE [t3].[createDate] IS NOT NULL
According to this MSDN article: http://msdn.microsoft.com/en-us/library/ms174420.aspx you can only get the current week in the year, not what that month returns.
There may be various approaches to implementing the idea suggested by #Marc B. Here's one, where no UDFs are used but the first and the last days of month are calculated directly:
WITH SampleData AS (
SELECT CAST('20110214' AS datetime) AS Op_Date
UNION ALL SELECT '20110217'
UNION ALL SELECT '20100214'
UNION ALL SELECT '20100217'
UNION ALL SELECT '20090214'
UNION ALL SELECT '20090217'
),
MonthStarts AS (
SELECT
Op_Date,
MonthStart = DATEADD(DAY, 1 - DAY(Op_Date), Op_Date)
/* alternatively: DATEADD(MONTH, DATEDIFF(MONTH, 0, Op_Date), 0) */
FROM FcData
),
Months AS (
SELECT
Op_Date,
MonthStart,
MonthEnd = DATEADD(DAY, -1, DATEADD(MONTH, 1, MonthStart))
FROM FcData
)
Weeks AS (
SELECT
Op_Date,
StartWeek = DATEPART(WEEK, MonthStart),
EndWeek = DATEPART(WEEK, MonthEnd)
FROM MonthStarts
)
SELECT
Op_Date,
NumberOfWeeks = EndWeek - StartWeek + 1
FROM Weeks
All calculations could be done in one SELECT, but I chose to split them into steps and place every step in a separate CTE so it could be seen better how the end result was obtained.
You can get number of weeks per month using the following method.
Datepart(WEEK,
DATEADD(DAY,
-1,
DATEADD(MONTH,
1,
DATEADD(DAY,
1 - DAY(GETDATE()),
GETDATE())))
-
DATEADD(DAY,
1 - DAY(GETDATE()),
GETDATE())
+1
)
Here how you can get accurate amount of weeks:
DECLARE #date DATETIME
SET #date = GETDATE()
SELECT ROUND(cast(datediff(day, dateadd(day, 1-day(#date), #date), dateadd(month, 1, dateadd(day, 1-day(#date), #date))) AS FLOAT) / 7, 2)
With this code for Sep 2014 you'll get 4.29 which is actually true since there're 4 full weeks and 2 more days.