What does this SQL Query mean? - sql

I have the following SQL query:
select AuditStatusId
from dbo.ABC_AuditStatus
where coalesce(AuditFrequency, 0) <> 0
I'm struggling a bit to understand it. It looks pretty simple, and I know what the coalesce operator does (more or less), but dont' seem to get the MEANING.
Without knowing anymore information except the query above, what do you think it means?

select AuditStatusId
from dbo.ABC_AuditStatus
where AuditFrequency <> 0 and AuditFrequency is not null
Note that the use of Coalesce means that it will not be possible to use an index properly to satisfy this query.

COALESCE is the ANSI standard function to deal with NULL values, by returning the first non-NULL value based on the comma delimited list. This:
WHERE COALESCE(AuditFrequency, 0) != 0
..means that if the AuditFrequency column is NULL, convert the value to be zero instead. Otherwise, the AuditFrequency value is returned.
Since the comparison is to not return rows where the AuditFrequency column value is zero, rows where AuditFrequency is NULL will also be ignored by the query.

It looks like it's designed to detect a null AuditFrequency as zero and thus hide those rows.

From what I can see, it checks for fields that aren't 0 or null.

I think it is more accurately described by this:
select AuditStatusId
from dbo.ABC_AuditStatus
where (AuditFrequency IS NOT NULL AND AuditFrequency != 0) OR 0 != 0
I'll admit the last part will never do anything and maybe i'm just being pedantic but to me this more accurately describes your query.

The idea is that it is desireable to express a single search condition using a single expression but it's merely style, a question of taste:
One expression:
WHERE age = COALESCE(#parameter_value, age);
Two expressions:
WHERE (
age = #parameter_value
OR
#parameter_value IS NULL
);
Here's another example:
One expression:
WHERE age BETWEEN 18 AND 65;
Two expressions
WHERE (
age >= 18
AND
age <= 65
);
Personally, I have a strong personal perference for single expressions and find them easier to read... if I am familiar with the pattern used ;) Whether they perform differently is another matter...

Related

Simple where clause condition involving NULL

I have a query that needs to exclude both Null and Blank Values, but for some reason I can't work out this simple logic in my head.
Currently, my code looks like this:
WHERE [Imported] = 0 AND ([Value] IS NOT NULL **OR** [Value] != '')
However, should my code look like this to exclude both condition:
WHERE [Imported] = 0 AND ([Value] IS NOT NULL **AND** [Value] != '')
For some reason I just can't sort this in my head properly. To me it seems like both would work.
In your question you wrote the following:
have a query that needs to exclude both Null and Blank Values
So you have answered yourself, the AND query is the right query:
WHERE [Imported] = 0 AND ([Value] IS NOT NULL AND [Value] != '')
Here is an extract from the ANSI SQL Draft 2003 that I borrowed from this question:
6.3.3.3 Rule evaluation order
[...]
Where the precedence is not determined by the Formats or by
parentheses, effective evaluation of expressions is generally
performed from left to right. However, it is
implementation-dependent whether expressions are actually evaluated left to right, particularly when operands or operators might
cause conditions to be raised or if the results of the expressions
can be determined without completely evaluating all parts of the
expression.
You don't specify what kind of database system you are using but the concept of short-circuit evaluation which is explained in the previous paragraph applies to all major SQL versions (T-SQL, PL/SQL etc...)
Short-circuit evaluation means that once an expression has been successfully evaluated it will immediately exit the condition and stop evaluating the other expressions, applied to your question:
If value is null you want to exit the condition, that's why it should be the first expression (from left to right) but if it isn't null it should also not be empty, so it has to be NOT NULL and NOT EMPTY.
This case is a bit tricky because you cannot have a non empty string that is also null so the OR condition will also work but you will do an extra evaluation because short-circuit evaluation will never exit in the first expression:
Value is null but we would always need to check that value is also not an empty string (value is null or value is not an empty string).
In this second case, you may get an exception because the expression [Value] != '' may be checked on a null object.
So I think AND is the right answer. Hope it helps.
If the value was numeric and you didn't want either 1 or 2, you would write that condition as
... WHERE value != 1 AND value != 2
An OR would always be true in this case. For instance a value of 1 would return true for the check against 2 - and then the OR-check would return true, as at least one of the conditions evaluated to true.
When yu also want to check against null values, the situation is a bit more complicated. A check against a null value always fails: value != '' is false when value is null. That is why there is a special IS NULL or IS NOT NULL test.

Avoid division by zero in PostgreSQL

I'd like to perform division in a SELECT clause. When I join some tables and use aggregate function I often have either null or zero values as the dividers. As for now I only come up with this method of avoiding the division by zero and null values.
(CASE(COALESCE(COUNT(column_name),1)) WHEN 0 THEN 1
ELSE (COALESCE(COUNT(column_name),1)) END)
I wonder if there is a better way of doing this?
You can use NULLIF function e.g.
something/NULLIF(column_name,0)
If the value of column_name is 0 - result of entire expression will be NULL
Since count() never returns NULL (unlike other aggregate functions), you only have to catch the 0 case (which is the only problematic case anyway). So, your query simplified:
CASE count(column_name)
WHEN 0 THEN 1
ELSE count(column_name)
END
Or simpler, yet, with NULLIF(), like Yuriy provided.
Quoting the manual about aggregate functions:
It should be noted that except for count, these functions return a
null value when no rows are selected.
I realize this is an old question, but another solution would be to make use of the greatest function:
greatest( count(column_name), 1 ) -- NULL and 0 are valid argument values
Note:
My preference would be to either return a NULL, as in Erwin and Yuriy's answer, or to solve this logically by detecting the value is 0 before the division operation, and returning 0. Otherwise, the data may be misrepresented by using 1.
Another solution avoiding division by zero, replacing to 1
select column + (column = 0)::integer;
If you want the divider to be 1 when the count is zero:
count(column_name) + 1 * (count(column_name) = 0)::integer
The cast from true to integer is 1.

Oracle sql null value is not selected

In NAME table FIRST column is having null but no rows are selected. Please help me to understand.
SELECT * FROM NAME WHERE FIRST != '1'
Any comparison with null is false - = and <>, >, <, and so on. You cannot use null in an IN list as well - it would be ignored. Moreover, two nulls are not even equal to each other.
To get the nulls, you need to ask for them explicitly, like this:
SELECT * FROM NAME WHERE FIRST IS NULL OR FIRST != '1'
Any comparison to NULL returns NULL, which is equivalent to FALSE. This is true eve of not-equals.
If you want to include NULL values, do one of the following:
where first <> '1' or first is null
or
where coalesce(first, '<null>') <> '1'
In Oracle, null is not considered a legal value to select unless you explicitly ask for it:
select * from name where (first != '1') or first is null
You could also use NVL (similar to coalesce):
select * from name where nvl(first,'0') != '1'
That is correct because NULL can never be compared with anything else....
The only option that you have is to include a NULL check as an or in the command
SELECT * FROM NAME WHERE FIRST!=1 OR FIRST IS NULL
According to Oracle Documentation NULL is defined as a value not knownm or when the value is not meaningful. That is solely the reason why Oracle mentions not consider a value of ZERO as NULL. This is just an FYI, an addon. Thanks!
NULL is dumb. Period.
NULL is evil.
If X is NULL and Y is NULL, then X does in fact equal Y because they are both NULL.
It's also a PITA that I can't say
IF X IN ('a','B','C', null)
Because this condition happens. But now I have to say
IF ( X IN ('a','B','C') or X is NULL )
which is a waste of time and a risk of error if I forget the parentheses.
What irks me further is that NULL shouldn't happen in the first place. Fields (er... ok kids, I'll call them Columns) should always be initialized. Period. Stop the nulls. Don't allow them. Default values should always be zeroes or blanks so that those folks that are too lazy to initialize columns in their software will have them initialized for them automatically.
There are many instances where a failure to define default values of zeroes and blanks makes life more difficult than it has to be.

What applications are there for NULLIF()?

I just had a trivial but genuine use for NULLIF(), for the first time in my career in SQL. Is it a widely used tool I've just ignored, or a nearly-forgotten quirk of SQL? It's present in all major database implementations.
If anyone needs a refresher, NULLIF(A, B) returns the first value, unless it's equal to the second in which case it returns NULL. It is equivalent to this CASE statement:
CASE WHEN A <> B OR B IS NULL THEN A END
or, in C-style syntax:
A == B || A == null ? null : A
So far the only non-trivial example I've found is to exclude a specific value from an aggregate function:
SELECT COUNT(NULLIF(Comment, 'Downvoted'))
This has the limitation of only allowing one to skip a single value; a CASE, while more verbose, would let you use an expression.
For the record, the use I found was to suppress the value of a "most recent change" column if it was equal to the first change:
SELECT Record, FirstChange, NULLIF(LatestChange, FirstChange) AS LatestChange
This was useful only in that it reduced visual clutter for human consumers.
I rather think that
NULLIF(A, B)
is syntactic sugar for
CASE WHEN A = B THEN NULL ELSE A END
But you are correct: it is mere syntactic sugar to aid the human reader.
I often use it where I need to avoid the Division by Zero exception:
SELECT
COALESCE(Expression1 / NULLIF(Expression2, 0), 0) AS Result
FROM …
Three years later, I found a material use for NULLIF: using NULLIF(Field, '') translates empty strings into NULL, for equivalence with Oracle's peculiar idea about what "NULL" represents.
NULLIF is handy when you're working with legacy data that contains a mixture of null values and empty strings.
Example:
SELECT(COALESCE(NULLIF(firstColumn, ''), secondColumn) FROM table WHERE this = that
SUM and COUNT have the behavior of turning nulls into zeros. I could see NULLIF being handy when you want to undo that behavior. If fact this came up in a recent answer I provided. If I had remembered NULLIF I probably would have written the following
SELECT student,
NULLIF(coursecount,0) as courseCount
FROM (SELECT cs.student,
COUNT(os.course) coursecount
FROM #CURRENTSCHOOL cs
LEFT JOIN #OTHERSCHOOLS os
ON cs.student = os.student
AND cs.school <> os.school
GROUP BY cs.student) t

Matching BIT to DATETIME in CASE statement

I'm attempting to create a T-SQL case statement to filter a query based on whether a field is NULL or if it contains a value. It would be simple if you could assign NULL or NOT NULL as the result of a case but that doesn't appear possible.
Here's the psuedocode:
WHERE DateColumn = CASE #BitInput
WHEN 0 THEN (all null dates)
WHEN 1 THEN (any non-null date)
WHEN NULL THEN (return all rows)
From my understanding, the WHEN 0 condition can be achieved by not providing a WHEN condition at all (to return a NULL value).
The WHEN 1 condition seems like it could use a wildcard character but I'm getting an error regarding type conversion. Assigning the column to itself fixes this.
I have no idea what to do for the WHEN NULL condition. My internal logic seems to think assigning the column to itself should solve this but it does not as stated above.
I have recreated this using dynamic SQL but for various reasons I'd prefer to have it created in the native code.
I'd appreciate any input. Thanks.
The CASE expression (as OMG Ponies said) is mixing and matching datatypes (as you spotted), in addition you can not compare to NULL using = or WHEN.
WHERE
(#BitInput = 0 AND DateColumn IS NULL)
OR
(#BitInput = 1 AND DateColumn IS NOT NULL)
OR
#BitInput IS NULL
You could probably write it using CASE but what you want is an OR really.
You can also use IF..ELSE or UNION ALL to separate the 3 cases