CONVERT on only NOT NULL records - sql-server

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)

Related

Comparing Results From Two Different Queries Based on Common Field

Ok, so I just started working with SQL so please be easy on me if there's a super easy solution that I just don't know. I'm using Microsoft SQL Server. I have two queries that give me results, one being
EXEC ('SELECT ID ,
Type,
Date
FROM DB2T.BBT') AT DB2
and the other being
select
ca.value('(/CA[#name=''ID'']/#value)[1]','VARCHAR(MAX)') as ID,
ca.value('(/CA[#name=''Type'']/#value)[1]', 'VARCHAR(MAX)') as Type,
ca.value('(/CA[#name=''Date'']/#value)[1]', 'VARCHAR(MAX)') as Date,
from log
This is just how I extract the relevant data from the places I need. I end up with two different queries with two different table outputs, each row containing an ID, Type, and Date.
I need to combine these two queries so I can compare the two tables. I need to see, depending on matching IDs from the two queries, if the values for Type and Date are equal. I only want to output IDs that have differing values and then output the differing values with it.
So I have two problems I guess, one being combining the two queries and then doing the comparing. Thanks in advance.
This query will combine the resultsets into one, then group by the ID, Type, and Date columns and pull back which ones don't have two rows (should have one from DB2 and one from SQL). It doesn't tell you exactly what is different but should be pretty easy to tell with that few columns.
SELECT
MIN(System) AS System,
ID,
Type,
Date
FROM (
select
'SQL',
ca.value('(/CA[#name=''ID'']/#value)[1]','VARCHAR(MAX)') as ID,
ca.value('(/CA[#name=''Type'']/#value)[1]', 'VARCHAR(MAX)') as Type,
ca.value('(/CA[#name=''Date'']/#value)[1]', 'VARCHAR(MAX)') as Date,
from log
UNION ALL
SELECT 'DB2', * FROM OPENQUERY([DB2], ''SELECT ID, Type, Date FROM DB2T.BBT'')
) compare
GROUP BY ID, Type, Date
HAVING COUNT(*) <> 2
ORDER BY ID, Type, Date
Basically, break it down into 2 queries. The first one is qry1, the second is qry2. You want to use an inner join, because you only want values where Type and Date are equal. Then, you use a WHERE clause to give you only the records where ID doesn't match.
You may have to put ID in brackets, I can't remember off the top of my head if that's a reserved word or not. I know both Date and Type are reserved words, and that's why I put them in brackets.
SELECT
qry1.ID as ID1,
qry1.[Type] as Type1,
qry1.[Date] as Date1,
qry2.ID as ID2,
qry2.[Type] as Type2,
qry2.[Date] as Date2
FROM
(SELECT ID, Type, Date
FROM DB2T.BBT) as qry1,
INNER JOIN
(select
ca.value('(/CA[#name=''ID'']/#value)[1]','VARCHAR(MAX)') as ID,
ca.value('(/CA[#name=''Type'']/#value)[1]', 'VARCHAR(MAX)') as Type,
ca.value('(/CA[#name=''Date'']/#value)[1]', 'VARCHAR(MAX)') as Date,
from log) as qry2
ON qry1.[Type] = qry2.[Type]
AND qry1.[Date] = qry2.[Date]
WHERE qry1.ID <> qry2.ID
What about comparing computed columns that are hashes of the concatenated column values? Something like this:
declare #t1 table (id int, type varchar(max), dt date, hash_bytes as HASHBYTES('SHA1', CAST(id AS NVARCHAR(MAX)) + CAST(type AS NVARCHAR(MAX)) + CAST(dt AS NVARCHAR(MAX))))
declare #t2 table (id int, type varchar(max), dt date, hash_bytes as HASHBYTES('SHA1', CAST(id AS NVARCHAR(MAX)) + CAST(type AS NVARCHAR(MAX)) + CAST(dt AS NVARCHAR(MAX))))
insert into #t1 values
(1, 'val1', getdate()), -- no match in #t2
(2, 'val2', getdate() + 1),
(3, 'val3', getdate() + 2),
(4, 'val4', getdate() + 3),
(5, 'val5', getdate() + 4)
insert into #t2 values
(2, 'val2', getdate() + 1), -- same
(3, 'val300', getdate() + 2), -- different type
(4, 'val4', getdate() + 300), -- different date
(5, 'val500', getdate() + 400),-- different type & date
(6, 'val6', getdate() + 5) -- no match in #t1
select *
from #t1 t1
full join #t2 t2 on t1.hash_bytes = t2.hash_bytes
id type dt hash_bytes id type dt hash_bytes
1 val1 2018-07-27 0xF53D672F572DC49D15AE2ECD2F3225624073FEB8 NULL NULL NULL NULL
2 val2 2018-07-28 0x8840035CC198447CB1F9D85E97A57F2B08ADB39E 2 val2 2018-07-28 0x8840035CC198447CB1F9D85E97A57F2B08ADB39E
3 val3 2018-07-29 0x372E6A3B48C3C96C2456A514CD9D35CAC4EEEACE NULL NULL NULL NULL
4 val4 2018-07-30 0xE91A2E58D2964BB3BE6BDD1C1ECA3628E956484D NULL NULL NULL NULL
5 val5 2018-07-31 0xB289831856A15334BE60EC4F78502052B15EE4CD NULL NULL NULL NULL
NULL NULL NULL NULL 3 val300 2018-07-29 0x2007D7205352EE65013DC21E527780E1FED763D8
NULL NULL NULL NULL 4 val4 2019-05-23 0x60CC2C7B3902204E82F137401446EB974EC83C3B
NULL NULL NULL NULL 5 val500 2019-08-31 0xFFF8FD045B306B3F1663FC4903CE859A6C9577FB
NULL NULL NULL NULL 6 val6 2018-08-01 0x72407548472D00C87E6DDF42A05E0B1B687AACBA

Update Final SQL Table with Temp Table using select max for Column

Good day all! What I want to do is update FinalTable with a temp table, where the DateStamp Column of The temp table is greater then DateStamp column in the FinalTable
So far I have come up with something like this:
INSERT INTO [dbo].[FinalTable]([DateStamp], [TIME], [DATE], [USER_LOGIN],[USER_NAME], [MODEL_NAME], [SCORECARD_IDENTIFIER], [SCORECARD_NAME],[ELEMENT_IDENTIFIER], [ELEMENT_NAME], [SERIES_IDENTIFIER], [SERIES_NAME],[PERIOD_NAME], [ACTION_TYPE], [ACTION], [PREVIOUS_VALUE], [VALUE], [UNIT])
SELECT
CONVERT(VARCHAR, CONCAT([DATE], ' ' ,[TIME]), 121) AS [DateStamp],
[TIME], [DATE], [USER_LOGIN], [USER_NAME],
[MODEL_NAME], [SCORECARD_IDENTIFIER], [SCORECARD_NAME],
[ELEMENT_IDENTIFIER], [ELEMENT_NAME],
[SERIES_IDENTIFIER], [SERIES_NAME],
[PERIOD_NAME], [ACTION_TYPE], [ACTION],
[PREVIOUS_VALUE], [VALUE], [UNIT]
FROM
#TEMP
WHERE
(SELECT CONVERT(VARCHAR, CONCAT([DATE], ' ' ,[TIME]), 121) AS [DateStamp] FROM #TEMP) > (SELECT MAX([DateStamp]) FROM [Test].[dbo].[FinalTable])
DROP TABLE #TEMP
Unfortunately it gives me an error like this:
Msg 512, Level 16, State 1, Line 17
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
The [DateStamp] column in the temp is being created in the select because I am reading a text file. So initially I want to check the two tables and where the [DateStamp] column value is higher in #Temp then the one in the [FinalTable] just add/insert the new rows into [FinalTable]
If anyone suggests something else do let me know. I'm still a newbie to SQL but I'm trying what I can.
Try this
INSERT INTO [dbo].[FinalTable]([DateStamp],[TIME],[DATE]..)
SELECT convert(varchar,CONCAT([DATE], ' ' ,[TIME]), 121) AS [DateStamp],[TIME],[DATE]
FROM #TEMP T
where convert(varchar,CONCAT(T.[DATE], ' ' ,T.[TIME]), 121) > (Select MAX([DateStamp]) FROM [Test].[dbo].[FinalTable])
Also I do not recommend using varchar while comparing dates
Problem here:
where (SELECT convert(varchar,CONCAT([DATE], ' ' ,[TIME]), 121) AS [DateStamp] FROM #TEMP)
Here is no condition on #TEMP

SQL Server 2008 inconsistent results when converting datetime to varchar

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.

I need to select data from a table according to time.But my table field is datetime

I need to select data from a table according to time.But my table field is datetime.How can i select data from table only depending on time?Can i use only time in where clause?Please reply
Try this one -
DECLARE #temp TABLE
(
Col1 INT
, Col2 DATETIME
)
INSERT INTO #temp (Col1, Col2)
VALUES
(1, '2013-08-29 07:41:43.717'),
(2, '2013-08-29 08:41:50.067')
SELECT *
FROM #temp
WHERE CAST(Col2 AS TIME) BETWEEN '08:00' AND '12:00'
Output -
Col1 Col2
----------- -----------------------
2 2013-08-29 08:41:50.067
You can try this:
SELECT CONVERT(TIME, column) FROM table
column is your datetime column
You can also use CONVERT(TIME, column) in your WHERE-clause.

IsNumeric Time value problem

Table1
Time
10:00:00
12:00:00
Absent
14:00:00
Holiday
...,
Time column Datatype is varchar
I want to check the time column value is numeric then 'Present'
Tried Query
Select case when isnumeric(time) then 'Present' else time end as time from table1
Showing error in 'then'
How to modify my query according to my requirement
Need Query Help
Try using ISDATE
Returns 1 if the expression is a valid
date, time, or datetime value;
otherwise, 0.
Something like
DECLARE #Table TABLE(
[Time] VARCHAR(50)
)
INSERT INTO #Table SELECT '10:00:00'
INSERT INTO #Table SELECT '12:00:00'
INSERT INTO #Table SELECT 'Absent'
INSERT INTO #Table SELECT '14:00:00'
INSERT INTO #Table SELECT 'Holiday'
SELECT *,
ISDATE(Time),
case when ISDATE(time) != 0 then 'Present' else time end
FROM #Table

Resources