SQL Server Function Fails, logic seems good - sql-server

This SQL Function returns 0 no matter what the input, where did I screw up ?
The idea is to return a string or a date indicating the last day of February with a four digit year as input
CREATE FUNCTION [dbo].[LastDayOfFeb]
----------------------------------------------------------------------------------
--This returns the last day of February by figuring out when leap year occurs
--Leap years are those years that are evenly divisible by 4, except for
--centennial years (those ending in -00), which receive the extra
--day only if they are evenly divisible by 400
-- Input SMALLINT , Output DATE
----------------------------------------------------------------------------------
(#Year SMALLINT)
returns VARCHAR
AS
BEGIN
set #year = cast(#year as smallint)
--1. ______________Not a multiple of 4 -------------------------> NO
IF #Year % 4 <> 0
RETURN '0228' + Cast(#YEAR AS VARCHAR)
--2. ______________A multiple of 4 but NOT Centennial ----------> YES
IF #Year % 4 <> 0
RETURN '0229' + Cast(#YEAR AS VARCHAR)
--3. ______________A Centennial and a multiple of 400 ----------> YES
IF #Year % 400 = 0
RETURN '0229' + Cast(#YEAR AS VARCHAR)
--4. ______________A Centennial but NOT a multiple of 400 ------> NO
RETURN '0228' + Cast(#YEAR AS VARCHAR)
END
GO

Try replacing RETURN VARCHAR with RETURN VARCHAR(10). By not specifying the size of the return string, it is assuming a length of 1, which is why you only get the leading '0'.

try
declare #year int = 2005
declare #date = dateadd(year, #year - 1900, '19000101')
select #date = dateadd(month, 2, #date)
select #date = dateadd(day, -1, #date)
select #date
rather then using strings.
as a function this would be
CREATE FUNCTION [dbo].[LastDayOfFeb]
(#year SMALLINT)
RETURNS DATE
AS
BEGIN
RETURN dateadd(day, -1,
dateadd(month, 2,
dateadd(year, #year - 1900, 0)))
END
an example of usage / test
WITH cte AS (
SELECT year = 2000, last_day_of_feb = dbo.LastDayOfFeb(2000)
UNION ALL
SELECT year + 1, dbo.LastDayOfFeb(year + 1)
FROM cte
WHERE year + 1 <= 2040
)
SELECT *
FROM cte
SQL Fiddle

Related

Calculating age from SSN

I'm working with a project in SSRS
In Database i have a column called X and in this column , i have Social Security Numbers for all employees and all numbers look like this with out any ( - or /) example 1111111111 (DDMMYYXXXX).
My question is ,how can i write a sql to just select 6 first number and then minus current time and in end give me age of employees. Can someone please point me in the right direction.
Thanks.
So far the sql i wrote look like this:
create function dbo.birthdate_from_cpr(#cpr varchar(10))
returns date
as
begin
declare #year char(2) = substring(#cpr, 5, 2),
#month char(2) = substring(#cpr, 3, 2),
#day char(2) = substring(#cpr, 1, 2),
#century char(2)
if right(datepart(yy, getdate()), 2) < #year
set #century = left(datepart(yy, getdate()) - 100, 2)
else
set #century = left(datepart(yy, getdate()), 2)
return convert(date, #century + #year + #month + #day, 120)
end
go
select dbo.birthdate_from_cpr('1312761234'),
dbo.birthdate_from_cpr('0101041234'),
age = datediff(yy, dbo.birthdate_from_cpr('1312761234'), getdate())
One way is to use left and stuff to create a well-formatted string, and convert to change it to a date value, and then it's just datediff.
Don't be alarmed by the length of the query, It's only the last column you need. I've chosen to show every step in a different column.
DECLARE #SSN char(10) = '1309761234'
SELECT #SSN as OriginalString,
STUFF(
STUFF(LEFT(#SSN, 6), 3, 0, '.')
, 6, 0, '.') As DateString,
CONVERT(date,
STUFF(
STUFF(LEFT(#SSN, 6), 3, 0, '.')
, 6, 0, '.')
, 4) As Date, -- German, no century - dd.mm.yy
DATEDIFF(YEAR,
CONVERT(date,
STUFF(LEFT(#SSN, 4), 3, 0, '.') +'.'+
CAST(DATEPART(YEAR, GETDATE()) / 100 - 1 as char(2)) +
SUBSTRING(#SSN, 5, 2)
, 104)
, GETDATE()) As Age
Result:
OriginalString DateString Date Age
1309761234 13.09.76 13.09.1976 00:00:00 41
And with your query:
SELECT Users.Id, Users.FirstName + ' ' + Users.LastName AS Medarbajder,
Users.SSN AS CPRNR,
CASE WHEN Users.SSN IS NOT NULL THEN
DATEDIFF(YEAR,
CONVERT(date,
STUFF(LEFT(Users.SSN, 4), 3, 0, '.') +'.'+
CAST(DATEPART(YEAR, GETDATE()) / 100 - 1 as char(2)) +
SUBSTRING(Users.SSN, 5, 2)
, 104)
, GETDATE())
ELSE
NULL
END As Age,
convert(varchar(10), Paychecks.WorkStartDate, 105) AS StartDato ,
Paychecks.DepartmentName AS Afdelinger
FROM dbo.Paychecks, dbo.Users
WHERE Users.CustomerId=214 AND Users.Id=Paychecks.UserId order by Users.FirstName;
You need to extract the date from the ssn column to calculate the age, assuming your described format "1111111111 (DDMMYYXXXX)". However the format string DDMMYY won't easily convert by itself so we need to flip it around into a format the CONVERT function will recognise
Something like this:
convert(date, substring(Users.SSN , 17, 2) + substring(Users.SSN , 15, 2) + substring(Users.SSN , 13, 2), 12)
From there its a simple matter to DATEDIFF the age.
Be aware that SQL Server will treat the years 00 to 49 as this century. Which might be an issue for older folk...
I'd recommend creating a UDF for converting the CPR to a date which will make your life easier with doing analysis in the future and you test it more easily. This version addresses the century issue that #paul-bambury mentioned by assuming nobody is more than 100 years old.
create function dbo.birthdate_from_cpr(#cpr varchar(10))
returns date
as
begin
declare #year char(2) = substring(#cpr, 5, 2),
#month char(2) = substring(#cpr, 3, 2),
#day char(2) = substring(#cpr, 1, 2),
#century char(2)
-- if the current 2 digit year is less than the birthday year, assume it was last century
-- e.g. 76 should be 1976 but 02 should be 2002
if right(datepart(yy, getdate()), 2) < #year
set #century = left(datepart(yy, getdate()) - 100, 2)
else
set #century = left(datepart(yy, getdate()), 2)
return convert(date, #century + #year + #month + #day, 120)
end
go
select dbo.birthdate_from_cpr('1312761234'),
dbo.birthdate_from_cpr('0101041234'),
age = datediff(yy, dbo.birthdate_from_cpr('1312761234'), getdate())

Calculate financial year start and end date based on year entered SQL Server and SSRS

I have report, which takes YEAR as one parameter and I wanted to calculate the start and end of the financial year. Here is how I'm trying:
CREATE PROCEDURE [dbo].[sp_name]
#StartDate as datetime,
#Enddate as datetime,
#year as varchar(10)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
#StartDate = year(dateadd(q, -1, cast(cast(#year AS char) + '/01/' + cast(#year AS char) AS datetime))) = #year
Is this the correct way to do this?
I need financial start date as 1-July-2014 to 30-June-2015, if year entered as 2015.Please note that, this I need internally to be calculated in script. If I'm doing something wrong, how can I correct this to get desired results?
Using DATEADD and DATEDIFF you can computer for your fiscal years:
DECLARE #year INT = 2015
SELECT
start_date = DATEADD(MONTH, 6, DATEADD(YEAR, DATEDIFF(YEAR, 0, DATEADD(YEAR, #year - 1900, 0)) - 1, 0)),
end_date = DATEADD(DAY, -1, DATEADD(MONTH, 6, DATEADD(YEAR, DATEDIFF(YEAR, 0, DATEADD(YEAR, #year - 1900, 0)), 0)))
Read here for more common date routines.
To use this in a stored procedure:
CREATE PROCEDURE procedure_name
#year AS INT
AS
BEGIN
SET NOCOUNT ON
SELECT
start_date = DATEADD(MONTH, 6, DATEADD(YEAR, DATEDIFF(YEAR, 0, DATEADD(YEAR, #year - 1900, 0)) - 1, 0)),
end_date = DATEADD(DAY, -1, DATEADD(MONTH, 6, DATEADD(YEAR, DATEDIFF(YEAR, 0, DATEADD(YEAR, #year - 1900, 0)), 0)))
END
For SQL server 2012+ versions, you can use DATEFROMPARTS
https://msdn.microsoft.com/en-IN/library/hh213228.aspx
CREATE PROCEDURE [dbo].[usp_name]
#StartDate as datetime,
#Enddate as datetime,
#year as int
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
SELECT #StartDate = DATEFROMPARTS(#year-1,7,1), #EndDate=DATEFROMPARTS(#year,6,30)
END
Perhaps this will help and also works when the financial year has changed or you move to a new company.
CREATE PROCEDURE [dbo].[usp_yeardates] /* or your sp name */
#year AS SMALLINT,
#monthoffset AS TINYINT = 0, /* if you wish your year to start at a month other than jan then set number of months to offset, e.g. to start April, move three forward #monthoffset = 3 */
#startdate AS SMALLDATETIME OUTPUT, /* NB 2008r2+ use DATE instead of SMALLDATETIME */
#enddate AS SMALLDATETIME OUTPUT
AS
/* Created by Darren Edward Comeau - 26/08/2015 */
BEGIN
/* check inputs */
IF #year < 1900 or #year > 2078
RAISERROR ('year out of bounds',16,1)
ELSE IF #monthoffset > 11
RAISERROR ('monthoffset out of bounds',16,2)
ELSE
SELECT
/* logic to establish start / end date */
#startdate =
dateadd(month,#monthoffset,
dateadd(year,#year-1900,'19000101')
),
#enddate =
dateadd(day,-1,
dateadd(month,#monthoffset,
dateadd(year,#year-1899,'19000101')
)
);
END;
GO
You would use the procedure as follows;
/* usage */
DECLARE
#startdate SMALLDATETIME,
#enddate SMALLDATETIME,
#year SMALLINT,
#monthoffset TINYINT,
#rc INT;
EXEC #rc = usp_yeardates
#year = 2011,
#monthoffset = 6, /* 6 months offset equalls July - June year */
#startdate = #startdate OUTPUT,
#enddate = #enddate OUTPUT;
SELECT
#rc AS [ReturnCode],
#startdate AS [StartDate],
#enddate AS [EndDate];
This will give you financial year's as well start and end date
DECLARE #DateFrom datetime, #DateTo datetime
SET #DateFrom = '2012-03-30'
SET #DateTo = '2021-03-31'
DECLARE #Output TABLE ( Item NVARCHAR(1000),startdate Datetime,enddate Datetime )
DECLARE #Year INT
DECLARE #EndYear INT
DECLARE #Month INT
DECLARE #FinacialYearValue INT
SET #Month = CAST(MONTH(#DateFrom) AS INT)
SET #Year = CAST(YEAR(#DateFrom) AS INT)
SET #EndYear= CAST(YEAR(#DateTo) AS INT)
SET #FinacialYearValue = (CASE WHEN #Month <=3 THEN #Year - 1 ELSE #Year END)
WHILE #EndYear >= #FinacialYearValue
BEGIN
INSERT INTO #Output (Item,startdate,enddate )
SELECT CAST(#FinacialYearValue AS varchar(4)) + '-' + CAST((#FinacialYearValue +1 ) AS varchar(4)) ,
start_date = DATEADD(MONTH, 3, DATEADD(YEAR, DATEDIFF(YEAR, 0, DATEADD(YEAR, #FinacialYearValue+1 - 1900, 0)) - 1, 0)),
end_date = DATEADD(DAY, -1, DATEADD(MONTH, 3, DATEADD(YEAR, DATEDIFF(YEAR, 0, DATEADD(YEAR, #FinacialYearValue+1 - 1900, 0)), 0)))
SET #FinacialYearValue += 1
END
SELECT * FROM #Output
Declare #BillDate smalldatetime, #FYStartDate smalldatetime, #FYEndDate smalldatetime
Select #BillDate ='10-JAN-2019'
Select #FYStartDate = case when MONTH(#BillDate) <=3 Then '01-Apr-' + CAST(YEAR(#BillDate) - 1 AS varchar(4)) Else '01-Apr-' + CAST(YEAR(#BillDate) AS varchar(4)) End,
#FYEndDate = case when MONTH(#BillDate) <=3 Then '31-Mar-' + CAST(YEAR(#BillDate) AS varchar(4)) Else '31-Mar-' + CAST(YEAR(#BillDate) + 1 AS varchar(4)) End
The below code would well in both Azure SQL DB and On-premises. Change your Time Zone as per your need/wish. (Unit Tested)
If we given the current date or whatever date we wish to give, the below code would help us to give us both the financial year start and end date as result sets.
Also want to mention that the logic for financial year is not works well on year alone.please check below 2 cases.
Year- 2019 --> it may be either March 31 or April 1. if we dont specify date, we willl end up with errors.
Date -
20190331 --> financial start date is 20180401 and financial end date - 20190331.
20190401 --> financial start date is 20190401 and financial end date - 20200331.
DECLARE #Current_DateTime DATETIME= SYSDATETIMEOFFSET() AT TIME ZONE 'India Standard Time'; -- GETDATE()
-- SET #Current_DateTime='20200312'; -- uncomment this line to test with your desired date.
SELECT DATEFROMPARTS(Yr, 4, 1) AS FinancialYear_StartDate,
DATEFROMPARTS(Yr + 1, 3, 31) AS FinancialYear_EndDate,
CONCAT(Yr,'-',Yr+1) AS FinancialYear
FROM
(SELECT CASE WHEN DATEPART(MONTH, #Current_DateTime ) < 4
THEN DATEPART(YEAR, #Current_DateTime ) - 1 ELSE DATEPART(YEAR, #Current_DateTime ) END Yr) a;
CREATE PROC udp_financial_year
AS
BEGIN
SELECT DISTINCT
CASE
WHEN DATEPART(MONTH,creationdate) <10 then
CONVERT(VARCHAR,DATEPART(YEAR,creationdate)-1)+'-'+
CONVERT(VARCHAR,DATEPART(YEAR,creationdate))
ELSE
CONVERT(VARCHAR,DATEPART(YEAR,creationdate))+'-'+
CONVERT(VARCHAR,DATEPART(YEAR,creationdate)+1)
END
financialyr
FROM testing
ORDER BY financialyrDESC
END
This will provide starting date of an Indian financial year. i.g. April to March.
SELECT CAST(DATEFROMPARTS(YEAR(DATEADD(M, (MONTH(DATEADD(MONTH, -4, GETDATE()) - 1) * -1), GETDATE())), MONTH('04-01-2020'), DAY('04-01-2020')) AS date)
Declare #Date date = Getdate() ---Paste your date here
Declare #Fyear varchar(4)
Declare #FyearStartDate Date
Declare #FyearEnd varchar(4)
Declare #FyearEndDate Date
If Month(#Date) >= 4
Set #Fyear = year(#Date)
Else
Set #Fyear = year(#Date)-1
Set #FyearStartDate = '04' +'-'+ '01-' + #Fyear
Set #FyearEnd = #Fyear+1
Set #FyearEndDate = '03' +'-'+ '31-' + #FyearEnd
Select #FyearStartDate FYSTARTDT, #FyearEndDate FYENDDT

Calculating DATEDIFF(Month) in SQL Server

I am using the DateDiff function to find the number of months between two dates. But I am facing the problem like if the difference is 1 month and 3 days it is not giving as 2 months.
SELECT *
FROM tablename
WHERE
DATEDIFF(month, CONVERT(DATE, CONVERT(DATE, '20/10/2013', 103), 120),
CONVERT(DATE, CONVERT(DATE, '25/11/2013', 103), 120)) > 2
Result should be 2 but it is giving 1
The date column in the table is varchar type values are stored as dd/mm/yyyy. Even one day in the month should be calculated as 1 month
Got the Answer
ALTER FUNCTION [dbo].[CalculateNumberOfMonths]
(
#date1 varchar(50),
#date2 varchar(50)
)
RETURNS varchar(10)
AS
BEGIN
declare #days int
declare #months int
select #days = datediff(day,CONVERT(DATE,#date1,103),CONVERT(DATE,#date2,103))
select #months = datediff(month,CONVERT(DATE,#date1,103),CONVERT(DATE,#date2,103))
if(#days % 7 >0)
begin
set #months= #months + 1
end
RETURN #months
END

Select all dates after a cutoff day in current month

I have a situation where I need to return all records loaded after a specific day of the current month, in a sense the cut off date of that month.
In my situation I need to return all values after the 9th of the current month.
DECLARE #CUTOFFDAY INT
DECLARE #CUTOFFDATE DATETIME
SET #CUTOFFDAY = 9
SET #CUTOFFDATE = CAST(CAST(YEAR(getdate()) AS varchar) + '-' + CAST(MONTH(getdate())AS varchar) + '-' + CAST(#CUTOFFDAY AS varchar) AS DATETIME)
SELECT Date
FROM DateTable
WHERE ContractDate > #CUTOFF
DATE
declare #cutoffday int = 9
select * from <yourtable>
where <yourdatefield> >=
dateadd(m, datediff(m, 0, current_timestamp), #cutoffday - 1)

Get dates from a week number in T-SQL

In Microsoft SQL Server, I have a week number
(from DATEPART(wk, datecol))
But what I would like to do is turn this back into the date span for that week.
For example,
SELECT DATEPART(wk, GETDATE())
yields 10. I would like to derive 3/1/2009 and 3/7/2009 from this number.
Is this possible?
Quassnoi's answer works, but kind of leaves you on the hook for cleaning up the dates if they are dates in the middle of the day (his start of week leaves you one day earlier than you need to be if you use a time in the middle of the day -- you can test using GETDATE()).
I've used something like this in the past:
SELECT
CONVERT(varchar(50), (DATEADD(dd, ##DATEFIRST - DATEPART(dw, DATECOL), DATECOL)), 101),
CONVERT(varchar(50), (DATEADD(dd, ##DATEFIRST - DATEPART(dw, DATECOL) - 6, DATECOL)), 101)
A side benefit of this is that by using ##DATEFIRST you can handle nonstandard week starting days (the default is Sunday, but with SET ##DATEFIRST you can change this).
It seems crazy that simple date manipulation in SQL Server has to be this arcane, but there you go...
You can set #WeekNum and #YearNum to whatever you want - in this example they are derived from the #datecol variable, which is set to GETDATE() for purposes of illustration. Once you have those values- you can calculate the date range for a week by using the following:
DECLARE #datecol datetime = GETDATE();
DECLARE #WeekNum INT
, #YearNum char(4);
SELECT #WeekNum = DATEPART(WK, #datecol)
, #YearNum = CAST(DATEPART(YY, #datecol) AS CHAR(4));
-- once you have the #WeekNum and #YearNum set, the following calculates the date range.
SELECT DATEADD(wk, DATEDIFF(wk, 6, '1/1/' + #YearNum) + (#WeekNum-1), 6) AS StartOfWeek;
SELECT DATEADD(wk, DATEDIFF(wk, 5, '1/1/' + #YearNum) + (#WeekNum-1), 5) AS EndOfWeek;
To answer your question:
--CHANGE A WEEK NUMBER BACK INTO A DATE FOR THE FIRST DATE OF THE WEEK
DECLARE #TaskWeek INT = 17
DECLARE #TaskYear INT = 2013
SELECT DATEADD(WEEK, #TaskWeek - 1,DATEADD(dd, 1 - DATEPART(dw, '1/1/' + CONVERT(VARCHAR(4),#TaskYear)), '1/1/' + CONVERT(VARCHAR(4),#TaskYear)))
If your week starts from Monday (on SQL Server 2008)
select datecol,
DATEPART(ISOWK, datecol) as week,
((DATEPART(dw, datecol)+5)%7)+1 as weekday,
(DATEADD(dd, -((DATEPART(dw, datecol)+5)%7), datecol)) as Monday,
(DATEADD(dd, -((DATEPART(dw, datecol)+5)%7)+6, datecol)) as Sunday
SELECT DATECOL - DATEPART(weekday, DATECOL), DATECOL - DATEPART(weekday, DATECOL) + 7
How about a function that jumps to the week before that week number and then steps through the next few days until the week number changes (max 7 steps), returning the new date?
CREATE FUNCTION dbo.fnGetDateFromWeekNo
(#weekNo int , #yearNo int)
RETURNS smalldatetime
AS
BEGIN
DECLARE #tmpDate smalldatetime
set #tmpdate= cast(cast (#yearNo as varchar) + '-01-01' as smalldatetime)
-- jump forward x-1 weeks to save counting through the whole year
set #tmpdate=dateadd(wk,#weekno-1,#tmpdate)
-- make sure weekno is not out of range
if #WeekNo <= datepart(wk,cast(cast (#yearNo as varchar) + '-12-31' as smalldatetime))
BEGIN
WHILE (datepart(wk,#tmpdate)<#WeekNo)
BEGIN
set #tmpdate=dateadd(dd,1,#tmpdate)
END
END
ELSE
BEGIN
-- invalid weeknumber given
set #tmpdate=null
END
RETURN #tmpDate
END
I've taken elindeblom's solution and modified it - the use of strings (even if cast to dates) makes me nervous for the different formats of dates used around the world. This avoids that issue.
While not requested, I've also included time so the week ends 1 second before midnight:
DECLARE #WeekNum INT = 12,
#YearNum INT = 2014 ;
SELECT DATEADD(wk,
DATEDIFF(wk, 6,
CAST(RTRIM(#YearNum * 10000 + 1 * 100 + 1) AS DATETIME))
+ ( #WeekNum - 1 ), 6) AS [start_of_week],
DATEADD(second, -1,
DATEADD(day,
DATEDIFF(day, 0,
DATEADD(wk,
DATEDIFF(wk, 5,
CAST(RTRIM(#YearNum * 10000
+ 1 * 100 + 1) AS DATETIME))
+ ( #WeekNum + -1 ), 5)) + 1, 0)) AS [end_of_week] ;
Yes, I know I'm still casting but from a number. It "feels" safer to me.
This results in:
start_of_week end_of_week
----------------------- -----------------------
2014-03-16 00:00:00.000 2014-03-22 23:59:59.000
Another way to do it:
declare #week_number int;
declare #start_weekday int = 0 -- Monday
declare #end_weekday int = 6 -- next Sunday
select #week_number = datediff(week, 0, getdate())
select
dateadd(week, #week_number, #start_weekday) as WEEK_FIRST_DAY,
dateadd(week, #week_number, #end_weekday) as WEEK_LAST_DAY
Explanation:
#week_number is computed based on the initial calendar date '1900-01-01'. Replace getdate() by whatever date you want.
#start_weekday is 0 if Monday. If Sunday, then declare it as -1
#end_weekday is 6 if next Sunday. If Saturday, then declare it as 5
Then dateadd function, will add the given number of weeks and the given number of days to the initial calendar date '1900-01-01'.
dateadd(
dd,
datepart(wk, #Date)*7,
convert(smalldatetime, convert(char,year(max(#Date)))+convert(char, '-01-01'))
)-1
Here you just have to pass year and week number.
DECLARE #Year VARCHAR(4)
SET #Year= '2012'
DECLARE #FirstDate DATETIME
SET #FirstDate = (SELECT DATEADD(dd,1,(SELECT DATEADD(wk,DATEPART(wk,GETDATE())-1,Convert(DAteTime,'01-01-' + #Year))))
)
DECLARE #LastDate DATETIME
SET #LastDate =(SELECT DATEADD(dd,4,#FirstDate))
SELECT #FirstDate
,#LastDate
This should work regardless of ##DATEFIRST
ALTER FUNCTION dbo.DEV_VW_WeekSerial
(#YearNum int,
#WeekNum int,
#DayNum int)
RETURNS Date AS
BEGIN
DECLARE #FirstDayYear As Date;
SET #FirstDayYear='01/01/' + CAST(#YearNum As varchar)
RETURN dateadd(d,(#DayNum-datepart(weekday,#FirstDayYear)),dateadd(week, #WeekNum-1,#FirstDayYear))
END
Give it #Year and #Week,
return first date of that week.
Declare #Year int
,#Week int
,#YearText varchar(4)
set #Year = 2009
set #Week = 10
set #YearText = #Year
print dateadd(day
,1 - datepart(dw, #YearText + '-01-01')
+ (#Week-1) * 7
,#YearText + '-01-01')
I just incorporated the SELECT with a CASE statement (For my situation Monday marked the first day of the week, and didn't want to deal with the SET DATEFIRST command:
CASE DATEPART(dw,<YourDateTimeField>)
WHEN 1 THEN CONVERT(char(10), DATEADD(DD, -6, <YourDateTimeField>),126) + ' to ' + CONVERT(char(10), <YourDateTimeField>,126)
WHEN 2 THEN CONVERT(char(10), <YourDateTimeField>,126) + ' to ' + CONVERT(char(10), DATEADD(DD, 6, <YourDateTimeField>),126)
WHEN 3 THEN CONVERT(char(10), DATEADD(DD, -1, <YourDateTimeField>),126) + ' to ' + CONVERT(char(10), DATEADD(DD, 5, <YourDateTimeField>),126)
WHEN 4 THEN CONVERT(char(10), DATEADD(DD, -2, <YourDateTimeField>),126) + ' to ' + CONVERT(char(10), DATEADD(DD, 4, <YourDateTimeField>),126)
WHEN 5 THEN CONVERT(char(10), DATEADD(DD, -3, <YourDateTimeField>),126) + ' to ' + CONVERT(char(10), DATEADD(DD, 3, <YourDateTimeField>),126)
WHEN 6 THEN CONVERT(char(10), DATEADD(DD, -4, <YourDateTimeField>),126) + ' to ' + CONVERT(char(10), DATEADD(DD, 2, <YourDateTimeField>),126)
WHEN 7 THEN CONVERT(char(10), DATEADD(DD, -5, <YourDateTimeField>),126) + ' to ' + CONVERT(char(10), DATEADD(DD, 1, <YourDateTimeField>),126)
ELSE 'UNK'
END AS Week_Range
The most votes answer works fine except the 1st week and last week of year. When datecol value is '2009-01-01', the result will be 01/03/2009 and 12/28/2008.
My solution:
DECLARE #Date date = '2009-03-01', #WeekNum int, #StartDate date;
SELECT #WeekNum = DATEPART(WEEK, #Date);
SELECT #StartDate = DATEADD(DAY, -(DATEPART(WEEKDAY, DATEADD(YEAR, DATEDIFF(YEAR, 0, #Date), 0)) + 6), DATEADD(YEAR, DATEDIFF(YEAR, 0, #Date), 0));
SELECT CONVERT(nvarchar, CASE WHEN #WeekNum = 1 THEN CAST(DATEADD(YEAR, DATEDIFF(YEAR, 0, #Date), 0) AS date) ELSE DATEADD(DAY, 7 * #WeekNum, #StartDate) END, 101) AS StartOfWeek
,CONVERT(nvarchar, CASE WHEN #WeekNum = DATEPART(WEEK, DATEADD(DAY, -1, DATEADD(YEAR, DATEDIFF(YEAR, 0, #Date) + 1, 0))) THEN DATEADD(DAY, -1, DATEADD(YEAR, DATEDIFF(YEAR, 0, #Date) + 1, 0)) ELSE DATEADD(DAY, 7 * #WeekNum + 6, #StartDate) END, 101) AS EndOfWeek;
This will display 01/01/2009 and 01/03/2009 for the 1st week, and display 03/01/2009 and 03/07/2009 for the 10th week.
I think this would be what you want exactly. You can replace the variables with their expressions as you wish.
declare #IntWeek as varchar(20)
SET #IntWeek = '201820'
SELECT
DATEADD(wk, DATEDIFF(wk, ##DATEFIRST, LEFT(#IntWeek,4) + '-01-01') +
(cast(RIGHT(#IntWeek, 2) as int) -1), ##DATEFIRST) AS StartOfWeek
SELECT DATEADD(week, #weekNumber - 1, DATEADD(DAY, ##datefirst - DATEPART(weekday, CAST(YEAR(GETDATE()) AS VARCHAR) + '-01-01') - 6, CAST(YEAR(GETDATE()) AS VARCHAR) + '-01-01'))
DECLARE #dayval int,
#monthval int,
#yearval int
SET #dayval = 1
SET #monthval = 1
SET #yearval = 2011
DECLARE #dtDateSerial datetime
SET #dtDateSerial = DATEADD(day, #dayval-1,
DATEADD(month, #monthval-1,
DATEADD(year, #yearval-1900, 0)
)
)
DECLARE #weekno int
SET #weekno = 53
DECLARE #weekstart datetime
SET #weekstart = dateadd(day, 7 * (#weekno -1) - datepart (dw, #dtDateSerial), #dtDateSerial)
DECLARE #weekend datetime
SET #weekend = dateadd(day, 6, #weekstart)
SELECT #weekstart, #weekend
Answer:
select DateAdd(day,-DATEPart(DW,<Date>), <Date>) [FirstDayOfWeek] ,DateAdd(day,-DATEPart(DW,<Date>)+6, <Date>) [LastDayOfWeek]
FROM <TABLE>
This works for me:
select
convert(varchar(50), dateadd(dd, - datepart(dw, DATECOL) + 1, DATECOL), 101),
convert(varchar(50), dateadd(dd, - datepart(dw, DATECOL) + 7, DATECOL), 101)
I didn't take the time to test out every answer on here, but nothing seems as simple and as efficient as this:
DECLARE #WeekNum int
DECLARE #YearNum char(4)
SELECT DATEADD(wk, DATEDIFF(wk, 6, '1/1/' + #YearNum) + (#WeekNum-1), 6) AS StartOfWeek
SELECT DATEADD(wk, DATEDIFF(wk, 5, '1/1/' + #YearNum) + (#WeekNum-1), 5) AS EndOfWeek

Resources