SQL SERVER and NULL values on Equal operator - sql-server

I have in a where clause the following statement COLUMN_1 <> 'O'
But the rows that contains NULL on the COLUMN_1 are not take in consideration, it is like they contain the value 'O'
Why is that ?
Thanks in advance.

Because NULL does not equal, nor does not not equal anything, including NULL. NULL <> 'O' evaluates to UNKNOWN; which is specifically not TRUE.
If you want to evaluate with NULL values you need to use IS NULL:
WHERE (COLUMN_1 <> 'O' OR COLUMN_1 IS NULL)
This is also documented on both not-equal operator articles:
Not Equal To (Transact SQL) - traditional
Compares two expressions (a comparison operator). When you compare nonnull expressions, the result is TRUE if the left operand is not equal to the right operand; otherwise, the result is FALSE. If either or both operands are NULL, see the topic SET ANSI_NULLS (Transact-SQL).
Not Equal To (Transact SQL) - exclamation
Tests whether one expression is not equal to another expression (a comparison operator). If either or both operands are NULL, NULL is returned. Functions the same as the <> (Not Equal To) comparison operator.

Related

How do comparison operators like '<' and '>' work for string values?

I have seen that greater than and less than operators can be applied on string values in SQL Server but I haven't figured out yet what logic is being applied here behind the scenes to perform the comparison.
For example, the string value 'Gabriel' is greater than 'Cassandra':
SELECT 1 WHERE 'Gabriel' > 'Cassandra'
The query above returns 1, whereas an empty result set is returned if the comparison operator is changed to '<'.
The comparison is alphabatical, so 'B' is greater than 'A', and 'C' is greater than 'B' and so on.

Math operations with NULL in tsql

Why
select 1 - NULL
returns NULL instead of 1?
It wasn't clearly expected to me.
Null: A value of NULL indicates that the value is unknown. A value of NULL is different from an empty or zero value. No two null values are equal. Comparisons between two null values, or between a NULL and any other value, return unknown because the value of each NULL is unknown.
If you do any arithmetic operations with null the whole expression evaluates to Null. In order to handle null you should use Isnull() or coalesce function like this.
select 1 - isnull(NULL,0) as result
Simply because NULL is not 0.
If it helps, consider NULL as a synonym for "unknown", and then it'll make perfect sense - the result of 1 minus an unknown number can only give an unknown result.
Here are some references on how NULL behaves differently:
NULL can be thought of as UNKNOWN (docs).
Arithmetic operations with NULL result in NULL (wiki).
SUM() operation ignores NULL instead of returning UNKNOWN (docs).
String concatenation with NULL result in NULL (wiki and comment by #Zohar).
Boolean comparisons with NULL use three-value logic (wiki).
Where clauses with NULL should use IS, because boolean comparisons result in UNKNOWN not TRUE (docs).
To determine whether an expression is NULL, use IS NULL or IS NOT NULL instead of comparison operators (such as = or !=). Comparison operators return UNKNOWN when either or both arguments are NULL.

Postgres NOT in array

I'm using Postgres' native array type, and trying to find the records where the ID is not in the array recipient IDs.
I can find where they are IN:
SELECT COUNT(*) FROM messages WHERE (3 = ANY (recipient_ids))
But this doesn't work:
SELECT COUNT(*) FROM messages WHERE (3 != ANY (recipient_ids))
SELECT COUNT(*) FROM messages WHERE (3 = NOT ANY (recipient_ids))
What's the right way to test for this condition?
SELECT COUNT(*) FROM "messages" WHERE NOT (3 = ANY (recipient_ids))
You can always negate WHERE (condition) with WHERE NOT (condition)
You could turn it around a bit and say "3 is not equal to all the IDs":
where 3 != all (recipient_ids)
From the fine manual:
9.21.4. ALL (array)
expression operator ALL (array expression)
The right-hand side is a parenthesized expression, which must yield an array value. The left-hand expression is evaluated and compared to each element of the array using the given operator, which must yield a Boolean result. The result of ALL is "true" if all comparisons yield true (including the case where the array has zero elements). The result is "false" if any false result is found.
Beware of NULLs
Both ALL:
(some_value != ALL(some_array))
And ANY:
NOT (some_value = ANY(some_array))
Would work as long as some_array is not null. If the array might be null, then you must account for it with coalesce(), e.g.
(some_value != ALL(coalesce(some_array, array[]::int[])))
Or
NOT (some_value = ANY(coalesce(some_array, array[]::int[])))
From the docs:
If the array expression yields a null array, the result of ANY will be null
If the array expression yields a null array, the result of ALL will be null
Augmenting the ALL/ANY Answers
I prefer all solutions that use all or any to achieve the result, appreciating the additional notes (e.g. about NULLs). As another augementation, here is a way to think about those operators.
You can think about them as short-circuit operators:
all(array) goes through all the values in the array, comparing each to the reference value using the provided operator. As soon as a comparison yields false, the process ends with false, otherwise true. (Comparable to short-circuit logical and.)
any(array) goes through all the values in the array, comparing each to the reference value using the provided operator. As soon as a comparison yields true, the process ends with true, otherwise false. (Comparable to short-circuit logical or.)
This is why 3 <> any('{1,2,3}') does not yield the desired result: The process compares 3 with 1 for inequality, which is true, and immediately returns true. A single value in the array different from 3 is enough to make the entire condition true. The 3 in the last array position is prob. never used.
3 <> all('{1,2,3}') on the other hand makes sure all values are not equal 3. It will run through all comparisons that yield true up to an element that yields false (the last in this case), to return false as the overall result. This is what the OP wants.
an update:
as of postgres 9.3,
you can use NOT in tandem with the #> (contains operator) to achieve this as well.
IE.
SELECT COUNT(*) FROM "messages" WHERE NOT recipient_ids #> ARRAY[3];
not (3 = any(recipient_ids))?
Note that the ANY/ALL operators will not work with array indexes. If indexes are in mind:
SELECT COUNT(*) FROM "messages" WHERE 3 && recipient_ids
and the negative:
SELECT COUNT(*) FROM "messages" WHERE NOT (3 && recipient_ids)
An index can then be created like:
CREATE INDEX recipient_ids_idx on tableName USING GIN(recipient_ids)
Use the following query
select id from Example where NOT (id = ANY ('{1, 2}'))

Is SQL Server's double checking needed here?

IF #insertedValue IS NOT NULL AND #insertedValue > 0
This logic is in a trigger.
The value comes from a deleted or inserted row (doesn't matter).
2 questions :
Do I need to check both conditions? (I want all value > 0, value in db can be nullable)
Does SQL Server check the expression in the order I wrote it ?
1) Actually, no, since if the #insertedValue is NULL, the expression #insertedValue > 0 will evaulate to false. (Actually, as Martin Smith points out in his comment, it will evaluate to a special value "unknown", which when forced to a Boolean result on its own collapses to false - examples: unknown AND true = unknown which is forced to false, unknown OR true = true.) But you're relying on comparison behaviour with NULL values. A single step equivalent method, BTW, would be:
IF ISNULL(#insertedValue, 0) > 0
IMHO, you're better sticking with the explicit NULL check for clarity if nothing else.
2) Since the query will be optimised before execution, there is absolutely no guarantee of order of execution or short circuiting of the AND operator.
Combining the two - if the double check is truly unnecessary, then it will probably be optimised out before execution anyway, but your SQL code will be more maintainable in my view if you make this explicit.
You can use COALESCE => Returns the first nonnull expression among its arguments.
Now you can make the query more flexible, by increasing the column limits and again you need to check the Greater Then Zero condition. Important point to note down here is you have the option to check values in multiple columns.
declare #val int
set #val = COALESCE( null, 1, 10 )
if(#val>0)
select 'fine'
else
select 'not fine'

gnu C condition of "if"

we got if(expression) {...} for example. We all know if expression is true, it will execute lines in braces. But what is "True" in C?
Is that != 0 means true as I think?
Thank you
Here is what the standard has to say.
§6.8.4 Selection statements
Syntax
selection-statement:
if ( expression ) statement
if ( expression ) statement else statement
switch ( expression ) statement
§6.8.4.1 The if statement
Constraints
The controlling expression of an if statement shall have scalar type.
Semantics
In both forms, the first substatement is executed if the expression compares unequal to 0. In the else form, the second substatement is executed if the expression compares equal to 0. If the first substatement is reached via a label, the second substatement is not executed.
An else is associated with the lexically nearest preceding if that is allowed by the
syntax.
Any none-zero result tests as true.
Yes, true is not-null in C and C++.

Resources