SQL Server 2008 inconsistent results when converting datetime to varchar - sql-server

I have a table with two datetime columns and I'm trying to convert them to an iso string format using the following query:
select
CONVERT(VARCHAR(23), date1, 126) as date1,
CONVERT(VARCHAR(23), date2, 126) as date2
from
some_table
But I'm getting two different results, one with milliseconds and one without
date1 date2
2015-03-11T05:16:04.663 2015-03-11T05:15:43
I've looked at the create table script and they are both defined as datetime. I have no clue how the data is being inserted.
How can I get both columns to return with milliseconds ?

SQL Server "helpfully" will trim the milliseconds portion if it's entirely 0. If you need the 0 milliseconds included (I can't imagine what you're doing where you need .000 to be included) then you'll have to detect the trimming and re-add them:
;With Converted as (
--Your existing query. For this example, I'm just using one date:
select CONVERT(varchar(23),CONVERT(datetime,'2015-03-01T05:15:43.000'),126) as date2
)
select
CASE
WHEN LEN(date2) = 19 THEN date2 + '.000'
ELSE date2
END as date2
from Converted
(And, again if for some bizarre reason you really need the end result to be a varchar(23) rather than a varchar(27) you'll have to add another CONVERT that wraps the CASE expression because the system's not smart enough to realise that any value that the CASE returns could always fit in a varchar(23))

It is becouse the second date has 0 ms.
CREATE TABLE #Test ( date1 datetime, date2 datetime)
INSERT INTO #Test VALUES ('2015-03-11 05:16:04.663','2015-03-11 05:15:43' )
INSERT INTO #Test VALUES ('2015-03-11 05:16:04','2015-03-11 05:15:43.55' )
select
CONVERT(VARCHAR(23), date1, 126) as date1,
CONVERT(VARCHAR(23), date2, 126) as date2
from
#Test
Check this example.

Related

Return new date string in the same format as input

I've got two columns: varchar column InputValue with input dates (all strings pass IsDate(InputValue)=1 validation) and datetime column NewDate with new dates. How do I return new dates as a string in the same format as in input dates? Example (I need OutputValue to contain NewDate value and be formatted the same way as InputValue):
InputValue NewDate OutputValue
(varchar) (datetime) (varchar)
20010101 02/02/2002 20020202
01-01-2000 12/25/2001 12-25-2001
Aug 12 2012 11/15/2000 Nov 15 2000
Is there any way to find out the style of the input date, so I can just use CONVERT(varchar, NewDate, #inputStyle)? Or maybe you have any custom code to get as close to the result as possible?
Thank you!
You can use TRY_CONVERT to attempt a conversion using a variety of styles, then convert the value back and compare it to see if the style matches. See also the documentation.
DECLARE #T TABLE (InputValue varchar(30), NewDate date, ExpectedValue varchar(30));
INSERT INTO #T VALUES
('20010101', '02/02/2002', '20020202'),
('01-01-2000', '12/25/2001', '12-25-2001'),
('Aug 12 2012', '11/15/2000', 'Nov 15 2000');
SELECT *,
OutputValue = (
SELECT TOP (1)
OutputValue = CONVERT(varchar(30), t.NewDate, v.style)
FROM (VALUES
(0),(110),(112)
) v(style)
WHERE t.InputValue = CONVERT(varchar(30), TRY_CONVERT(date, t.InputValue, v.style), v.style)
)
FROM #T t;
I've only added three styles. You can add all of them if you think they may be relevant
FROM (VALUES
(0),(1),(2),(3),(4),(5),(6),(7),(8),(24),(10),(11),(12),(13),(14),(20),(21),(22),(100),(101),(102),(103),(104),(105),(106),(107),(108),(9),(110),(111),(112),(113),(114),(120),(25),(121),(23),(126),(127),(130),(131)
) v(style)
It goes without saying that this type of table design is really bad.
Well, it would be quite an undertaking to write rules for all possible date formats, but if you just wanted those and for reasons that are your own entirely, it could be done with iif functions:
DECLARE #T TABLE (InputValue varchar(20), NewDate date, OutputValue varchar(20))
INSERT INTO #T SELECT '20010101', '02/02/2002', '20020202'
INSERT INTO #T SELECT '01-01-2000', '12/25/2001', '12-25-2001'
INSERT INTO #T SELECT 'Aug 12 2012', '11/15/2000', 'Nov 15 2000'
select InputValue
, NewDate
, OutputValue
, iif(len(InputValue) = 8, convert(varchar(20), NewDate, 112)
, iif(InputValue LIKE '[A-Za-z]%', convert(varchar(20), NewDate, 107)
, convert(varchar(20), NewDate, 32))) derived
from #t

SQL Server query where condition

We are using the below SQL fragment in the where condition of a SQL Server stored procedure:
convert(varchar, CreateDate, 101) <= convert(varchar, GETDATE() - #numberofdays, 101)
Datatype of CreateDate is datetime
Datatype of #numberofdays is int
Can you please confirm if this condition will work fine or it can fail in any scenario as the datatypes are converted to varchar before comparing dates?
CreateDate <= DATEADD(day,-1*#numberofdays,GETDATE())
Yes it will work.
See below queries
declare #numberofdays int
set #numberofdays=3
declare #CreateDate datetime
set #CreateDate= '2017-03-20'
select
convert(varchar,#CreateDate, 101) as date1,
convert(varchar,GETDATE()- #numberofdays,101) as date2
output from them is
date1 date2
03/20/2017 10/08/2017
Which is in same format and will work
working demo

Convert a varchar variable to a datetime variable

I have a data with a few columns. One of them (Col1) is a varchar variable.
I'll give a sample of a few values :
Col1:
'2013-01-01 00:00:00:000'
NULL
'2013-01-01 00:00:00:000'
I'n the design I'm trying to change the data type from a varchar variable into a datetime variable and it throws me an error:
"Unable to modify table. conversion failed when converting date and/or time from a character string".
Any suggestions to remove the problem?
You have to convert the varchar to datetime. You can use cast or convert function. You should store your date value in a proper format in your varchar column.
I assume you are using SQL server 2012.
Try like this,
DECLARE #d TABLE (col1 VARCHAR(50))
INSERT INTO #d
VALUES ('2013-01-01 00:00:00:000')
,(NULL)
,('2013-01-01 00:00:00:000')
SELECT convert(DATETIME, Col1) AS DATE
In case the above query returns error then you can use try_convert function.
(this would ignore your bad format data) Note: You should take necessary action to your bad data.
SELECT try_convert(DATETIME, Col1) AS DATE
FROM #d
FROM #d
You can use ISDATE() to filter the date columns and simply CAST the column.
In the MSDN it describes as
Returns 1 if the expression is a valid date, time, or datetime value; otherwise, 0.
Sample execution with given data:
DECLARE #TestTable TABLE (Col1 VARCHAR(50))
INSERT INTO #TestTable (Col1) VALUES
('2013-01-01 00:00:00:000'),
(NULL),
('2013-01-01 00:00:00:000');
SELECT CAST(Col1 AS DATETIME)
FROM #TestTable
WHERE ISDATE(Col1) = 1
Output:
Col1
------------------------
2013-01-01 00:00:00:000
2013-01-01 00:00:00:000
Hi #Jordan1200 as suggested above the following should be a quick and simple fix;
CAST(Col1 AS DATETIME) AS Col1

CONVERT on only NOT NULL records

I am working in SQL Server 2008. I have a table with two columns that store date values, but the columns themselves are varchar. (I know, this is bad practice, but I don't own the table.) Some of the records in these two columns are NULL. I am trying to do a comparison of the two columns against each other. So, to enable the comparison, I need to do a CONVERT. But, CONVERT fails when it encounters NULLs. How do I essentially prevent the CONVERT from happening when it encounters a NULL? My core query is as follows:
SELECT
col1
FROM table_a
WHERE
CONVERT(date, col2, 101) > CONVERT(date, col3, 101)
I tried an inner query with an IN clause (i.e., the inner query returns only non-NULL records), but this failed because it seems that the query optimizer runs both queries independently, i.e., it runs the CONVERT on all records, which causes the failure. I also tried a self join (i.e., return only records in the first instance of the table where the records aren't null in the second instance of the table). But, this failed as well because of the same problem in the inner query scenario.
Try this:
SELECT
col1
FROM table_a
WHERE
case
when col2 is null or col3 is null then 0
when CONVERT(date, col2, 101) > CONVERT(date, col3, 101) then 1
end = 1
This method prevents the null strings from being converted (or attempted to be) and lets you decide what else you might want to do if one or the other cols is null.
EDITS: first version contained syntax errors in the case statement - these should be fixed now. Apologies for the hasty typing and not SQLFiddling it.
Try this: (Sample Data Included)
DECLARE #TABLE TABLE
(
SomeText VARCHAR(50),
Date01 VARCHAR(50),
Date02 VARCHAR(50)
)
INSERT INTO #TABLE VALUES('Good Date 01','10/01/2014','12/30/2014')
INSERT INTO #TABLE VALUES('Early Date 01','10/01/2014','12/30/2013')
INSERT INTO #TABLE VALUES('Good Date 02','10/01/2013','10/01/2014')
INSERT INTO #TABLE VALUES('Bad Data 01',NULL,'12/30/2014')
INSERT INTO #TABLE VALUES('Bad Data 02','10/01/2014',NULL)
INSERT INTO #TABLE VALUES('Bad Data 03',NULL,NULL)
SELECT
SomeText,
DATEDIFF(D,CONVERT (DATE, Date01, 101) , CONVERT (DATE, Date02, 101)) AS DELTA
FROM
#TABLE
WHERE
1 = 1
AND ISDATE(Date01) = 1
AND ISDATE(Date02) = 1
and DATEDIFF(D,CONVERT (DATE, Date01, 101) , CONVERT (DATE, Date02, 101)) < 0
The ISDATE(Date01) and ISDATE(Date02) remove missing data points from being attempted by the convert function.
Try
SELECT * FROM #Tmp
WHERE
col2 IS NULL OR col3 IS NULL OR
CONVERT(DATETIME, col2, 101) > CONVERT(DATETIME, col3, 101)
I have tried below query in SQL 2005 its working fine without any error, but it returns all the records without null. Above query return null record too
SELECT * FROM #Tmp WHERE CONVERT(DATETIME, col2, 101) > CONVERT(DATETIME, col3, 101)

date comparison in sql server

I am trying to display records which have their date (I have a column Date in table) 30 days back from today's date. And once it gets displayed I need to make a new record by adding details with Date= today's date..
I tried this:
select * from
paymenthist
where
Date = CONVERT(datetime, CONVERT(varchar, DATEADD(day, -30, GETDATE()), 101))
But all records are getting displayed..
Ok, I admit the way I suggested may be inefficient, but if one is a datetime and the other is a date then I believe this will be more efficient than the >= <= approach because SQL is often not great at utilising indexes for queries like this, and under the covers a datetime is actually a floating point, so for pure efficiency, try this:
CREATE TABLE ##PaymentHistory
(
ID INT IDENTITY,
[Date] DATETIME,
Col1 INT,
Col2 INT
)
INSERT INTO ##PaymentHistory([Date],Col1,Col2)
VALUES(FLOOR(CAST(GETDATE() -29 AS FLOAT) ) ,1,1)
, (FLOOR(CAST(GETDATE() -30 AS FLOAT) ) ,2,2)
, (FLOOR(CAST(GETDATE() -31 AS FLOAT) ) ,3,3)
SET IDENTITY_INSERT ##PaymentHistory ON
INSERT INTO ##PaymentHistory(ID, [Date], Col1, Col2)
SELECT ID, GETDATE(), Col1, Col2
FROM ##PaymentHistory
WHERE CAST(Date AS FLOAT) = FLOOR(CAST(GETDATE() -30 AS FLOAT) )
SET IDENTITY_INSERT ##PaymentHistory OFF
It depends somewhat on the datatype of the date column, but try this.
select * from paymenthist where cast(Date as date) = cast(DATEADD(day, -30, GETDATE()) as date)

Resources