SQL Server: Compare two columns - sql

I have two columns in a SQL table as follow. I need to compare these two columns for mismatches but due to extra decimals i am getting false results. When i try to convert the first column it gives the error
"Error converting data type varchar to numeric."
How to solve this issue? The length of first column varies.
Column01(varchar) Column02(Decimal)
0.01 0.010000
0.255 0.255000

You have data in Column01 that cannot be casted to DECIMAL.
With SQL Server 2012+ I would use TRY_PARSE:
SELECT *
FROM your_table
WHERE Column02 = TRY_PARSE(Column01 AS DECIMAL(38,18));
LiveDemo
When value from column cannot be casted safely you get NULL.
For SQL Server 2008 you can use:
SELECT *
FROM #tab
WHERE (CASE
WHEN ISNUMERIC(Column01) = 1 THEN CAST(Column01 AS DECIMAL(38,18))
ELSE NULL
END) = Column02;
EDIT:
If you need it at column level use:
SELECT Column01, Column02,
CASE WHEN Column02 = TRY_PARSE(Column01 AS DECIMAL(38,18))
OR (Column02 IS NULL AND Column01 IS NULL)
THEN 'true'
ELSE 'false'
END AS [IsEqual]
FROM #tab;
LiveDemo2

You can do this using self join and conversion function
SELECT x.Column01, y.Column02
FROM table1 x, table1 y
WHERE x.Column02 = try_parse(y.Column01 as decimal(38,18))
Since I cannot comment, I like to thank lad2025 for showing live demo and introducing to data.stackexchange for composing queries

One other way of doing it:
create table #temp(col1 varchar(10),col2 decimal(10,6))
insert into #temp values(0.01,0.010000 ),(0.255,0.255000),(0.25,25),(0.555,10.0)
select * from #temp where REPLACE(REPLACE(col2,col1,''),0,'') = ''
select * from #temp where REPLACE(REPLACE(col2,col1,''),0,'') <> ''

Related

Converting varchar to int (a strange case?)

I have scoured through all "Varchar to Int" posts but can't seem to find anyone with this issue (although, I am fairly new to SQL so I may be doing something fundamentally wrong):
SELECT *
FROM [TABLE]
WHERE CONVERT(INT,
CASE
WHEN NOT CONVERT(VARCHAR(12), dept_code) LIKE '%[^0-9]%' THEN 8900
END) < 9000;
It's a fairly simple query, where the goal is to filter out all the values in field "dept_code" so that only fully numeric values less than 9000 are kept; varchars and non-numeric values are fine to stay. When running the above I still get the error "Conversion failed when converting the varchar value 'E103' to data type int."
Any help would be appreciated.
You can simply this query by avoiding CASE and Regex like expression. You can use IsNumeric function to filter numeric rows and then apply the condition by converting dept_code of filtered rows to int, like below -
select * from tablex
where ISNUMERIC(dept_code) = 0 --alphanumeric code
OR(ISNUMERIC(dept_code) = 1 and Convert(int, dept_code) < 9000) -- numeric less than 9000
Example here
Use try_convert() or try_cast():
SELECT t.*
FROM [TABLE] t
WHERE TRY_CONVERT(int, dept_code) < 9000
If you want to speed this query, you can materialize a computed column and add an index:
alter table [table] add dept_code_int as (try_convert(int, dept_code)) persisted;
create index idx_table_dept_code_int on [table](dept_code_int);
You are missing an else in your case statement ... Secondly do your numeric dept_codes get to be really big ... this thing will choke on that.
SELECT *
FROM [TABLE]
WHERE CONVERT(INT,
CASE
WHEN NOT CONVERT(VARCHAR(12), dept_code) LIKE '%[^0-9]%' THEN 8900 ELSE dept_code
END) < 9000;
Try this: http://sqlfiddle.com/#!18/bb6b7/17
;WITH TABLE_ENHANCED AS
(
SELECT
t.*
, dept_code_numeric =
CASE
WHEN CONVERT(VARCHAR(12), dept_code) NOT LIKE '%[^0-9]%'
THEN CONVERT(INT, dept_code)
ELSE 0
END
FROM [TABLE] t
)
SELECT
*
FROM TABLE_ENHANCED
WHERE dept_code_numeric < 9000
Try below Script
SELECT *
FROM [TABLE]
WHERE isnumeric(dept_code)=1
and dept_code<9000;
This should work. The conversion to int is implicit.
SELECT *
FROM test
WHERE (ISNUMERIC(dept_code)=1 and dept_code<9000)
or (ISNUMERIC(dept_code) = 0)

Error converting data type varchar to numeric. When try to compare numeric

I got a error when i am trying to execute below query. can anyone sort out this would appreciated.
DECLARE #TABLE TABLE(ID INT,CATEGORY VARCHAR(30),VALUE VARCHAR(30))
INSERT INTO #TABLE
SELECT 1,'A','5'
UNION ALL
SELECT 2,'B','6'
UNION ALL
SELECT 3,'C','VAL'
UNION ALL
SELECT 4,'D','HSD'
DECLARE #TABLE1 TABLE(ID INT,CATEGORY VARCHAR(30),VALUE VARCHAR(30))
INSERT INTO #TABLE1
SELECT 1,'A','5.0'
UNION ALL
SELECT 2,'B','6.0'
UNION ALL
SELECT 3,'C','VAL'
UNION ALL
SELECT 4,'D','HSD'
SELECT
A.ID,
A.CATEGORY,
A.VALUE
FROM #TABLE A, #TABLE1 B
WHERE
CASE ISNUMERIC(A.VALUE) WHEN 1 THEN CAST (A.VALUE AS NUMERIC)
ELSE A.VALUE END=CASE ISNUMERIC(B.VALUE) WHEN 1
THEN CAST (B.VALUE AS NUMERIC) ELSE B.VALUE END
I believe the error you are getting is being caused by that your CASE expressions in the WHERE clause have branches with different types, namely text and numeric. To fix this, you need to make all branches be the same type. Making everything numeric won't work because of the text, but we can make everything text instead.
For the case of numeric data, you don't even have the same type of data there either. To get around this, you can cast the numeric data to a common decimal format before converting back again to text:
WHERE
CASE WHEN ISNUMERIC(A.VALUE) = 1
THEN CONVERT(VARCHAR, CAST(A.VALUE AS DECIMAL(10,2)))
ELSE A.VALUE END =
CASE WHEN ISNUMERIC(B.VALUE) = 1
THEN CONVERT(VARCHAR, CAST(B.VALUE AS DECIMAL(10,2)))
ELSE B.VALUE END
The best long term solution for you would be to not mix text and numeric data in the same column. I don't know why this answer was downvoted, as it is working code which answers the original question.
Output:
Demo here:
Rextester
One Columns can only be one type..
You can't put two type "NUMERIC" and "varchar(30)" in one column...
Best way is cast to one type. Seems varchar(30) is a better choice.
SELECT
A.ID,
A.CATEGORY,
A.VALUE
FROM #TABLE A, #TABLE1 B
WHERE
ISNUMERIC(A.VALUE) = ISNUMERIC(B.VALUE)
and
CASE ISNUMERIC(A.VALUE) WHEN 1 THEN CAST(CAST(A.VALUE AS NUMERIC) as VARCHAR(30)) ELSE A.VALUE END
= CASE ISNUMERIC(B.VALUE) WHEN 1 THEN cast(CAST(B.VALUE AS NUMERIC) as VARCHAR(30)) ELSE B.VALUE END

converting varchar to Int SQL SERVER

I needed help with something I am not entirely sure how to resolve.
This is my code :
SELECT DISTINCT
Nr_of_Times_Cust_No_Appears=CASE WHEN CAST(a.TV_Code AS Int)-CAST(BB_Code AS Int)=0 THEN COUNT(*) OVER (PARTITION BY BB_Code) ELSE 'Not same' END
FROM table
Basically, the above code is meant to make sure that the substraction of TV Code and BB Code is Zero(0) if not then 'Not Same'. TV Code and BB Code are both varchar that are CAST to Int. The problem lies in the ELSE ' NOT SAME'.
This is the output I get from SQL SERVER Management Studio:
Conversion failed when converting the varchar value 'Not same' to data type int.
What should I do to make it work?
UPDATE: I finally found the workaround.
CAST(COUNT(*) OVER (PARTITION BY XX) AS Varchar)..... It worked!!!!
This is happening because the output of your CASE statement is returning count() (an integer) from THEN 'Not same' (a string) from the ELSE. They need to be the same types. If you cast your count() to a string you will be fine.
SELECT DISTINCT Nr_of_Times_Cust_No_Appears=
CASE WHEN CAST(a.TV_Code AS Int)-CAST(BB_Code AS Int)=0
THEN CAST(COUNT(*) OVER (PARTITION BY BB_Code) AS VARCHAR)
ELSE 'Not same'
END
FROM table
Alternative:
SELECT DISTINCT Nr_of_Times_Cust_No_Appears=
CASE WHEN CAST(a.TV_Code AS Int)-CAST(BB_Code AS Int)=0
THEN COUNT(*) OVER (PARTITION BY BB_Code)
ELSE -1
END
FROM table
In the consuming code i.e. User Interface, if Nr_of_Times_Cust_No_Appears < 0 then show 'Not same'!
The error is simply occurring as your destination column can only have one data type.
The first part of your CASE statement is effictively setting the column type to expect an integer, so when you hit the ELSE section and try to insert Not Same, you're getting the error.
Sample:
SELECT Num
INTO #T
FROM ( SELECT '1' AS Num
UNION
SELECT '2'
) AS val
SELECT CASE WHEN Num = '1' THEN CAST(Num AS INT)
ELSE 'Not 1'
END AS OutputVal
FROM #T
DROP TABLE #T
Gives you:
Conversion failed when converting the varchar value 'Not 1' to data type int.
So you need to insert an acceptable value, which could be NULL:
Sample:
SELECT Num
INTO #T
FROM ( SELECT '1' AS Num
UNION
SELECT '2'
) AS val
SELECT CASE WHEN Num = '1' THEN CAST(Num AS INT)
ELSE NULL
END AS OutputVal
FROM #T
DROP TABLE #T
Check variable Nr_of_Times_Cust_No_Appears. It seems to be int, but you try to set it 'Not same'.

SQL Server AVG function to return NULL if all values are NULL

I have a table similar to this
+--+-----+----+
|ID|Entry|Exit|
+--+-----+----+
|18|32154|NULL|
+--+-----+----+
|19|NULL |NULL|
+--+-----+----+
When I select AVG(Entry) it correctly gives me 32154, when I select AVG(Exit) it blows up saying "Operand data type void type is invalid for avg operator."
How can I get NULL as the average for a column that only has NULL values?
Thanks,
Try using CASE like this
SELECT CASE WHEN SUM(Exit) IS NULL THEN NULL ELSE AVG(Exit) END AS MyAverage
FROM MyTable
I think The problem is with the column name. Just change the column name to ExitCol and check.
In that case even SELECT AVG(ExitCol) AS MyAverage FROM MyTable also will work
The problem is that the Exit column doesn't have a data type that is compatible with the SUM function.
You can run this query to see that you indeed get NULL from SUM if all values are NULL (and a proper data type)
select sum(a) from (select convert(int, null) a union select null) a
Select avg(isnull(Exit,0)) from table
use set xact_abort off to get it to return null
declare #a table (id int, amount numeric(10,2))
insert into #a values (1, null), (2,null), (3,null)
set xact_abort off
select AVG(amount)
from #a

sql like operator to get the numbers only

This is I think a simple problem but not getting the solution yet. I would like to get the valid numbers only from a column as explained here.
Lets say we have a varchar column with following values
ABC
Italy
Apple
234.62
2:234:43:22
France
6435.23
2
Lions
Here the problem is to select numbers only
select * from tbl where answer like '%[0-9]%' would have done it but it returns
234.62
2:234:43:22
6435.23
2
Here, obviously, 2:234:43:22 is not desired as it is not valid number.
The desired result is
234.62
6435.23
2
Is there a way to do this?
You can use the following to only include valid characters:
SQL
SELECT * FROM #Table
WHERE Col NOT LIKE '%[^0-9.]%'
Results
Col
---------
234.62
6435.23
2
You can try this
ISNUMERIC (Transact-SQL)
ISNUMERIC returns 1 when the input
expression evaluates to a valid
numeric data type; otherwise it
returns 0.
DECLARE #Table TABLE(
Col VARCHAR(50)
)
INSERT INTO #Table SELECT 'ABC'
INSERT INTO #Table SELECT 'Italy'
INSERT INTO #Table SELECT 'Apple'
INSERT INTO #Table SELECT '234.62'
INSERT INTO #Table SELECT '2:234:43:22'
INSERT INTO #Table SELECT 'France'
INSERT INTO #Table SELECT '6435.23'
INSERT INTO #Table SELECT '2'
INSERT INTO #Table SELECT 'Lions'
SELECT *
FROM #Table
WHERE ISNUMERIC(Col) = 1
Try something like this - it works for the cases you have mentioned.
select * from tbl
where answer like '%[0-9]%'
and answer not like '%[:]%'
and answer not like '%[A-Z]%'
With SQL 2012 and later, you could use TRY_CAST/TRY_CONVERT to try converting to a numeric type, e.g. TRY_CAST(answer AS float) IS NOT NULL -- note though that this will match scientific notation too (1+E34). (If you use decimal, then scientific notation won't match)
what might get you where you want in plain SQL92:
select * from tbl where lower(answer) = upper(answer)
or, if you also want to be robust for leading/trailing spaces:
select * from tbl where lower(answer) = trim(upper(answer))