How to subtract one month from a date using SQL Server - sql

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));

Related

New to SQL Server looking for assistance for a datetime conversion

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:

Why does my query return records which doesn't meet the where clause conditions?

I have written a query which returns records with dates that are actually older than the mentioned date.
Declare #DateFrom date
Set #DateFrom= '02/Oct/2019'
SELECT 1, Convert(varchar(11), AppliedDateTime, 106)
FROM [MC_Tenders].[dbo].[AppliedWorks]
Where
Convert(varchar, AppliedDateTime,106) >= Convert(varchar, #DateFrom,106)
Applied dates are saved in table as datetime e.g. 2017-04-25 15:51:25.257
You are doing the comparison as strings rather than dates. Remove the conversion:
SELECT 1, Convert(varchar(11), AppliedDateTime, 106)
FROM [MC_Tenders].[dbo].[AppliedWorks]
WHERE AppliedDateTime >= #DateFrom;
Type 106 is dd mm yyyy. When you compare as strings, the strings are compared, not the dates. With format 106, the days are compared first, so: '18-10-2017' < '25-12-1900' because "1" < "2".
Just to finish Gordon Linoff's thought, your code should look something like this:
SELECT
1
, CAST(AppliedDateTime AS DATE) AS AppliedDate
FROM
[MC_Tenders].[dbo].[AppliedWorks]
WHERE
CAST(AppliedDateTime AS DATE) >= #DateFrom;
Edit: I'm assuming AppliedDateTime is actually stored as a datetime, or some data type other than DATE. The explicit CAST to the DATE type will strip out the time component and allow SQL to just compare the date component to your variable.

How to filter only the date from a string stored in a varchar

Ii have values stored in the SQL Server in the following manner : 02-Jul-12 12:00:00 AM here the time and minutes, seconds can be anything like 02-Jul-12 12:15:52 PM ,02-Jul-12 6:02:12 AM so on.
I want to have a where condition which will omit the time and take the data based on the date like the following where some_Date='02-Jul-12'
How would I do this?
SELECT * FROM whatever WHERE some_Date LIKE '02-Jul-12%';
If you are on SQL2008 or later, you can cast your DATETIME to DATE.
See this post: http://blog.sqlauthority.com/2012/09/12/sql-server-get-date-and-time-from-current-datetime-sql-in-sixty-seconds-025-video/
But in a WHERE-clause it is better to search between dates, like this:
DECLARE #startDate DATETIME = '02-Jul-2012'
DECLARE #endDate DATETIME = DATEADD(DAY, 1, #startDate)
SELECT * FROM [table] WHERE [some_Date] BETWEEN #startDate AND #endDate
SELECT * FROM dbo.tbl_MyTable
WHERE
REPLACE(CONVERT(VARCHAR(9), DateTimeValueColumn, 6), ' ', '-')='02-Jul-12'
or
On chage in code is instead of using getdate function voncert you datestring in datetime format and do compare this follow query will work for you
SELECT * FROM dbo.tbl_MyTable
WHERE
CAST(CONVERT(CHAR(10), DateTimeValueColumn, 102) AS DATE) =
CAST(CONVERT(CHAR(10),GETDATE(),102) AS DATE)
If you are storing dates as characters -- which is not recommended -- you should at least use ISO format: YYYY-MM-DD hh:mm:ss. This makes the date useful for sorting and comparisons ("<" works, ">" works, "between" works as well as equals).
To extract the date, you can then use left(datestr, 10). In your format, you would use:
where left(datestr, 9) = '01-Jan-13'
If you are storing the fields as a datetime or smalldatetime, you may think they are stored as a string. They are not. They are stored as some number of days since some particular date, with day parts stored as fractional days. If you are using SQL Server 2005 or greater, then the best way is:
where cast(datetime as date) = '2013-01-01' -- I recommend ISO formats, even for constants. '20130101' is even better
To select rows with today's date (not time)
select * from myTable where datediff(dd, dateColumn, getdate()) = 0

How do you extract just date from datetime in T-Sql?

I am running a select against a datetime column in SQL Server 2005. I can select only the date from this datetime column?
Best way is:
SELECT DATEADD(day, DATEDIFF(Day, 0, #ADate), 0)
This is because internally, SQL Server stores all dates as two integers, of which the first one is the ****number of days*** since 1 Jan 1900. (the second one is the time portion, stored as the number of seconds since Midnight. (seconds for SmallDateTimes, or milleseconds for DateTimes)
Using the above expression is better because it avoids all conversions, directly reading and accessing that first integer in a dates internal representation without having to perform any processing... the two zeroes in the above expression (which represent 1 Jan 1900), are also directly utilized w/o processing or conversion, because they match the SQL server internal representation of the date 1 jan 1900 exactly as presented (as an integer)..
*NOTE. Actually, the number of date boundaries (midnights) you have to cross to get from the one date to the other.
Yes, by using the convert function. For example:
select getdate(), convert(varchar(10),getdate(),120)
RESULTS:
----------------------- ----------
2010-05-21 13:43:23.117 2010-05-21
You can use the functions:
day(date)
month(date)
year(date)
Also the Datepart() function might be of some use:
http://msdn.microsoft.com/en-us/library/ms174420(SQL.90).aspx
DECLARE #dToday DATETIME
SET #dToday = CONVERT(nvarchar(20), GETDATE(), 101)
SELECT #dToday AS Today
This returns today's date at 12:00am : '2010-05-21 00:00:00.000'
Then you can use the #dToday variable in a query as needed
CONVERT (date, GETUTCDATE())
CONVERT (date, GETDATE())
CONVERT (date, '2022-18-01')
I don't know why the others recommend it with varchar(x) tbh.
https://learn.microsoft.com/de-de/sql/t-sql/functions/getdate-transact-sql

Compare DATETIME and DATE ignoring time portion

I have two tables where column [date] is type of DATETIME2(0).
I have to compare two records only by theirs Date parts (day+month+year), discarding Time parts (hours+minutes+seconds).
How can I do that?
Use the CAST to the new DATE data type in SQL Server 2008 to compare just the date portion:
IF CAST(DateField1 AS DATE) = CAST(DateField2 AS DATE)
A small drawback in Marc's answer is that both datefields have been typecast, meaning you'll be unable to leverage any indexes.
So, if there is a need to write a query that can benefit from an index on a date field, then the following (rather convoluted) approach is necessary.
The indexed datefield (call it DF1) must be untouched by any kind of function.
So you have to compare DF1 to the full range of datetime values for the day of DF2.
That is from the date-part of DF2, to the date-part of the day after DF2.
I.e. (DF1 >= CAST(DF2 AS DATE)) AND (DF1 < DATEADD(dd, 1, CAST(DF2 AS DATE)))
NOTE: It is very important that the comparison is >= (equality allowed) to the date of DF2, and (strictly) < the day after DF2. Also the BETWEEN operator doesn't work because it permits equality on both sides.
PS: Another means of extracting the date only (in older versions of SQL Server) is to use a trick of how the date is represented internally.
Cast the date as a float.
Truncate the fractional part
Cast the value back to a datetime
I.e. CAST(FLOOR(CAST(DF2 AS FLOAT)) AS DATETIME)
Though I upvoted the answer marked as correct. I wanted to touch on a few things for anyone stumbling upon this.
In general, if you're filtering specifically on Date values alone. Microsoft recommends using the language neutral format of ymd or y-m-d.
Note that the form '2007-02-12' is considered language-neutral only
for the data types DATE, DATETIME2, and DATETIMEOFFSET.
To do a date comparison using the aforementioned approach is simple. Consider the following, contrived example.
--112 is ISO format 'YYYYMMDD'
declare #filterDate char(8) = CONVERT(char(8), GETDATE(), 112)
select
*
from
Sales.Orders
where
CONVERT(char(8), OrderDate, 112) = #filterDate
In a perfect world, performing any manipulation to the filtered column should be avoided because this can prevent SQL Server from using indexes efficiently. That said, if the data you're storing is only ever concerned with the date and not time, consider storing as DATETIME with midnight as the time. Because:
When SQL Server converts the literal to the filtered column’s type, it
assumes midnight when a time part isn’t indicated. If you want such a
filter to return all rows from the specified date, you need to ensure
that you store all values with midnight as the time.
Thus, assuming you are only concerned with date, and store your data as such. The above query can be simplified to:
--112 is ISO format 'YYYYMMDD'
declare #filterDate char(8) = CONVERT(char(8), GETDATE(), 112)
select
*
from
Sales.Orders
where
OrderDate = #filterDate
You can try this one
CONVERT(DATE, GETDATE()) = CONVERT(DATE,'2017-11-16 21:57:20.000')
I test that for MS SQL 2014 by following code
select case when CONVERT(DATE, GETDATE()) = CONVERT(DATE,'2017-11-16 21:57:20.000') then 'ok'
else '' end
You may use DateDiff and compare by day.
DateDiff(dd,#date1,#date2) > 0
It means #date2 > #date1
For example :
select DateDiff(dd, '01/01/2021 10:20:00', '02/01/2021 10:20:00')
has the result : 1
For Compare two date like MM/DD/YYYY to MM/DD/YYYY .
Remember First thing column type of Field must be dateTime.
Example : columnName : payment_date dataType : DateTime .
after that you can easily compare it.
Query is :
select * from demo_date where date >= '3/1/2015' and date <= '3/31/2015'.
It very simple ......
It tested it.....