Comparing dates stored as varchar - sql-server

I need to compare dates that are stored in my database as varchar against today's date.
Specifically, I need to exclude any records with a date that has passed.
I tried:
SELECT * FROM tblServiceUsersSchedule
WHERE ScheduleEndDate !='' AND ScheduleEndDate < '2015/05/31'
This selected values such as 17/06/2012 and 19/04/2015, which have both already passed, along with 01/06/2015 which hasn't.
I then tried to cast the data with:
SELECT *
FROM tblServiceUsersSchedule
WHERE CAST(ScheduleEndDate as DATETIME) < CAST('05/31/2015' as DATETIME) AND ScheduleEndDate !='' AND ScheduleEndDate is not null
But got the following error:
The coversion of a varchar data type to a datetime data type resulted
in an out-of-range value.
I checked the data behind and none are null, none are blank white space. All are dates in the format of dd/mm/yyyy.
I can't figure out how to compare the varchar date stored with todays date.

Storing date values as varchar is simply wrong.
If possible, you should alter the table to store them as date data type.
You can do it in a few simple steps:
Rename the current columns (I'm guessing ScheduleStartDate is also varchar) to columnName_old. This can be easily done by using sp_rename.
Use alter table to add the columns with the appropriate data type.
Copy the values from the old columns to the new columns using an update statement. Since all of the dates are stored in the same format, you can use convert like this: set ScheduleStartDate = convert(date, NULLIF(ltrim(rtrim(ScheduleStartDate_old)), ''), 103) If your sql server version is 2012 or higher, use try_convert. Note i've used the nullif, ltrim and rtrim to convert values that only contains white spaces to null.
Drop and recreate indexes that is referencing these columns. The simplest way to do this is by right-clicking the index on SSMS and choose script index as -> drop and create.
Use alter table to remove the old columns.
Note: if these columns are being referenced in any other objects on the database you will have to change these objects as well. This includes stored procedures, foreign keys etc`.
If you can't change the data types of the columns, and your sql server version is lower then 2012, you need to use convert like this:
SELECT * FROM tblServiceUsersSchedule
WHERE CONVERT(DATE, NULLIF(ScheduleEndDate, RTRIM(LTRIM('')), 103)
< CAST(GETDATE() As Date);
AND ScheduleEndDate IS NOT NULL
Note that if you have even a single row where the column's data is not in dd/MM/yyyy format this will raise an error.
For sql server versions 2012 or higher, use Try_convert. This function will simply return null if the conversion fails:
SELECT * FROM tblServiceUsersSchedule
WHERE TRY_CONVERT(DATE, NULLIF(ScheduleEndDate, RTRIM(LTRIM('')), 103)
< CAST(GETDATE() As Date);
AND ScheduleEndDate IS NOT NULL
Note: I've used CAST(GETDATE() as Date) to remove the time part of the current date. This means that you will only get records where the ScheduleEndDate is at least one day old. If you want to also get the records where the ScheduleEndDate is today, use <= instead of <.
One final thing: Using functions on columns in the where clause will prevent Sql Server to use any indexing on these columns.
This is yet another reason why you should change your columns to the appropriate data type.

Other than what people have already suggested that you should never store DATETIME as VARCHAR. Always store it in a DATETIME type column; I think you should change your condition in WHERE
ScheduleEndDate < '2015/05/31'
To this, in order to get all dates which hasn't passed yet
ScheduleEndDate >= '2015/05/31'
Your query should look like
SELECT * FROM tblServiceUsersSchedule
WHERE ScheduleEndDate IS NOT NULL
AND ScheduleEndDate >= '2015/05/31'

If you HAVE TO store your dates as varchar (and as per other other answers, this is a poor practice), then using an ISO style format like yyyy-mm-dd should allow textual comparisons without issue.
If your column is a date data type, and you're using SQL 2012 or later then use DATEFROMPARTS (or one of its variants) for date comparison, so
WHERE DateToCompare < DATEFROMPARTS (2019, 12, 31)
rather than
WHERE DateToCompare < '2019-12-31'
SQL handles the latter fine, but the former is more "correct".

Related

Varchar(255) as MM/DD/YYYY HH:MM to Datetime format - SQL Server

I know there are a million of these date conversion questions, but I can't find the specific one to solve my problem.
I have a table with a column [Date] that contains data that is formatted as MM/DD/YYYY HH:MM, but is stored as a varchar.
[Date] (varchar(255),null)
12/22/2017 0:34
12/21/2017 21:33
12/21/2017 21:17
...
I need to run a query and filter by date range, so I need to figure out how to convert to a usable datetime format.
I've tried
WHERE CONVERT(VARCHAR(255), CAST([Date] AS DATETIME), 121) between #beg1 and #end1
But get the error
The conversion of a varchar data type to a datetime data type resulted in an out-of-range value.
I've tried several other answers, but none were quite formatted the same as my data so the conversions didn't work.
Any help would be greatly appreciated
As many of us have mentioned, to real solution is fix the data type, which means altering the database.
First, to fix the data, you need to change the format to an ISO format, specifically here we're going to do with the ISO8601 format (yyyy-mm-ddThh:mi:ss.mmm). This will require a TRY_CONVERT and CONVERT (the first to change the data to a smalldatetime and the second to the formatted varchar):
UPDATE dbo.YourTable
SET YourDate = CONVERT(varchar(20),TRY_CONVERT(smalldatetime, YourDate, 101), 126);
Now we can alter the data type (to a smalldatetime as your data is accurate to a minute:
ALTER TABLE dbo.YourTable ALTER COLUMN YourDate smalldatetime NULL;
If you "must" leave it at a varchar (this is a bad idea, as your data has so many problems is so), then you need to use TRY_CONVERT in the WHERE, with the correct style code:
WHERE TRY_CONVERT(smalldatetime, YourDate, 101)
This is, however, a really bad idea as your data is severely flawed. For example, according to your data, the "date" '12/22/2017 0:34' is after today ('09/30/2020 21:25'), not before.
The code as you wrote it works fine. You probably have a badly formatted record or record where it is not in a date format. Try code like this to find those records. Any columns with a "NULL" value are ones where the try_cast could not succeed. These are the ones blowing up your query.
You can then choose to correct these values or simply exclude them from your query.
SELECT
[DateText], try_cast([DateText] AS Datetime) FROM Dates

T SQL Conversion failed when converting date and/or time from character string from VARCHAR(MAX)

I'm using SQL Server 2014. I have a date stored as varchar(MAX) in the format of:
2019-02-18
However, I want it in the British format dd/mm/yyyy (103).
This is my SQL:
SELECT CONVERT(DATE, DateField, 103) AS "JobStartDate"
FROM tblTest
However, I keep getting this error:
Conversion failed when converting date and/or time from character string.
What am I missing?
Update: The date is initially stored as varchar max as it is coming from a 3rd party system. I have no control over this and I completly understand this is the wrong format, but this is what I have been given.
I have a date stored as varchar(MAX)
There's your problem right there.
Not only you are using the wrong data type to store dates, you are also using max which is a known performance killer.
The solution to the problem is to alter the table and store dates in a Date data type - but first, you must look up all the objects that depends on that column and make sure they will not break or change them as well.
Assuming this can't be done, or as a temporary workaround, you must first convert the data you have to Date, and then convert it back to a string representation of that date using the 103 style to get dd/mm/yyyy.
Since yyyy-mm-dd string format is not culture dependent with the date data type, you can simply do this:
SELECT CONVERT(char(10), TRY_CAST(DateField As Date), 103) As [JobStartDate]
FROM tblTest
Note I've used try_cast and not cast since the database can't stop you from storing values that can't be converted to dates in that column.
You want to format the DateField column and not convert it to date.
So first convert it to DATE and then apply the format:
SELECT FORMAT(CONVERT(DATE, DateField, 21), 'dd/MM/yyyy') AS JobStartDate
See the demo.

SQL Server date formatting issue

I have a SQL Server 2008 database with a transaction table. There is a field defined as NVARCHAR(16). The data stored is date and time formatted like this:
2016100708593100
I need to write a query that looks at that field and pulls data between two dates
select ... from...where convert(varchar,
convert(datetime,left(a.xact_dati,8)),101)
between '9/29/2016' and '10/05/2016'
I have tried other converts but nothing returns any data. If I use >=getdate()-1
I get data so I should be seeing something returned. Any suggestions?
Replace WHERE Clause with
... WHERE CONVERT(DATETIME,LEFT(a.xact_dati,8)) BETWEEN '9/29/2016' AND '10/05/2016'
Assuming YMD order just
where cast(left('2016100708593100', 8) as date) between '20160929' and '20161005'
Note this clause is not satisfied.
The problem is you're trying to do a date comparison with varchar data.
You go half way to converting the initial value to datetime but then back to varchar.
You could rely on Sql to implicitly convert the between parameters to datetime.
select 'matched',convert(datetime,left('2016100708593100',8),112)
where convert(datetime,left('2016100708593100',8),112) between '2016/09/29' and '2016/10/10'
Take the date part of the string and CAST it as DATE and then compare it with the proper date format.
select ... from...
where cast(left('2016100708593100', 8) as date) between '2016-09-29' and '2016-10-10'
a very straight and fast approach could be to keep this in BIGINT
Something like this:
cast(left(a.xact_dati,8) as bigint) between 20160929 and 20161005
But anyway this will not be sargable and therefore cannot use an index.
You might even stick to varchar, as the YYYYMMDD format is safe with alphanumerical sorting. Cutting a string with LEFT is sargable (AFAIK):
left(a.xact_dati,8) between '20160929' and '20161005'

What should be a default datetime value?

I am inserting Excel Sheet records in my DataTable in c# and passing this DataTable to an SQL stored procedure. In my c# code I have put certain checks for empty data cells of Excel sheet to avoid Exceptions. But It seems like I am missing something while giving a default value for my SQL Date field.
string InvoiceDate = (row.Cells[3].Text == " ") ? "0/00/0000 00:00:00 AM" : (row.Cells[3].Text);
And I get the following error:
String was not recognized as a valid DateTime.Couldn't store
<0/00/0000 00:00:00 AM> in InvoiceDate Column. Expected type is
DateTime.
Edited -
Declaration of SQL field [InvoiceDate]
[InvoiceDate] [date] NOT NULL
Please don't suggest inserting null as I cannot Insert null for this column.
First, There is no 00/00/0000 date, not in the real world and not in sql server.
Second, why do you even need a default values? just use null instead.
Third, use ISO 8601 format for specifying dates in strings (yyyy-mm-ddThh:mm:ss)
Forth, As Giorgi rightfully pointed out in his comment, why even use strings for a datetime value? use a variable of type DateTime in c#. note that it's min value is different then the sql server DateTime data type min value.
If your datetime column is not nullable, you can use 1753-01-01 (min value for datetime) or 9999-12-31 (max value for datetime)
One last thing, you might want to consider using either datetime2 or separate the date and time to different columns (data types date and time, of course). Why? read here.
Try to insert the current date instead:
string InvoiceDate = string.IsNullOrEmpty(row.Cells[3].Text) ? DateTime.Now.ToString() : (row.Cells[3].Text);

How to set date format for the result of a SELECT statement in SQL Server

I know how to use CONVERT function in SELECT statement to change the format of the Date column:
SELECT
StationID
, CONVERT(varchar, [Date], 101) as Date
, Value
FROM my_table
But I was wondering if I can set the date format in general before running the SELECT statement, when I don't know the name of the date column in the following SELECT statement:
SELECT * from FROM my_table
Is any SET statement or other T-SQL that I can run before my SELECT statement so that I can change the Date format temporarily?
Thank you
No.
In particular, any date columns which you select are not actually formatted at all, but are instead returned down the wire as an actual piece of date data in a binary "format" which is used for dates. If you are seeing them formatted, it's because your client (either management studio or some other tool) is converting them to strings to display.
When you use SELECT *, there is obviously no way to tell SQL Server to do any conversions on any particular columns, so the data is going to be returned in whatever the data types of the underlying query returns. So regardless of whether your data types are really date or not, no manipulation is going to happen at that point anyway.
I'm pretty sure there's no way to do what you're asking. However, there are ways to format the date string when you output it using your programming language.

Resources