New to SQL Server looking for assistance for a datetime conversion - sql

this is my first submission on Stack Overflow, and I am open to any suggestions on structuring my questions.
I am new to SQL Server, and I have a line of code I that I don't understand.
Can someone please explain this?
declare #prior_year datetime = convert(date, '12/31/' + convert(varchar, datepart(yy, #start_date) - 1))

This is a problematic way to determine the last day of the year before the date(time) stored in some variable.
convert(date, '12/31/' + convert(varchar, datepart(yy, #start_date) - 1))
In English, working outward:
datepart(yy, #start_date)
Tell me the year of the variable #start_date. This is poor form because, if we mean year, we should spell out YEAR (see "Date Parts" in this post). I said this already once today, but this is just laziness, it's like "I'm going to type just enough characters to avoid an unexpected result, but not enough characters to make my intent clear." Worse is YYYY, which I see often - you have a choice between YYYY and YEAR, why not type the one that's actually a word?
datepart(yy, #start_date) - 1
--------------------------- ^^^
Subtract one from that year.I don't have any issues here, but it may be clearer to use an explicit DATEADD() against the variable first, and then extracting the year from that, since things like <some date thing> - 1 can be misread as an attempt to subtract a day (also covered in the shorthand post referenced above).
convert(varchar, datepart(yy, #start_date) - 1))
--^^^^^^^^^^^^^^^^
Convert that explicitly to a string.
Also poor form here because we should always specify the length of variable-width data. In some cases this can lead to unexpected truncation. See this post.
'12/31/' + convert(varchar, datepart(yy, #start_date) - 1))
--^^^^^^^^^^
Prefix that year with 12/31 to produce a mm/dd/yyyy string.
More poor form, because this then assumes the user has US English regional settings, MDY dateformat, etc. If you're going to insist on building a string that represents a date, always use a standard, unambiguous format: YYYYMMDD. (And FWIW YYYY-MM-DD is ambiguous, try it with SET LANGUAGE FRENCH;). See this post.
convert(date, <the rest>)
Converts the whole expression to a date.
A better solution
Ideally we should not be using strings anywhere along the line for any of this. We have built-in functions that provide all kinds of native date handling capabilities without having to worry about languages, regional settings, date format preferences, or string lengths:
SELECT DATEFROMPARTS(YEAR(#start_date) - 1, 12, 31);
-- or, more explicitly:
SELECT DATEFROMPARTS(DATEPART(YEAR, #start_date) - 1, 12, 31);
The other way you can think about this is that the last day of last year is the same day as the day before the first day of this year. Thinking about it in these terms can make it much easier to conceptualize when you are doing things like prior month, where determining the last day of the previous month is more tedious. Or if you are finding endpoints for range queries, because the end of the current reporting period is never as deterministic as the start of the next reporting period. More on that here.
SELECT DATEADD(DAY, -1, DATEFROMPARTS(YEAR(#start_date), 1, 1));
Also of potential use:
Dating Responsibly
Simplify Date Period Calculations in SQL Server
SQL Server DateTime Best Practices
Four short videos in this series

Reading this from the inside out:
We're first finding the year of the date using DATEPART and then subtracting 1 so for a value for today's date: 2020-08-18 we'd be getting an integer value of 19
datepart(yy, '2020-08-18') - 1)
We're then using convert on that value to change it to a varchar:
convert(varchar, 19)
We're then using that new varchar to create a string:
'12/31/' + '19'
Finally we're using convert again to create a date from the string
convert(date, '12/31/19')

Tony,
For completeness please provide the definition and assignment for #start_date. Assuming the statement you provided works, it is probably defined something like
declare #start_date date
set #start_date = '07-01-2020'
Working from the inside out, we can then break the statement down like so ...
This will extract the year value
datepart(yy, #start_date)
This will subtract 1 from the #start_date year value, assuming 2020, this returns 2019
convert(varchar, datepart(yy, #start_date) - 1)
And then this will convert that to the last day of the previous year.
convert(date, '12/31/' + convert(varchar, datepart(yy, #start_date) - 1))
So the statement simply sets the new field to the last day of the prior year.

declare #prior_year datetime = convert(date, '12/31/' + convert(varchar, datepart(yy, #start_date) - 1))
This SQL code declares a #prior_year datetime variable that is hard coded to 12/31/. datepart is used to extract the previous year from another datetime variable #start_date` that is passed in and tacks the returned value onto the end of the '12/31/' hard coded string. So; its really just a formula of 12/31/(#start_date prior year)
So if #start_date is 8/20/2020
You will end up with the output of 12/31/2019
declare #start_date datetime = getdate()
declare #prior_year datetime = convert(date, '12/31/' + convert(varchar, datepart(yy, #start_date) - 1))
select #prior_year
Result:

Related

How to subtract one month from a date using SQL Server

I have a date in format dd/mm/yyyy. I want to subtract one month from it.
I am using this code but the output is "09/10/2020" I don't know why my code does the subtraction of the year -2 also.
This is my request
SELECT
FORMAT(CONVERT (DATE, DATEADD(MONTH, -1, CONVERT(char(9), GETDATE()))), 'dd/MM/yyyy')
you need to change it to:
select format(CONVERT (date,DATEADD(MONTH, -1,GETDATE())), 'dd/MM/yyyy' )
but as Larnu stated. it seems like you need to change the column.
Your current code doesn't work as expected because:
SELECT CONVERT(char(9), GETDATE());
Returns this (at least in my language):
Nov 9 20
Which is, unfortunately, and again in my language, a valid date (but in {20}20, not {20}22).
Even in the right style (103), char(9) would yield 10/11/202 tomorrow, since 9 digits is only enough if either the day or month is a single digit.
Don't know why you are converting GETDATE() to a string. Just perform date math on it and then format it if you need to (using a specific style number, e.g. 103 for d/m/y):
SELECT CONVERT(char(10), DATEADD(MONTH, -1, GETDATE()), 103);
I really wouldn't use FORMAT() for such simple output, as the CLR overhead really isn't worth it. Ideally you leave it as a date/time type until presentation time - surely your presentation layer can present your date as d/m/y if that's really a wise idea.
And if you are storing or passing dates as strings (and worse, in regional formats like d/m/y) you really should consider fixing that.
First of all,
You should be storing your Date as a string for easier manipulation. If you don't want to change the column, you can always convert from Date to Varchar and then (re)convert it.
Example:
First, convert Date to varchar using the style code '112' ISO for formatting as yyyyMMdd:
DECLARE #date DATE = GETDATE();
DECLARE #dateConverted as VARCHAR (8) = (SELECT CONVERT(VARCHAR, #date, 112));
Then you just subtract the month using DATEADD():
DECLARE #previousMonth AS VARCHAR (8) = (SELECT FORMAT(DATEADD(month, -1, #dateConverted), 'yyyyMMdd'));
Finally, convert varchar do Date again:
DECLARE #previousMonthConverted AS DATE = (SELECT CONVERT(CHAR(10), CONVERT(date, #previousMonth), 120));

Convert date to SQL datetime

I'm somewhat new to T-SQL and despite reading a number of articles that indicate this should work, I'm having trouble converting October 1st of the current year to a datetime.
I've tried:
SELECT CAST(DATEPART(year, GETDATE()) + '1015' AS DATETIME)
SELECT CONVERT(datetime, 'Oct 15 ' + DATEPART(YEAR,GETDATE()),100)
And all kinds of variations.
Any ideas? I need to set a datetime variable to whatever Oct 1st of the current year is.
What you're trying to is close, but DATEPART returns a number, so the "+" is doing addition, not concatenation.
Try it like this:
SELECT CAST(CAST(DATEPART(year, GETDATE()) AS VARCHAR(4)) + '1015' AS DATETIME)
edit -- Ed beat me to it, and the Concat function is better too.
But if you really wanted to knock it out of the park, try this...
SELECT DATEADD(month, 9, DATEADD(year, DATEDIFF(year, 0, getdate()), 0)) As October1CurrentYear
No casting required!
Your first query is very close. The problem is that the plus sign (+) for concatenation is actually giving you a numeric value, which you can't cast to a date.
To concatenate a year and '1015' and end up with a string, use the CONCAT function instead:
SELECT CAST(CONCAT(DATEPART(YEAR, GETDATE()), '1015') AS DATE)

SSRS : Embed a #Year parameter in a query

I have an SSRS report which uses a #Year parameter, which is chosen by the user at run-time.
Fine, so far, but the SQL in the Data set Properties section contains a hard-coded date of '2010-08-31' , but, the year part of it needs to be the same as the #Year parameter which the user chooses. In other words, if you run the report in the year 2010 the results will be correct, but not if you run it now (in 2014).
The SQL at the moment is (miminum required):
SELECT DateDiff(Year, birth_dt, '2010-08-31')
--Date of Start of Academic Term
FROM table99
WHERE acad_period = #Year
...so my question is, what is the correct syntax for substituting the #Year value in place of '2010'?
EDIT : Please note that the actual format for the year is (eg) 12/13, 13/14
you can replace the line
SELECT DateDiff(Year, birth_dt, '2010-08-31')
with
SELECT DateDiff(Year, birth_dt, #Year+'-08-31')
To do the same with current date
SELECT DateDiff(Year, birth_dt, DATEPART(yyyy, getdate())+'-' + DATEPART(mm, getdate()) +'-'+DATEPART(dd, getdate()))
based on your clarification in comment, if you pass in '12/13' your query would be something like this.
SELECT DATEDIFF(Year, birth_dt, '20'+LEFT(#Year,2) + '-08-31')
FROM table99
WHERE acad_period = #Year
Since your year parameter isn't a simple year value but is instead a string like "13/14" presumably meaning the 2013/2014 school year, I would definitely handle parsing it outside of the query.
Add a computed #TermStart parameter to the dataset with the following formula:
=DateSerial(2000 + CInt(Split(Parameters!Year.Value,"/")(0)),8,31)
(So long as you aren't expecting any dates prior to 2000 of course)
Then you can use the #Year and #TermStart parameters in the query like so:
SELECT DateDiff(Year, birth_dt, #TermStart)
--Date of Start of Academic Term
FROM table99
WHERE acad_period = #Year
But as I mentioned in a comment above, that is not the correct way to calculate age. There are several ways to do that. My favorite is this:
SELECT datediff(hour,birth_dt,#TermStart)/8766
--Date of Start of Academic Term
FROM table99
WHERE acad_period = #Year

Convert only the year part of the datetime in SQL server

Any other easier way to bring the year part of a datetime to current year? If not, which one is better performance wise?
Attempt #1:
CAST(DATEPART(MONTH, mydate) AS VARCHAR) + '/' +
CAST(DATEPART(DAY, mydate) AS VARCHAR) + '/' +
CAST(YEAR(GETDATE()) AS VARCHAR) AS DATETIME
Attempt #2:
DATEADD(YEAR, DATEDIFF(YEAR, mydate, GETDATE()), mydate)
The performance differences are negligible, whichever one is faster. The differences will be in the microsecond range.
I normally use DATEADD + DATEDIFF as a matter of preference. The correct format of the VARCHAR version is to use the ISO-8601 format YYYYMMDD, e.g.
CAST(STUFF(CONVERT(char(8),mydate,112),1,4,YEAR(GETDATE())) as DATETIME)
CONVERT(,,112) => YYYYMMDD. STUFF replaces the first 4 characters with current year. YEAR() returns a number but in the context of STUFF is automatically cast as a varchar.
Don't use your first method. It can create unreliable results.
1/2/2012 can be interpreted as February 1st or January 2nd, depending on settings.
Avoid strings, especially for dates.
Your second method is much more reliable

SQL Server: Get data for only the past year

I am writing a query in which I have to get the data for only the last year. What is the best way to do this?
SELECT ... FROM ... WHERE date > '8/27/2007 12:00:00 AM'
The following adds -1 years to the current date:
SELECT ... From ... WHERE date > DATEADD(year,-1,GETDATE())
I found this page while looking for a solution that would help me select results from a prior calendar year. Most of the results shown above seems return items from the past 365 days, which didn't work for me.
At the same time, it did give me enough direction to solve my needs in the following code - which I'm posting here for any others who have the same need as mine and who may come across this page in searching for a solution.
SELECT .... FROM .... WHERE year(*your date column*) = year(DATEADD(year,-1,getdate()))
Thanks to those above whose solutions helped me arrive at what I needed.
Well, I think something is missing here. User wants to get data from the last year and not from the last 365 days. There is a huge diference. In my opinion, data from the last year is every data from 2007 (if I am in 2008 now). So the right answer would be:
SELECT ... FROM ... WHERE YEAR(DATE) = YEAR(GETDATE()) - 1
Then if you want to restrict this query, you can add some other filter, but always searching in the last year.
SELECT ... FROM ... WHERE YEAR(DATE) = YEAR(GETDATE()) - 1 AND DATE > '05/05/2007'
The most readable, IMO:
SELECT * FROM TABLE WHERE Date >
DATEADD(yy, -1, CONVERT(datetime, CONVERT(varchar, GETDATE(), 101)))
Which:
Gets now's datetime GETDATE() = #8/27/2008 10:23am#
Converts to a string with format 101 CONVERT(varchar, #8/27/2008 10:23am#, 101) = '8/27/2007'
Converts to a datetime CONVERT(datetime, '8/27/2007') = #8/27/2008 12:00AM#
Subtracts 1 year DATEADD(yy, -1, #8/27/2008 12:00AM#) = #8/27/2007 12:00AM#
There's variants with DATEDIFF and DATEADD to get you midnight of today, but they tend to be rather obtuse (though slightly better on performance - not that you'd notice compared to the reads required to fetch the data).
Look up dateadd in BOL
dateadd(yy,-1,getdate())
GETDATE() returns current date and time.
If last year starts in midnight of current day last year (like in original example) you should use something like:
DECLARE #start datetime
SET #start = dbo.getdatewithouttime(DATEADD(year, -1, GETDATE())) -- cut time (hours, minutes, ect.) -- getdatewithouttime() function doesn't exist in MS SQL -- you have to write one
SELECT column1, column2, ..., columnN FROM table WHERE date >= #start
I, like #D.E. White, came here for similar but different reasons than the original question. The original question asks for the last 365 days. #samjudson's answer provides that. #D.E. White's answer returns results for the prior calendar year.
My query is a bit different in that it works for the prior year up to and including the current date:
SELECT .... FROM .... WHERE year(date) > year(DATEADD(year, -2, GETDATE()))
For example, on Feb 17, 2017 this query returns results from 1/1/2016 to 2/17/2017
For some reason none of the results above worked for me.
This selects the last 365 days.
SELECT ... From ... WHERE date BETWEEN CURDATE() - INTERVAL 1 YEAR AND CURDATE()
The other suggestions are good if you have "SQL only".
However I suggest, that - if possible - you calculate the date in your program and insert it as string in the SQL query.
At least for for big tables (i.e. several million rows, maybe combined with joins) that will give you a considerable speed improvement as the optimizer can work with that much better.
argument for DATEADD function :
DATEADD (*datepart* , *number* , *date* )
datepart can be: yy, qq, mm, dy, dd, wk, dw, hh, mi, ss, ms
number is an expression that can be resolved to an int that is added to a datepart of date
date is an expression that can be resolved to a time, date, smalldatetime, datetime, datetime2, or datetimeoffset value.
declare #iMonth int
declare #sYear varchar(4)
declare #sMonth varchar(2)
set #iMonth = 0
while #iMonth > -12
begin
set #sYear = year(DATEADD(month,#iMonth,GETDATE()))
set #sMonth = right('0'+cast(month(DATEADD(month,#iMonth,GETDATE())) as varchar(2)),2)
select #sYear + #sMonth
set #iMonth = #iMonth - 1
end
I had a similar problem but the previous coder only provided the date in mm-yyyy format. My solution is simple but might prove helpful to some (I also wanted to be sure beginning and ending spaces were eliminated):
SELECT ... FROM ....WHERE
CONVERT(datetime,REPLACE(LEFT(LTRIM([MoYr]),2),'-
','')+'/01/'+RIGHT(RTRIM([MoYr]),4)) >= DATEADD(year,-1,GETDATE())
Here's my version.
YEAR(NOW())- 1
Example:
YEAR(c.contractDate) = YEAR(NOW())- 1
For me this worked well
SELECT DATE_ADD(Now(),INTERVAL -2 YEAR);
If you are trying to calculate "rolling" days, you can simplify it by using:
Select ... FROM ... WHERE [DATE] > (GETDATE()-[# of Days])