Subselect inside Case in sql? - sql

I have this pretty code of mine, written by using "if". I want to know if its possible to do just the same thing, using "case". Inside "WeekNumber" are just numbers from 1 to 53.
I want to subselect inside case function
declare #currYear int = datepart(year,getdate());
declare #date date = datefromparts(#currYear,1,1);
--declare #date date = '2022-01-01'
declare #firstDayOfWeekToLast date = DATEADD(day,-datepart(weekday,#date) + 2,#date)
declare #lastDayOfWeekToLast date = DATEADD(day,-datepart(weekday,#date) + 6,#date)
declare #firstDayOfWeekToNew date = DATEADD(day,-datepart(weekday,#date) - 5,#date)
declare #lastDayOfWeekToNew date = DATEADD(day,-datepart(weekday,#date) - 1,#date)
select DATEPART(WEEKDAY,#date)
if(DATEPART(weekday,#date) > 5)
begin
select format(DATEADD(week,WeekNumber,#firstDayOfWeekToLast),'dd.MM.yyyy') as 'First day of Week',
format(DATEADD(week,WeekNumber,#lastDayOfWeekToLast),'dd.MM.yyyy') as 'Last day of Week'
from WEEKNUMBER
end
else if(DATEPART(weekday,#date) = 1)
begin
select format(DATEADD(week,WeekNumber-1,#firstDayOfWeekToLast),'dd.MM.yyyy') as 'First day of Week',
format(DATEADD(week,WeekNumber-1,#lastDayOfWeekToLast),'dd.MM.yyyy') as 'Last day of Week'
from WEEKNUMBER
end
else
begin
select format(DATEADD(week,WeekNumber,#firstDayOfWeekToNew),'dd.MM.yyyy') as 'First day of Week',
format(DATEADD(week,WeekNumber,#lastDayOfWeekToNew),'dd.MM.yyyy') as 'Last day of Week'
from WEEKNUMBER
end

I am not sure if I completely understand your question but you could try the query below.
declare #currYear int = datepart(year,getdate());
declare #date date = datefromparts(#currYear,1,1);
--declare #date date = '2022-01-01'
declare #firstDayOfWeekToLast date = DATEADD(day,-datepart(weekday,#date) + 2,#date)
declare #lastDayOfWeekToLast date = DATEADD(day,-datepart(weekday,#date) + 6,#date)
declare #firstDayOfWeekToNew date = DATEADD(day,-datepart(weekday,#date) - 5,#date)
declare #lastDayOfWeekToNew date = DATEADD(day,-datepart(weekday,#date) - 1,#date)
--The changes I made start below.
SELECT
WEEKNUMBER,
CASE
WHEN (DATEPART(weekday,#date) > 5) THEN format(DATEADD(week,WeekNumber,#firstDayOfWeekToLast),'dd.MM.yyyy')
WHEN (DATEPART(weekday,#date) = 1) THEN format(DATEADD(week,WeekNumber-1,#firstDayOfWeekToLast),'dd.MM.yyyy')
ELSE format(DATEADD(week,WeekNumber,#firstDayOfWeekToNew),'dd.MM.yyyy')
END 'First day of Week',
CASE
WHEN (DATEPART(weekday,#date) > 5) THEN format(DATEADD(week,WeekNumber,#lastDayOfWeekToLast),'dd.MM.yyyy')
WHEN (DATEPART(weekday,#date) = 1) THEN format(DATEADD(week,WeekNumber-1,#lastDayOfWeekToLast),'dd.MM.yyyy')
ELSE format(DATEADD(week,WeekNumber,#lastDayOfWeekToNew),'dd.MM.yyyy')
END 'Last day of Week'
FROM WEEKNUMBER

Related

Dynamically extract data for previous month

I want to generate data every month for the previous month.
set (startdate, enddate) = ('2021-02-01', '2021-02-28');
Instead of manually inserting the date every month as in the above code, I want the 'startdate' variable to automatically pick the start date of previous month and the 'enddate' variable to pick the last date of previous month.
How to do that using sql?
If you want the previous month relative to the current date, you can just put it into a where clause:
where datecol < date_trunc('month', current_date) and
datecol >= date_trunc('month', current_date) - interval '1 month'
Note that this is safer than your code, because it works when the column has a time component.
You could put this into variables. I'm not sure that is necessary.
If you wanted this as variables, you could use:
(date_trunc('month', current_date) - interval '1 month',
last_day(date_trunc('month', current_date) - interval '1 month')
)
Is this what you're after ?
select
current_date() today
, date_trunc(month,add_months(today,-1)) first_day_last_month
, last_day ( first_day_last_month) last_day_last_month
In instances where your version of SQL doesn't support the date_trunc() function, you can use something like this:
declare
#year varchar(10) = YEAR(GETDATE()),
#month varchar(10) = MONTH(GETDATE()),
#day varchar(10) = DAY(getdate()),
#beginyear varchar(10) = YEAR(GETDATE()),
#beginmonth varchar(10) = MONTH(GETDATE()),
#begindate date,
#enddate date
if #month = 1
begin
set #beginyear = #year - 1
set #beginmonth = 12
end
if #month <> 1
begin
set #beginmonth = #month - 1
end
set #begindate = (select #beginyear + '-' + #beginmonth + '-' + '1')
set #enddate = (select #year + '-' + #month + '-' + '1')
Select [your data] from table where [date] between #begindate and #enddate

Getting number of days for a specific month and year between two dates SQL

I want to retrieve the number of days between two dates that overlap a specific month.
For Example :
Month = 1
Year = 2020
StartDate ='2019-11-12'
ENDDate ='2020-1-13'
Result = 13 days
13 because there are 13 days between the dates that are in the selected month: January 2020
Other Example:
Month=9
Year =2019
StartDate = '2019-8-13'
ENDDate ='2020-1-1'
Result = 30 days
30 because there are 30 days between the dates that are in the selected month: September 2019
The generic formula for the number of overlapping days in two ranges is
MAX(MIN(end1, end2) - MAX(start1, start2) + 1, 0)
In your case you have one set of Start and End dates, you must construct the other from the given month and year using datefromparts and eomonth.
Unfortunately SQL Server doesn't support LEAST and GREATEST formulas as do MySQL and Oracle, so this is a bit painful to implement. Here's an example using variables:
declare #month int;
declare #year int;
declare #startDate date;
declare #endDate date;
declare #startOfMonth date;
declare #endOfMonth date;
declare #minEnd date;
declare #maxStart date;
set #month = 1;
set #year = 2020;
set #startDate = '2019-11-12';
set #endDate = '2020-01-13';
set #startOfMonth = datefromparts(#year, #month, 1)
set #endOfMonth = eomonth(#startOfMonth)
set #minEnd = case when #endDate < #endOfMonth then #endDate
else #endOfMonth
end;
set #maxStart = case when #startDate < #startOfMonth then #startOfMonth
else #startDate
end;
select case when datediff(day, #maxStart, #minEnd) + 1 < 0 then 0
else datediff(day, #maxStart, #minEnd) + 1
end as days_in_month
Output:
13
Demo on dbfiddle; this includes other sample date ranges.
You could implement something similar using a series of CTEs if the values are derived from a table.

Datepart query shows value 1 for saturday

The following is my stored procedure for setting workingday between two dates
Create procedure [dbo].[sp_workingdays](#startdate date,#enddate date,#createddatetime datetime,#adminid int)
as
declare #start date,#end date
declare #day varchar(50)
declare #timeid int
declare #daypare int
declare #workingdaytype varchar(20)
begin
set #start=#startdate
set #end=#enddate
while (#start<=#end)
begin
if #start not in (select Date from Generalholyday_details)
begin
select #day= DATENAME(dw,#start)
select #workingdaytype =case (DATEPART(DW,#start)+##DATEFIRST)%7 when 1 then 'Leave Day' when 2 then 'Full Day' when 3 then 'Full Day' when 4 then 'Full Day'when 5 then 'Full Day' when 6 then 'Full Day' when 0 then 'Half Day' end
select #timeid=Time_id from Workingdaytimesetting_details where Workingday_type=#workingdaytype
insert into Workingday_details(Working_date,working_day,Time_id) values(#start,#day,#timeid)
update Workingday_details set createddatetime=#createddatetime where createddatetime is null
update Workingday_details set adminid=#adminid where adminid is null
end
set #start=DATEADD(day,1,#start)
end
end
GO
In datepart line 1 is for sunday. but actually when i run the stored procedure, i got 1 for Saturday. how can i set 1 for sunday.In my previous system i got 1 for sunday in same procedure.
Have a look at SET DATEFIRST (Transact-SQL)
Sets the first day of the week to a number from 1 through 7.
To see the current setting of SET DATEFIRST, use the ##DATEFIRST
function.
The setting of SET DATEFIRST is set at execute or run time and not at
parse time.
Specifying SET DATEFIRST has no effect on DATEDIFF. DATEDIFF always
uses Sunday as the first day of the week to ensure the function is
deterministic.
Try this one -
SET DATEFIRST 7
DATEFIRST - MSDN
Also try this query after small refactor:
CREATE PROCEDURE [dbo].[sp_workingdays]
(
#startdate DATE
, #enddate DATE
, #createddatetime DATETIME
, #adminid INT
)
AS BEGIN
DECLARE
#start DATE
, #end DATE
, #day VARCHAR(50)
, #timeid INT
, #workingdaytype VARCHAR(20)
SELECT
#start = #startdate
, #end = #enddate
WHILE (#start <= #end) BEGIN
IF NOT EXISTS(
SELECT 1
FROM Generalholyday_details
WHERE #start = [Date]
) BEGIN
SELECT
#day = DATENAME(dw, #start)
, #workingdaytype =
CASE WHEN dt = 1 THEN 'Leave Day'
WHEN dt IN (2,3,4,5,6) THEN 'Full Day'
ELSE 'Half Day'
END
FROM (
SELECT dt = (DATEPART(DW, #start) + ##DATEFIRST) % 7
) t
SELECT #timeid = Time_id
FROM Workingdaytimesetting_details
WHERE Workingday_type = #workingdaytype
INSERT INTO Workingday_details (Working_date, working_day, Time_id)
VALUES (#start, #day, #timeid)
UPDATE Workingday_details
SET createddatetime = #createddatetime
WHERE createddatetime IS NULL
UPDATE Workingday_details
SET adminid = #adminid
WHERE adminid IS NULL
END
SET #start = DATEADD(DAY, 1, #start)
END
END
GO

SQL Nth Day of Nth Week of a Month

I want to use the following function for scheduling club meetings which occur on a monthly basis based on the week and weekday of the month. In the example below I have a (to be) function that returns the Third Wednesday of the month. If that day occurs in the past then it returns the next month's 3rd Wednesday.
I want to get away from the Loops and I feel that there is a better method for calculation. Is there a more OO process? Your opinion?
--CREATE FUNCTION NextWeekDayofMonth
DECLARE
--(
#WEEK INT,
#WEEKDAY INT,
#REFERENCEDATE DATETIME
--)
--RETURNS DATETIME
--AS
-------------------------------
--Values for testing - Third Wednesday of the Month
set #WEEK = 3 --Third Week
set #WEEKDAY = 4 --Wednesday
set #REFERENCEDATE = '08/20/2011'
-------------------------------
BEGIN
DECLARE #WEEKSEARCH INT
DECLARE #FDOM DATETIME
DECLARE #RETURNDATE DATETIME
SET #FDOM = DATEADD(M,DATEDIFF(M,0,#REFERENCEDATE),0)
SET #RETURNDATE = DATEADD(M,0,#FDOM)
WHILE (#RETURNDATE < #REFERENCEDATE)
--If the calculated date occurs in the past then it
--finds the appropriate date in the next month
BEGIN
SET #WEEKSEARCH = 1
SET #RETURNDATE = #FDOM
--Finds the first weekday of the month that matches the provided weekday value
WHILE ( DATEPART(DW,#RETURNDATE) <> #WEEKDAY)
BEGIN
SET #RETURNDATE = DATEADD(D,1,#RETURNDATE)
END
--Iterates through the weeks without going into next month
WHILE #WEEKSEARCH < #WEEK
BEGIN
IF MONTH(DATEADD(WK,1,#RETURNDATE)) = MONTH(#FDOM)
BEGIN
SET #RETURNDATE = DATEADD(WK,1,#RETURNDATE)
SET #WEEKSEARCH = #WEEKSEARCH+1
END
ELSE
BREAK
END
SET #FDOM = DATEADD(M,1,#FDOM)
END
--RETURN #RETURNDATE
select #ReturnDate
END
IMO, the best process is to store important business information as rows in tables in a database. If you build a calendar table, you can get all the third Wednesdays by a simple query. Not only are the queries simple, they can be seen to be obviously correct.
select cal_date
from calendar
where day_of_week_ordinal = 3
and day_of_week = 'Wed';
The third Wednesday that's on or after today is also simple.
select min(cal_date)
from calendar
where day_of_week_ordinal = 3
and day_of_week = 'Wed'
and cal_date >= CURRENT_DATE;
Creating a calendar table is straightforward. This was written for PostgreSQL, but it's entirely standard SQL (I think) except for the columns relating to ISO years and ISO weeks.
create table calendar (
cal_date date primary key,
year_of_date integer not null
check (year_of_date = extract(year from cal_date)),
month_of_year integer not null
check (month_of_year = extract(month from cal_date)),
day_of_month integer not null
check (day_of_month = extract(day from cal_date)),
day_of_week char(3) not null
check (day_of_week =
case when extract(dow from cal_date) = 0 then 'Sun'
when extract(dow from cal_date) = 1 then 'Mon'
when extract(dow from cal_date) = 2 then 'Tue'
when extract(dow from cal_date) = 3 then 'Wed'
when extract(dow from cal_date) = 4 then 'Thu'
when extract(dow from cal_date) = 5 then 'Fri'
when extract(dow from cal_date) = 6 then 'Sat'
end),
day_of_week_ordinal integer not null
check (day_of_week_ordinal =
case
when day_of_month >= 1 and day_of_month <= 7 then 1
when day_of_month >= 8 and day_of_month <= 14 then 2
when day_of_month >= 15 and day_of_month <= 21 then 3
when day_of_month >= 22 and day_of_month <= 28 then 4
else 5
end),
iso_year integer not null
check (iso_year = extract(isoyear from cal_date)),
iso_week integer not null
check (iso_week = extract(week from cal_date))
);
You can populate that table with a spreadsheet or with a UDF. Spreadsheets usually have pretty good date and time functions. I have a UDF, but it's written for PostgreSQL (PL/PGSQL), so I'm not sure how much it would help you. But I'll post it later if you like.
Here's a date math way to accomplish what you want without looping:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Description: Gets the nth occurrence of a given weekday in the month containing the specified date.
-- For #dayOfWeek, 1 = Sunday, 2 = Monday, 3 = Tuesday, 4 = Wednesday, 5 = Thursday, 6 = Friday, 7 = Saturday
-- =============================================
CREATE FUNCTION GetWeekdayInMonth
(
#date datetime,
#dayOfWeek int,
#nthWeekdayInMonth int
)
RETURNS datetime
AS
BEGIN
DECLARE #beginMonth datetime
DECLARE #offSet int
DECLARE #firstWeekdayOfMonth datetime
DECLARE #result datetime
SET #beginMonth = DATEADD(DAY, -DATEPART(DAY, #date) + 1, #date)
SET #offSet = #dayOfWeek - DATEPART(dw, #beginMonth)
IF (#offSet < 0)
BEGIN
SET #firstWeekdayOfMonth = DATEADD(d, 7 + #offSet, #beginMonth)
END
ELSE
BEGIN
SET #firstWeekdayOfMonth = DATEADD(d, #offSet, #beginMonth)
END
SET #result = DATEADD(WEEK, #nthWeekdayInMonth - 1, #firstWeekdayOfMonth)
IF (NOT(MONTH(#beginMonth) = MONTH(#result)))
BEGIN
SET #result = NULL
END
RETURN #result
END
GO
DECLARE #nextMeetingDate datetime
SET #nextMeetingDate = dbo.GetWeekdayInMonth(GETDATE(), 4, 3)
IF (#nextMeetingDate IS NULL OR #nextMeetingDate < GETDATE())
BEGIN
SET #nextMeetingDate = dbo.GetWeekDayInMonth(DATEADD(MONTH, 1, GETDATE()), 4, 3)
END
SELECT #nextMeetingDate
Here's another function based solution using date math that returns the Next Nth Weekday on or after a given date. It doesn't use any looping to speak of, but it may recurs by at most one iteration if the next Nth weekday is in the next month.
This function takes the DATEFIRST setting into account for environments that use a value other than the default.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: David Grimberg
-- Create date: 2015-06-18
-- Description: Gets the next Nth weekday
-- #param Date is any date in a month
-- #param DayOfWeek is the weekday of interest ranging
-- from 1 to 7 with ##DATEFIRST being the
-- first day of the week
-- #param NthWeekday represents which ordinal weekday to return.
-- Positive values return dates relative to the start
-- of the month. Negative values return dates relative
-- to the end of the month. Values > 4 indicate the
-- last week, values < -4 indicate the first week.
-- Zero is assumed to be 1.
-- =============================================
ALTER FUNCTION dbo.xxGetNextNthWeekday
(
#Date date,
#NthWeekday smallint,
#DayOfWeek tinyint
)
RETURNS date
AS
BEGIN
DECLARE #FirstOfMonth date
DECLARE #inc int
DECLARE #Result date
-- Clamp the #NthWeekday input to valid values
set #NthWeekday = case when #NthWeekday = 0 then 1
when #NthWeekday > 4 then -1
when #NthWeekday < -4 then 1
else #NthWeekday
end
-- Normalize the requested day of week taking
-- ##DATEFIRST into consideration.
set #DayOfWeek = (##DATEFIRST + 6 + #DayOfWeek) % 7 + 1
-- Gets the first of the current month or the
-- next month if #NthWeekday is negative.
set #FirstOfMonth = dateadd(month, datediff(month,0,#Date)
+ case when #NthWeekday < 0 then 1 else 0 end
, 0)
-- Add and/or subtract 1 week depending direction of search and the
-- relationship of #FirstOfMonth's Day of the Week to the #DayOfWeek
-- of interest
set #inc = case when (datepart(WEEKDAY, #FirstOfMonth)+##DATEFIRST-1)%7+1 > #DayOfWeek
then 0
else -1
end
+ case when #NthWeekday < 0 then 1 else 0 end
-- Put it all together
set #Result = dateadd( day
, #DayOfWeek-1
, dateadd( WEEK
, #NthWeekday + #inc
, dateadd( WEEK -- Gets 1st Sunday on or
, datediff(WEEK, -1, #FirstOfMonth)
,-1 ) ) ) -- before #FirstOfMonth
-- [Snip here] --
if #Result < #Date
set #Result = dbo.xxGetNextNthWeekday( dateadd(month, datediff(month, 0, #Date)+1, 0)
, #NthWeekday, #DayOfWeek)
-- [to here for no recursion] --
Return #Result
END
If you want the past or future Nth weekday of the current month based on the #Date parameter rather than the next Nth weekday snip out the recursive part as indicated above.

How to determine the number of days in a month in SQL Server?

I need to determine the number of days in a month for a given date in SQL Server.
Is there a built-in function? If not, what should I use as the user-defined function?
In SQL Server 2012 you can use EOMONTH (Transact-SQL) to get the last day of the month and then you can use DAY (Transact-SQL) to get the number of days in the month.
DECLARE #ADate DATETIME
SET #ADate = GETDATE()
SELECT DAY(EOMONTH(#ADate)) AS DaysInMonth
You can use the following with the first day of the specified month:
datediff(day, #date, dateadd(month, 1, #date))
To make it work for every date:
datediff(day, dateadd(day, 1-day(#date), #date),
dateadd(month, 1, dateadd(day, 1-day(#date), #date)))
Most elegant solution: works for any #DATE
DAY(DATEADD(DD,-1,DATEADD(MM,DATEDIFF(MM,-1,#DATE),0)))
Throw it in a function or just use it inline. This answers the original question without all the extra junk in the other answers.
examples for dates from other answers:
SELECT DAY(DATEADD(DD,-1,DATEADD(MM,DATEDIFF(MM,-1,'1/31/2009'),0))) Returns 31
SELECT DAY(DATEADD(DD,-1,DATEADD(MM,DATEDIFF(MM,-1,'2404-feb-15'),0))) Returns 29
SELECT DAY(DATEADD(DD,-1,DATEADD(MM,DATEDIFF(MM,-1,'2011-12-22'),0))) Returns 31
--Last Day of Previous Month
SELECT DATEPART(day, DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE()),0)))
--Last Day of Current Month
SELECT DATEPART(day, DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE())+1,0)))
--Last Day of Next Month
SELECT DATEPART(day, DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE())+2,0)))
Personally though, I would make a UDF for it if there is not a built in function...
I would suggest:
SELECT DAY(EOMONTH(GETDATE()))
This code gets you the number of days in current month:
SELECT datediff(dd,getdate(),dateadd(mm,1,getdate())) as datas
Change getdate() to the date you need to count days for.
--- sql server below 2012---
select day( dateadd(day,-1,dateadd(month, 1, convert(date,'2019-03-01'))))
-- this for sql server 2012--
select day(EOMONTH(getdate()))
Solution 1: Find the number of days in whatever month we're currently in
DECLARE #dt datetime
SET #dt = getdate()
SELECT #dt AS [DateTime],
DAY(DATEADD(mm, DATEDIFF(mm, -1, #dt), -1)) AS [Days in Month]
Solution 2: Find the number of days in a given month-year combo
DECLARE #y int, #m int
SET #y = 2012
SET #m = 2
SELECT #y AS [Year],
#m AS [Month],
DATEDIFF(DAY,
DATEADD(DAY, 0, DATEADD(m, ((#y - 1900) * 12) + #m - 1, 0)),
DATEADD(DAY, 0, DATEADD(m, ((#y - 1900) * 12) + #m, 0))
) AS [Days in Month]
You do need to add a function, but it's a simple one. I use this:
CREATE FUNCTION [dbo].[ufn_GetDaysInMonth] ( #pDate DATETIME )
RETURNS INT
AS
BEGIN
SET #pDate = CONVERT(VARCHAR(10), #pDate, 101)
SET #pDate = #pDate - DAY(#pDate) + 1
RETURN DATEDIFF(DD, #pDate, DATEADD(MM, 1, #pDate))
END
GO
SELECT Datediff(day,
(Convert(DateTime,Convert(varchar(2),Month(getdate()))+'/01/'+Convert(varchar(4),Year(getdate())))),
(Convert(DateTime,Convert(varchar(2),Month(getdate())+1)+'/01/'+Convert(varchar(4),Year(getdate()))))) as [No.of Days in a Month]
select datediff(day,
dateadd(day, 0, dateadd(month, ((2013 - 1900) * 12) + 3 - 1, 0)),
dateadd(day, 0, dateadd(month, ((2013 - 1900) * 12) + 3, 0))
)
Nice Simple and does not require creating any functions Work Fine
You need to create a function, but it is for your own convenience. It works perfect and I never encountered any faulty computations using this function.
CREATE FUNCTION [dbo].[get_days](#date datetime)
RETURNS int
AS
BEGIN
SET #date = DATEADD(MONTH, 1, #date)
DECLARE #result int = (select DAY(DATEADD(DAY, -DAY(#date), #date)))
RETURN #result
END
How it works: subtracting the date's day number from the date itself gives you the last day of previous month. So, you need to add one month to the given date, subtract the day number and get the day component of the result.
select add_months(trunc(sysdate,'MM'),1) - trunc(sysdate,'MM') from dual;
I upvoted Mehrdad, but this works as well. :)
CREATE function dbo.IsLeapYear
(
#TestYear int
)
RETURNS bit
AS
BEGIN
declare #Result bit
set #Result =
cast(
case when ((#TestYear % 4 = 0) and (#testYear % 100 != 0)) or (#TestYear % 400 = 0)
then 1
else 0
end
as bit )
return #Result
END
GO
CREATE FUNCTION dbo.GetDaysInMonth
(
#TestDT datetime
)
RETURNS INT
AS
BEGIN
DECLARE #Result int
DECLARE #MonthNo int
Set #MonthNo = datepart(m,#TestDT)
Set #Result =
case #MonthNo
when 1 then 31
when 2 then
case
when dbo.IsLeapYear(datepart(yyyy,#TestDT)) = 0
then 28
else 29
end
when 3 then 31
when 4 then 30
when 5 then 31
when 6 then 30
when 7 then 31
when 8 then 31
when 9 then 30
when 10 then 31
when 11 then 30
when 12 then 31
end
RETURN #Result
END
GO
To Test
declare #testDT datetime;
set #testDT = '2404-feb-15';
select dbo.GetDaysInMonth(#testDT)
here's another one...
Select Day(DateAdd(day, -Day(DateAdd(month, 1, getdate())),
DateAdd(month, 1, getdate())))
I know this question is old but I thought I would share what I'm using.
DECLARE #date date = '2011-12-22'
/* FindFirstDayOfMonth - Find the first date of any month */
-- Replace the day part with -01
DECLARE #firstDayOfMonth date = CAST( CAST(YEAR(#date) AS varchar(4)) + '-' +
CAST(MONTH(#date) AS varchar(2)) + '-01' AS date)
SELECT #firstDayOfMonth
and
DECLARE #date date = '2011-12-22'
/* FindLastDayOfMonth - Find what is the last day of a month - Leap year is handled by DATEADD */
-- Get the first day of next month and remove a day from it using DATEADD
DECLARE #lastDayOfMonth date = CAST( DATEADD(dd, -1, DATEADD(mm, 1, FindFirstDayOfMonth(#date))) AS date)
SELECT #lastDayOfMonth
Those could be combine to create a single function to retrieve the number of days in a month if needed.
SELECT DAY(SUBDATE(ADDDATE(CONCAT(YEAR(NOW()), '-', MONTH(NOW()), '-1'), INTERVAL 1 MONTH), INTERVAL 1 DAY))
Nice 'n' Simple and does not require creating any functions
Mehrdad Afshari reply is most accurate one, apart from usual this answer is based on formal mathematical approach given by Curtis McEnroe in his blog https://cmcenroe.me/2014/12/05/days-in-month-formula.html
DECLARE #date DATE= '2015-02-01'
DECLARE #monthNumber TINYINT
DECLARE #dayCount TINYINT
SET #monthNumber = DATEPART(MONTH,#date )
SET #dayCount = 28 + (#monthNumber + floor(#monthNumber/8)) % 2 + 2 % #monthNumber + 2 * floor(1/#monthNumber)
SELECT #dayCount + CASE WHEN #dayCount = 28 AND DATEPART(YEAR,#date)%4 =0 THEN 1 ELSE 0 END -- leap year adjustment
To get the no. of days in a month we can directly use Day() available in SQL.
Follow the link posted at the end of my answer for SQL Server 2005 / 2008.
The following example and the result are from SQL 2012
alter function dbo.[daysinm]
(
#dates nvarchar(12)
)
returns int
as
begin
Declare #dates2 nvarchar(12)
Declare #days int
begin
select #dates2 = (select DAY(EOMONTH(convert(datetime,#dates,103))))
set #days = convert(int,#dates2)
end
return #days
end
--select dbo.daysinm('08/12/2016')
Result in SQL Server SSMS
(no column name)
1 31
Process:
When EOMONTH is used, whichever the date format we use it is converted into DateTime format of SQL-server. Then the date output of EOMONTH() will be 2016-12-31 having 2016 as Year, 12 as Month and 31 as Days.
This output when passed into Day() it gives you the total days count in the month.
If we want to get the instant result for checking we can directly run the below code,
select DAY(EOMONTH(convert(datetime,'08/12/2016',103)))
or
select DAY(EOMONTH(convert(datetime,getdate(),103)))
for reference to work in SQL Server 2005/2008/2012, please follow the following external link ...
Find No. of Days in a Month in SQL
DECLARE #date DATETIME = GETDATE(); --or '12/1/2018' (month/day/year)
SELECT DAY(EOMONTH ( #date )) AS 'This Month';
SELECT DAY(EOMONTH ( #date, 1 )) AS 'Next Month';
result:
This Month
31
Next Month
30
DECLARE #m int
SET #m = 2
SELECT
#m AS [Month],
DATEDIFF(DAY,
DATEADD(DAY, 0, DATEADD(m, +#m -1, 0)),
DATEADD(DAY, 0, DATEADD(m,+ #m, 0))
) AS [Days in Month]
RETURN day(dateadd(month, 12 * #year + #month - 22800, -1))
select day(dateadd(month, 12 * year(date) + month(date) - 22800, -1))
A cleaner way of implementing this is using the datefromparts function to construct the first day of the month, and calculate the days from there.
CREATE FUNCTION [dbo].[fn_DaysInMonth]
(
#year INT,
#month INT
)
RETURNS INT
AS
BEGIN
IF #month < 1 OR #month > 12 RETURN NULL;
IF #year < 1753 OR #year > 9998 RETURN NULL;
DECLARE #firstDay DATE = datefromparts(#year, #month, 1);
DECLARE #lastDay DATE = dateadd(month, 1, #firstDay);
RETURN datediff(day, #firstDay, #lastDay);
END
GO
Similarily, you can calculate the days in a year:
CREATE FUNCTION [dbo].[fn_DaysInYear]
(
#year INT
)
RETURNS INT
AS
BEGIN
IF #year < 1753 OR #year > 9998 RETURN NULL;
DECLARE #firstDay DATE = datefromparts(#year, 1, 1);
DECLARE #lastDay DATE = dateadd(year, 1, #firstDay);
RETURN datediff(day, #firstDay, #lastDay);
END
GO
use SQL Server EOMONTH Function nested with day to get last day of month
select Day(EOMONTH('2020-02-1')) -- Leap Year returns 29
select Day(EOMONTH('2021-02-1')) -- returns 28
select Day(EOMONTH('2021-03-1')) -- returns 31
For any date
select DateDiff(Day,#date,DateAdd(month,1,#date))
select first_day=dateadd(dd,-1*datepart(dd,getdate())+1,getdate()),
last_day=dateadd(dd,-1*datepart(dd,dateadd(mm,1,getdate())),dateadd(mm,1,getdate())),
no_of_days = 1+datediff(dd,dateadd(dd,-1*datepart(dd,getdate())+1,getdate()),dateadd(dd,-1*datepart(dd,dateadd(mm,1,getdate())),dateadd(mm,1,getdate())))
replace any date with getdate to get the no of months in that particular date
DECLARE #Month INT=2,
#Year INT=1989
DECLARE #date DateTime=null
SET #date=CAST(CAST(#Year AS nvarchar) + '-' + CAST(#Month AS nvarchar) + '-' + '1' AS DATETIME);
DECLARE #noofDays TINYINT
DECLARE #CountForDate TINYINT
SET #noofDays = DATEPART(MONTH,#date )
SET #CountForDate = 28 + (#noofDays + floor(#noofDays/8)) % 2 + 2 % #noofDays + 2 * floor(1/#noofDays)
SET #noofDays= #CountForDate + CASE WHEN #CountForDate = 28 AND DATEPART(YEAR,#date)%4 =0 THEN 1 ELSE 0 END
PRINT #noofDays
DECLARE #date nvarchar(20)
SET #date ='2012-02-09 00:00:00'
SELECT DATEDIFF(day,cast(replace(cast(YEAR(#date) as char)+'-'+cast(MONTH(#date) as char)+'-01',' ','')+' 00:00:00' as datetime),dateadd(month,1,cast(replace(cast(YEAR(#date) as char)+'-'+cast(MONTH(#date) as char)+'-01',' ','')+' 00:00:00' as datetime)))
simple query in SQLServer2012 :
select day(('20-05-1951 22:00:00'))
i tested for many dates and it return always a correct result