Related
I have this query for expiry date calculation and its work fine but result show in - eg:-9 year 4 month and 5 day.
I want to show that in normal way like "Expire in 9 years 4 months and 5 day":
DECLARE #TempDate Datetime ,
#ExpiryDate Datetime,
#year int,
#month int,
#day int
SET #ExpiryDate = (SELECT TOP (1) [ExpiryDate] FROM [dbo].[Purchases] WHERE [ProductId] = 1)
SELECT #TempDate = #ExpiryDate
SELECT
#year = DATEDIFF(YEAR, #TempDate, GETDATE()) -
CASE
WHEN (MONTH(#ExpiryDate) > MONTH(GETDATE())) OR
(MONTH(#ExpiryDate) = MONTH(GETDATE()) AND DAY(#ExpiryDate) > DAY(GETDATE()))
THEN 1 ELSE 0
END
SELECT #TempDate = DATEADD(YEAR, #year, #TempDate)
SELECT #month = DATEDIFF(MONTH, #TempDate, GETDATE()) -
CASE
WHEN DAY(#ExpiryDate) > DAY(GETDATE())
THEN 1 ELSE 0
END
SELECT #TempDate = DATEADD(MONTH, #month, #TempDate)
SELECT #day = DATEDIFF(DAY, #TempDate, GETDATE())
SELECT #year AS Years, #month AS Months, #day AS [Days]
If I understand your question correctly, the calculation is working as you expect but you want the Years value to be returned as a positive rather than negative number. If this is the case, you should change the final SELECT to:
SELECT (#year * -1) AS Years, #month AS Months, #day AS [Days];
Alternatively if you want to return the output as a string (i.e. Expire in 9 years 4 months and 5 day), change the final SELECT to:
SELECT 'Expire in ' + CAST((#year * -1) AS VARCHAR(2)) + ' years '
+ CAST(#month AS VARCHAR(2)) + ' months and '
+ CAST(#day AS VARCHAR(2)) + ' day';
Casting as VARCHAR(2) assumes that you expect no more than 99 years, but you may want to increase that number.
I'm using SQL Server 2008 R2 and need to return all data with the last day of month through selected start- and enddate:
When the user select two dates something like:
Startdate: 2017-01-01
Enddate: 2017-22-02
The result have to be:
2017-31-01 AND 2017-22-02
I tried the following code, but I got the wrong result => 2017-28-02
SELECT
DATEADD(d, -1, DATEADD(mm, DATEDIFF(m, 0,'2017-22-02') + 1, 0)) AS DiffDate,
MEMBER_ID
FROM
dbo.tblOne
WHERE
DATUM >= '2017-01-01'
AND
DATUM <= '2017-22-02'
Could anyone has an idea what I'm doing wrong?!
Edit:
I expect the following result:
DiffDate | MemberID | ...
---------------------------------
2017-01-31 | CBK01
2017-01-31 | KKM05
2017-01-31 | ABC99
2017-02-22 | CBK01
2017-02-22 | KKM05
2017-02-22 | ABC99
I can suggest this method to get last date of a month of a date:
declare #date datetime = '2017-04-22';
select
dateadd(d,
-datepart(d,#date) -- count of days of #date to get back
,dateadd(m,1,#date) -- get date of next month of #date
) lastDate
I am using UDF fn_DateSerial to simplify such date operations:
--sample value
Declare #Startdate datetime
set #Startdate = GetDate()
--last day of month
select DateAdd(month, 1, dbo.fn_DateSerial(Year(#Startdate),Month(#Startdate),1,0,0,0,0)) - 1
So basically I am striping day part (making it 1st day), then 1 month is added, and finally one day is subtracted.
This UDF was inspired by vb6 function of same name.
/*
Function composes datetime from its parts - year, month, day, minute, etc.
*/
CREATE FUNCTION dbo.fn_DateSerial(#year int, #month int, #day int, #hour int, #minute int, #second int, #millisecond int) RETURNS datetime
BEGIN
DECLARE #dt datetime, #dtStr varchar(255)
--mm/dd/yyyy hh:mi:ss.mmm(24h)
SET #dtStr = ''
SET #dtStr = #dtStr + right('00'+convert(varchar(2), #month),2) + '/'
SET #dtStr = #dtStr + right('00'+convert(varchar(2), #day),2) + '/'
SET #dtStr = #dtStr + right('0000'+convert(varchar(4),#year),4)
SET #dtStr = #dtStr + ' ' + right('00'+convert(varchar(2), #hour),2) + ':'
SET #dtStr = #dtStr + right('00'+convert(varchar(2), #minute),2) + ':'
SET #dtStr = #dtStr + right('00'+convert(varchar(2), #second),2) + '.'
SET #dtStr = #dtStr + right('000'+convert(varchar(3), #millisecond),3)
SET #dt = CONVERT(datetime, #dtStr, 101)
return #dt
END
Leaving the date format out of the solution here but that is something you really need to resolve. As I understand it you simply need to find the last day of the previous month for a given date. This will do that using getdate() as the base. You could easily change getdate() to be a column in your data.
select LastDayOfPreviousMonth = dateadd(day, -1, dateadd(month, datediff(month, 0, GETDATE()), 0))
My scenario is as below:
#StartDate = 13th of current month
#EndDate = 12th of next month.
I want to get all the date with the day-name for Mondays, Tuesdays, Wednesdays, Thursdays, Fridays, Saturdays and Sundays lying between the start and end date.
Try this:
declare #startDate datetime = '2016-01-13'
declare #endDate datetime = '2016-02-12'
;with dateRange as
(
select [Date] = dateadd(dd, 1, #startDate)
where dateadd(dd, 1, #startDate) < #endDate
union all
select dateadd(dd, 1, [Date])
from dateRange
where dateadd(dd, 1, [Date]) < #endDate
)
select [Date], datename(dw,[Date])
from dateRange
To count the number of each day as per your comment (this should be part of the question really), change the last part of James' answer to this:
select datename(dw,[Date]) as day_name, count([Date]) as number_days
from dateRange group by datename(dw,[Date]), datepart(DW,[Date])
order by datepart(DW,[Date]);
You can try something like this :
DECLARE #StartDate DATETIME
DECLARE #StartDateFixed DATETIME
DECLARE #EndDate DATETIME
DECLARE #NumberOfDays int
SET #StartDate = '2016/01/01'
SET #EndDate = '2016/01/02'
SET #NumberOfDays = DATEDIFF(DAY,#StartDate,#EndDate) + 1
SET #StartDateFixed = DATEADD(DD,-1,#StartDate)
SELECT WeekDay , COUNT(WeekDay)
FROM (
SELECT TOP (#NumberOfDays) WeekDay = DATENAME(DW , DATEADD(DAY,ROW_NUMBER() OVER(ORDER BY spt.name), #StartDateFixed))
FROM [master].[dbo].[spt_values] spt
) A
GROUP BY WeekDay
The output will be
WeekDay
------------------------------ -----------
Friday 1
Saturday 1
(2 row(s) affected)
In case if you need to get current and next date from date number specified such as 13 and 12
Current Month
DECLARE #cur_mont INT = (SELECT MONTH(GETDATE()))
Current Year
DECLARE #cur_year INT = (SELECT YEAR(GETDATE()))
Next Month
DECLARE #nxt_mont INT = (SELECT MONTH(DATEADD(month, 1, GETDATE())))
Next Month year (In case of December year change)
DECLARE #nxt_year INT = (SELECT YEAR(DATEADD(month, 1, GETDATE())))
Create start date
DECLARE #startDate DATETIME = (SELECT CAST(CAST(#cur_year AS varchar) + '-' + CAST(#cur_mont AS varchar) + '-' + CAST(13 AS varchar) AS DATETIME))
Create end date
DECLARE #endDate DATETIME = (SELECT CAST(CAST(#nxt_year AS varchar) + '-' + CAST(#nxt_mont AS varchar) + '-' + CAST(12 AS varchar) AS DATETIME))
Dates between start and end date
SELECT TOP (DATEDIFF(DAY, #startDate, #endDate) + 1)
DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY a.object_id) - 1, #startDate) AS Date,
DATENAME(DW, DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY a.object_id) - 1, #startDate)) AS Day
FROM sys.all_objects a CROSS JOIN sys.all_objects b;
DECLARE #dayStart int = 13, --The day of current month
#dayEnd int = 12, --The day of another month
#howManyMonth int = 1, --How many month to take
#dateStart date,
#dateEnd date
--Here we determine range of the dates
SELECT #dateStart = CONVERT (date,
CAST(DATEPART(Year,GETDATE()) as nvarchar(5))+ '-' +
CASE WHEN LEN(CAST(DATEPART(Month,GETDATE()) as nvarchar(5))) = 1
THEN '0'+CAST(DATEPART(Month,GETDATE()) as nvarchar(5))
ELSE CAST(DATEPART(Month,GETDATE()) as nvarchar(5)) END + '-' +
CAST (#dayStart as nvarchar(5))),
#dateEnd = CONVERT (date,
CAST(DATEPART(Year,DATEADD(Month,#howManyMonth,GETDATE())) as nvarchar(5))+ '-' +
CASE WHEN LEN(CAST(DATEPART(Month,DATEADD(Month,#howManyMonth,GETDATE())) as nvarchar(5))) = 1
THEN '0'+CAST(DATEPART(Month,DATEADD(Month,#howManyMonth,GETDATE())) as nvarchar(5))
ELSE CAST(DATEPART(Month,DATEADD(Month,#howManyMonth,GETDATE())) as nvarchar(5)) END + '-' +
CAST (#dayEnd as nvarchar(5)))
;WITH cte AS (
SELECT #dateStart as date_
UNION ALL
SELECT DATEADD(day,1,date_)
FROM cte
WHERE DATEADD(day,1,date_) <= #dateEnd
)
--Get results
SELECT DATENAME(WEEKDAY,date_) as [DayOfWeek],
COUNT(*) as [DaysCount]
FROM cte
GROUP BY DATEPART(WEEKDAY,date_),
DATENAME(WEEKDAY,date_)
ORDER BY DATEPART(WEEKDAY,date_)
OPTION (MAXRECURSION 0)
Output:
DayOfWeek DaysCount
----------- -----------
Sunday 4
Monday 4
Tuesday 4
Wednesday 5
Thursday 5
Friday 4
Saturday 4
(7 row(s) affected
I have a week number and year and i need to display "total for mm/dd/yy to mm/dd/yy in a row of my ssrs report. My week starts with Monday. For example if my week number is '2' and year is '2010' then I have to display "total for 01/04/2010 to 01/10/2010 in my ssrs column. how to do this?
Try this
declare #year char(4) = '2010'
declare #week int = 2
declare #fromdate datetime
declare #todate datetime
set #fromdate = DATEADD(wk, DATEDIFF(wk, 6, '1/1/' + #year) + (#week-1), 7);
set #todate = DATEADD(wk, DATEDIFF(wk, 5, '1/1/' + #year) + (#week-1), 6) ;
;WITH dates AS
(
SELECT CONVERT(datetime,#fromDate) as Date
UNION ALL
SELECT DATEADD(d,1,[Date])
FROM dates
WHERE DATE < #toDate
)
select * from dates
SQL Server has a DATEPART function which calculates the ordinal week number of a year. However, you have to call DATEFIRST before this to define which day of the week represents the start of the week. In your case, you have stated that the start of your week is Monday (i.e. 1).
SET DATEFIRST 1;
SELECT SUM([your data column])
FROM [your table]
WHERE DATEPART(WEEKNUM, [your date column])=[your week parameter]
AND DATEPART(YEAR, [your date column])=[your year parameter]
Your description is not american standard nor isoweek. Seems like a mix of those. I never heard of that as a standard. It is nearly isoweek. So that is what this answer is based on.
Calculating iso year is a bit tricky, you can read about it here:
This is the syntax you need:
DECLARE #year int = 2010
DECLARE #week int = 2
;WITH CTE AS
(
SELECT
dateadd(wk, datediff(wk, - #week * 7,
cast(cast(#year as char(4)) as datetime) - 5), 0) startofweek
)
SELECT
replace('total for ' + convert(char(10), startofweek, 110)
+ ' to ' + convert(char(10), dateadd(day, 6, startofweek) , 110), '-', '/')
FROM CTE
Result:
total for 01/11/2010 to 01/17/2010
Isoweek 2 in 2010 is 2010-01-11
Try setting DATEFIRST (https://msdn.microsoft.com/en-ie/library/ms181598.aspx)
SET DATEFIRST 7
declare #wk int
declare #yr int
declare #EndOfWeek as datetime
set #wk = 2
set #yr = 2010
SET #EndOfWeek = dateadd (week, #wk, dateadd (year, #yr-1900, 0)) + 1 - datepart(dw, dateadd (week, #wk, dateadd (year, #yr-1900, 0)) )
SELECT
replace('total for ' + convert(char(10), dateadd(day, -6, #EndOfWeek) , 110)
+ ' to ' + convert(char(10), #EndOfWeek, 110), '-', '/')
The result:
total for 01/04/2010 to 01/10/2010
I hope it helps:
declare #year char(4) = '2014'
declare #week int = 2
select dateadd(week,#week,convert(date,#year+'-01-01',121))
Change the date format appropriate for you from this list
I need to calculate the year a week is assigned to. For example the 29th december of 2003 was assigned to week one of year 2004 (this is only for europe, I think). You can take a look at this with this code:
SELECT DATEPART(isowk, '20141229');
But now I need an easy way to get the year this week is assigned to. What I currently do is not that elegant:
DECLARE #week int, #year int, #date char(8)
--set #date = '20150101'
set #date = '20141229'
SET #week = cast(datepart(isowk, #date) as int)
if #week = 1
begin
if DATEPART(MONTH, #date) = 12
begin
set #year = DATEPART(year, #date) + 1
end
else
begin
set #year = DATEPART(year, #date)
end
end
select #date "DATE", #week "WEEK", #year "YEAR"
If anybody knew a more elegant way, that would be nice :-)
This solution The code in the question does not return the correct value for the date '1-1-2027'.
The following will return the correct value with all dates i tested (and i tested quite a few).
SELECT YEAR(DATEADD(day, 26 - DATEPART(isoww, '2012-01-01'), '2012-01-01'))
As taken from: https://capens.net/content/sql-year-iso-week
This is the most compact solution I could come up with:
CASE
WHEN DATEPART(ISO_WEEK, #Date) > 50 AND MONTH(#Date) = 1 THEN YEAR(#Date) - 1
WHEN DATEPART(ISO_WEEK, #Date) = 1 AND MONTH(#Date) = 12 THEN YEAR(#Date) + 1
ELSE YEAR(#Date) END
Can be used directly inside a SELECT statement. Or you could consider creating a user-defined function that takes the #Date parameter as input and outputs the result of the case statement.
I think this solution is much more logical and easier to comprehend for ISO-8601.
"The first week of the year is the week containing the first Thursday."
see ISO Week definition
So we need to deduct the weekday of the given date from Thursday and add this to that same date to get the year.
Adding 5 and then taking the modulus of 7 to move Sunday to the previous week.
declare #TestDate date = '20270101'
select year(dateadd(day, 3 - (datepart(weekday, #TestDate) + 5) % 7, #TestDate))
This will result in 2026 which is correct.
This will give the correct result for all dates I check between 1990-2100 using this:
declare #TestDate date = '19900101'
declare #Results as table
(
TestDate date,
FirstDayofYear varchar(20),
ISOYear int,
ISOWeek int
)
while (#TestDate < '21000201')
begin
insert #Results(TestDate, FirstDayofYear, ISOYEar, ISOWeek)
select #TestDate, datename(weekday, dateadd(day, datepart(day, #TestDate) * -1 +1, #TestDate)),
year(dateadd(day, 3 - (datepart(weekday, #TestDate) + 5) % 7, #TestDate)), datepart(ISOWK, #TestDate)
set #TestDate = dateadd(day, 1, #Testdate)
if(datepart(day, #TestDate) > 7)
begin
set #TestDate = dateadd(year, 1, dateadd(day, datepart(day, #TestDate) * -1 + 1, #TestDate))
end
end
-- Show all results that are wrong:
select * from #Results
where (ISOYear <> datepart(year, TestDate) and ISOWeek < 3)
or (ISOYear = datepart(year, TestDate) and ISOWeek >= 52)
I think Bart Vanseer solution is nice and simple, but off by 1.
I believe it should be
select year(dateadd(day, 3 - ((datepart(weekday, #TestDate) + 5) % 7) , #TestDate))
Try following to find a few places were it differs
declare #TestDate date = '2000-01-01'
DECLARE #cnt INT = 0;
DECLARE #cnt_total INT = 10000;
WHILE #cnt < #cnt_total
BEGIN
SET #TestDate = dateadd(day,1, #TestDate)
if year(dateadd(day, 3 - (datepart(weekday, #TestDate) + 6) % 8, #TestDate)) <>
year(dateadd(day, 3 - ((datepart(weekday, #TestDate) + 5) % 7) , #TestDate))
BEGIN
select #TestDate, year(dateadd(day, 3 - (datepart(weekday, #TestDate) + 6) % 8, #TestDate))
select #TestDate, year(dateadd(day, 3 - ((datepart(weekday, #TestDate) + 5) % 7) , #TestDate))
END
SET #cnt = #cnt + 1;
END;
Inspired by the other answers, i came to the following solution:
declare #TestDate date = '20270101'
SELECT DATEPART(year, DATEADD(day, 4 - DATEPART(weekday, #TestDate), #TestDate))
Just get thursday of the current week to get the correct year.
Assuming DATEFIRST is set to Monday (1).
DECLARE #date DATETIME
SET #date='2014-12-29'
SELECT
CASE --Covers logic for ISO week date system which is part of the ISO 8601 date and time standard. Ref: https://en.wikipedia.org/wiki/ISO_week_date
WHEN (DATEPART(ISO_WEEK,#date) = 53) AND (DATEPART(MONTH,#date) = 1)
THEN CAST((DATEPART(YEAR, #date) - 1) AS varchar(4)) + ('-W') + CAST (RIGHT('0' + CAST(DATEPART(ISO_WEEK,#date) AS varchar(2)),2) AS varchar(2))
WHEN (DATEPART(ISO_WEEK,#date) = 1) AND (DATEPART(MONTH,#date) = 12)
THEN CAST((DATEPART(YEAR,#date) + 1) AS varchar(4)) + ('-W') + CAST (RIGHT('0' + CAST(DATEPART(ISO_WEEK,#date) AS varchar(2)),2) AS varchar(2))
ELSE CAST(DATEPART(YEAR,#date) AS varchar(4)) + ('-W') + CAST (RIGHT('0' + CAST(DATEPART(ISO_WEEK,#date) AS varchar(2)),2) AS varchar(2))
END AS ISO_week
For IsoYear, get the Thursday from IsoWeek, and then get the year.