Why is '-' equal to 0 (zero) in SQL? - sql-server

When you run the following query in SQL Management studio the result will be 1.
SELECT
CASE WHEN '-' = 0 THEN
1
ELSE
0
END
That scares me a bit, because I have to check for 0 value a numerous number of times and it seems it is vulnerable for being equal to value '-'.

You're looking at it the wrong way around.
'-' is a string, so it will get implicitly casted to an integer value when comparing it with an integer:
select cast('-' as int) -- outputs 0
To make sure that you are actually comparing a value to the string '0', make your comparison like this instead:
select case when '-' = '0' then 1 else 0 end
In general, you're asking for trouble when you're comparing values of different data types, since implicit conversions happen behind the scene - so avoid it at all costs.

Related

ASCII Comparisons when Using SQL_Latin1_General_CP1_CI_AS

I ran the query below to see how strings would compare in SQL Server, since a different query based on comparison of fields with this type of data yielded different results than expected. I wasn't sure whether the angle bracket would be considered a lower value than a number (based on the ASCII table it would not, but wanted to check). As a result of the outcome, I've reviewed multiple posts regarding string comparison, collation and expected values and they all seem to reinforce that this should not be working this way. The collation on the database (as on the field that caused trouble) is SQL_Latin1_General_CP1_CI_AS.
SELECT ASCII('<') AS [<]
,ASCII('0') AS [0]
,CASE WHEN '<0.1' < '0.1' THEN 1 ELSE 0 END AS TEST1
,CASE WHEN '<' < '0' THEN 1 ELSE 0 END AS TEST2
,CASE WHEN ASCII('<') < ASCII('0') THEN 1 ELSE 0 END AS TEST3
Result:
< 0 TEST1 TEST2 TEST3
60 48 1 1 0
Any ideas to point me in the right direction would be very much appreciated!

SQL String are same but case equals method returns false

I am using SQL to compare two columns and return TRUE/FALSE if they are equal.
In some cases, the two columns contain exactly the same string (no spaces or anything) but I am still getting false.
What may the reason for this be?
I am using this code:
CASE WHEN column1 = column2 THEN 0 ELSE 1 END AS [check]
The values are different despite the displayed value.
Using T-SQL, run a query like this to see the exact difference in the underlying raw values:
SELECT
column1
, CAST(column1 AS varbinary(MAX)) AS column1Binary
, column2
, CAST(column2 AS varbinary(MAX)) AS column2Binary
FROM dbo.YourTable;
This will reveal underlying differences like tabs or subtle character differences.
In fact, a likely explanation for what you are seeing is that one/both of the strings has leading and/or trailing whitespace. On SQL Server you may try:
CASE WHEN LTRIM(column1) = LTRIM(column2) THEN 0 ELSE 1 END AS [check]
If the above does not detect the problematical records, then try checking the length:
CASE WHEN LEN(column1) = LEN(column2) THEN 0 ELSE 1 END AS [check2]

Is <> 0 condition will Consider Null & 0 as same in SQL

I need to compare variable in case condition in stored procedure.
case when #column <> 0 then ...
ELSE 0 END
but whenever am getting #column as NULL, then the above script returning as 0.
will sql consider both 0 & NULL as same.
Am using sql server 2014.
Thanks All
No. SQL considers NULL as "I have no idea". Comparing anything with "I have no idea" results in an answer of "I totally have no idea". Look:
- How high is John?
- I have no idea.
- What is two centimeters higher than John?
- I have no idea.
Even comparison between two NULL values is not true: if I have no idea how tall John is and if I also have no idea how tall Jack is, I can't conclude that John is equally tall as Jack (and I can't conclude that John is not equally tall as Jack). The only sensible answer is... "I have no idea".
The way to test for NULL is with IS operator, which specifically exists for this scenario (e.g. #column IS NULL, or #column IS NOT NULL).
So NULL is not equal to 0, nor is it NOT equal to 0. The result of NULL <> 0 is NULL. However, NULL is falsy where conditionals are concerned, so CASE thinks you should get the ELSE branch any time #column is NULL.
In case if you want to execute the then part of case if the column value is null, then modify your condition to check for nulls also
CASE WHEN (#column <> 0 OR #column IS NULL) then ...
ELSE 0 END

How do I do decimal arithmetic on two varchars and return result to an aliased column?

I have two fields of type varchar that contain numeric values or blank strings, the latter of which I have filtered out to avoid Divide by Zero errors.
I am attempting to determine the percentage value that num2 represents in relation to num1, i.e. (Num_2 * 1 / Num_1). Relatively simple math.
The problem I am having is that I cannot seem to do the math and then cast it to a decimal value. I keep receiving Arithmetic overflow error converting int to data type numeric errors.
Can someone help me out with the casting issue?
You didn't interpret the error correctly.
It is not about casting the result of your math to float, it is about implicit type casting before the equation is evaluated.
You have in your table some values that cannot be converted to numeric, because they are not valid numbers or numbers out of range. It is enough that one row contains invalid data to make fail the whole query.
perhaps you're looking for something similar to this?
declare #table table (
[numerator] [sysname]
, [denominator] [sysname]);
insert into #table
([numerator],[denominator])
values (N'1',N'2'),
(N'9999999999',N'88888888888');
select case
when isnumeric([numerator]) = 1
and isnumeric ([denominator]) = 1
then
cast([numerator] as [float]) / [denominator]
else
null
end
from #table;
Is this what you're looking for?
select cast('25.5' as decimal(15, 8)) / cast('100.0' as decimal(15, 8))
The example above will return this:
0.25500000000000000000000
In this case, I'm converting the operand types before they get used in the division.
Remember to replace the literals in my query by your field names.
you said that can be number or blank string.
son try something like this:
SELECT
(CASE WHEN NUM_2 = '' THEN 0 ELSE CAST(NUM_2 AS NUMERIC(15,4)) END)
/
(CASE WHEN NUM_1 = '' THEN 1 ELSE CAST(NUM_1 AS NUMERIC(15,4)) END)
you test if string is blank. if it is, you use 0 (or 1, to avoid division by zero)

Overcoming SQL's lack of short-circuit of AND conditions

I'm processing an audit log, and want to ignore entries where a NULL value is changed to zero (or remains NULL). The Old and New values are held in NVARCHAR fields regardless of the type of the fields being logged. In order to CAST a new value to decimal, to determine if it's zero, I need to restrict to cases where ISNUMERIC of the field returns 1.
I've got it to work with this strange bit of SQL - but feel sure there must be a better way.
WHERE MessageDesc LIKE 'poitem%'
AND NOT(OldValue IS NULL AND 0.0 =
CASE
WHEN ISNUMERIC(NewValue) = 1 THEN CAST(NewValue AS DECIMAL(18,4))
WHEN NewValue IS NULL THEN 0.0
ELSE 1.0
END)
Any suggestions?
SQL Server 2012 added a Try_Convert function, which returns NULL if the value cannot be casted as the given type. http://technet.microsoft.com/en-us/library/hh230993.aspx
WHERE NOT (OldValue is Null AND
(NewValue is null OR try_convert(float, NewValue) = 0.0)
)
If using a version prior to 2012, check out Damien_The_Unbeliever's answer here: Check if a varchar is a number (TSQL) ...based on Aaron's comment this will not work in all cases.
Since you are using SQL 2008, then it appears a combination of isnumeric and a modified version of Damien's answer from the link above will work. Your current solution in your question would have problems with values like '.', '-', currency symbols ($, etc.), and scientific notation like '1e4'.
Try this for SQL 2008 (here is SQLFiddle with test cases: http://sqlfiddle.com/#!3/fc838/3 ): Note: this solution will not convert text values to numeric if the text has commas (ex: 1,000) or accounting notation with parens (ex: using "(1)" to represent "-1"), because SQL Server will throw an error when trying to cast to decimal.
WHERE t.OldValue is null
AND
(
t.NewValue is null
OR
0.0 =
case
when isnumeric(t.NewValue) = 1
--Contains only characters that are numeric, negative sign, or decimal place.
--This is b/c isnumeric will return true for currency symbols, scientific notation, or '.'
and not (t.NewValue like '%[^0-9.\-\+]%' escape '\')
--Not other single char values where isnumeric returns true.
and t.NewValue not in ( '.', '-', '+')
then cast(t.NewValue as decimal(18,4))
else null --can't convert to a decimal type
end
)
Avoid ISNUMERIC() since it is problematic with '.'.
-- Dot comes up as valid numeric
select
ISNUMERIC('.') as test1,
ISNUMERIC('1A') as test2,
ISNUMERIC('1') as test3,
ISNUMERIC('A1') as test4
-- Results window (text)
test1 test2 test3 test4
----------- ----------- ----------- -----------
1 0 1 0
Use COALESCE() instead.
WHERE MessageDesc LIKE 'poitem%'
AND
NOT (OldValue IS NULL AND
CAST(COALESCE(NewValue, '0') AS DECIMAL(18,4)) = 0)

Resources