Not Equal logic trouble in SQL Server - sql

I can't believe I'm having so much trouble with this.
Using this statement:
USE XXXX
SELECT
ID, DESCRIPTION, STATUS
FROM
PART
WHERE
PART.ID LIKE 'PCH%'
AND PART.DESCRIPTION NOT LIKE '%OBSOLETE%'
AND PART.STATUS = 'O'
I get a table with 34 entries, each of them containing O in PART.STATUS.
What I actually want to say is, only show me the values which do NOT have a status of O. I know there are other ways around this. values that are not O should be null, but I'm annoyed that I can't figure out how the 'not equal' statement works. When I switch the last line to:
AND PART.STATUS <> 'O'
OR
AND PART.STATUS != 'O'
I get an empty table returned.
If I use the line
AND PART.STATUS IS NULL
I get the table I'm looking for.
What am I misunderstanding about the use of 'not equal statements'?

The problem is 3 valued predicate logic. When at least one side of predicate is NULL the result of predicate is UNKNOWN(no matter you use = or <> or > or <, ...), but WHERE clause only returns rows where predicate evaluates to TRUE. So our job is to make predicate to evaluate to TRUE when PART.STATUS IS NULL. This is done by adding additional check on NULL like:
USE XXXX
SELECT ID, DESCRIPTION,STATUS
FROM PART
WHERE
PART.ID LIKE 'PCH%'
AND PART.DESCRIPTION NOT LIKE '%OBSOLETE%'
AND (PART.STATUS <> 'O' OR PART.STATUS IS NULL)
Here is a little example. Imagine this is your table and you are issuing your statement WHERE PART.STATUS <> 'O'
PART(STATUS)
'A'
'O'
NULL
It evaluates to:
WHERE 'A' <> 'O' --TRUE
WHERE 'O' <> 'O' --FALSE
WHERE NULL <> 'O'--UNKNOWN
Since WHERE clause returns only rows where result of predicate is TRUE, you will get only 'A' here.

the issue here is with the nullvalue since every logical comparation against it would return false for example
PART.STATUS = NULL-- Would be false
PART.STATUS <> NULL-- would also return false
so you should do your comparison like
AND (PART.STATUS <> 'O' OR PART.STATUS IS NULL)

The part you're missing is that NULL is not a value, but the absence of it. A NULL means that the value in that field is either inexistent or unknown. That's why you cant' directly compare a value to a NULL. As stated in other answers, you have to use PART.STATUS IS NULL. Another option would be to use the ISNULL function, wich will test a value for NULL and, if it is, will return whatever value you specify on the second parameter. E.g.
USE XXXX
SELECT ID, DESCRIPTION,STATUS
FROM PART
WHERE
PART.ID LIKE 'PCH%'
AND PART.DESCRIPTION NOT LIKE '%OBSOLETE%'
AND ISNULL(PART.STATUS, '') <> 'O'
Check the documentation for NULL in Sql Server and the ISNULL function. Also, this question could be of use.

USE XXXX
SELECT ID, DESCRIPTION,STATUS
FROM PART
WHERE
PART.ID LIKE 'PCH%'
AND PART.DESCRIPTION NOT LIKE '%OBSOLETE%'
OR PART.STATUS != 'O'

Maybe your misunderstanding is probably about the NULL concept. NULL is not an empty string neither different from 'O', it's just NULL.
That's why you have to use
AND PART.STATUS IS NULL
or
AND isnull(PART.STATUS, '') <> 'O'

It is important to remember how NULL is treated in a database. It isn't a value at all!
No operator (>,<,=.. etc) less (is) used will ever return rows with NULL.
writing in SQL "where column = NULL" is like saying "give me all rows where the value isn't a value

Null values can't be compared with equals(=) or not equals operators. Try the below:
USE XXXX
SELECT ID, DESCRIPTION,STATUS FROM PART WHERE
PART.ID LIKE 'PCH%'
AND PART.DESCRIPTION NOT LIKE '%OBSOLETE%'
AND ISNULL(PART.STATUS, '') <> 'O'

Related

CASE expression for NULL condition is not working

I have an SQL query where the case expression is not working because I am getting the NULL value.
Any idea how to fix this?
select
td.reportEndDate,
CASE td.originalLinearAirDate
WHEN NULL THEN '12345678'
END As originalLinearAirDate
from
FROM DBA.Telecast td
where id = 2
order by
td.reportEndDate,
originalLinearAirDate;
You can use isnull
select
td.reportEndDate,
CASE WHEN td.originalLinearAirDate IS NULL THEN '19000101'
ELSE td.originalLinearAirDate
END As originalLinearAirDate
from
FROM DBA.Telecast td
where id = 2
order by
td.reportEndDate,
originalLinearAirDate;
You can use COALESCE() :
SELECT td.reportEndDate,
COALESCE(td.originalLinearAirDate, '12345678') AS originalLinearAirDate -- Use default date instead of '12345678'
FROM DBA.Telecast td
WHERE id = 2
ORDER BY td.reportEndDate, originalLinearAirDate;
In your case expression you didn't specified ELSE part hence you got NULL.
However, case expression will only return one type. So, you should check code or do necessary conversation.
The problem is the NULL comparison. The comparison is never true, even when used from comparison in a CASE expression.
If you wanted to do this using CASE, then you need to use IS NULL:
(CASE WHEN td.originalLinearAirDate IS NULL
THEN '12345678'
END) As originalLinearAirDate
If you want to return the original value in this case, you need an ELSE:
(CASE WHEN td.originalLinearAirDate IS NULL
THEN '12345678'
ELSE td.originalLinearAirDate
END) As originalLinearAirDate
Note that this will return an error if the column is really a DATE, because '12345678' cannot be converted to a date.
This version is better expressed using COALESCE():
COALESCE(td.originalLinearAirDate, '12345678')

Problem with field not equal to null in case statement

So I have EXISTS in huge query which looks like this:
EXISTS(
SELECT
*
FROM
ExistTable
WHERE
ExTableFieldA = #SomeGuid AND
ExTableFieldB = MainTableFieldB AND
ExTableFieldA <> (
CASE
WHEN MainTableFieldZ = 10 THEN MainTableFieldYYY
ELSE NULL
END
)
)
The problem comes from ELSE part of CASE statement, this ExTableFieldA <> NULL will be always false. I could easily write another parameter #EmptyGuid and make it equal to '00000000-0000-0000-0000-000000000000' and everything will work but is this the best approach ?
Pretty much I want to execute another check into the exist for the small size of the records which return the "main" query.
How about removing the case and just using boolean logic?
WHERE ExTableFieldA = #SomeGuid AND
ExTableFieldB = MainTableFieldB AND
(MainTableFieldZ <> 10 OR ExTableFieldA <> MainTableFieldYYY)
I would also recommend that you qualify the column names by including the table alias.
Note: This does assume that MainTableFieldZ is not NULL. If that is a possibility than that logic can easily be incorporated.
ELSE NULL is implied even if you don't list it, but you could use ISNULL here.
ISNULL(ExTableFieldA,'') <> (
CASE
WHEN MainTableFieldZ = 10 THEN MainTableFieldYYY
ELSE ''
END
)
You may need to use some other value like 9999 instead of ''

SQL , SQL QUERIES

I have the following condition:
if column is NULL, or have value like Unassessed or ABC then the result should be I.
I need help how to put three in one condition like below. Just confused with NULL value. And it is string in column.
JobAssessStage ='Unassessed','','ABC'
JobAssessStage in ('Unassessed','','ABC')
Use below condition with is null
JobAssessStage in ('Unassessed','ABC') or JobAssessStage is null
use case when for multiple condition
select case when JobAssessStage in ('Unassessed','ABC') or
JobAssessStage is null then 'I' else 'You' End
from yourtable
In some cases you can use also use COALESCE function (it returns the first non-null expression in a list) on JobAssessStage field:
COALESCE(JobAssessStage, 'X') in ('Unassessed','ABC','X')
If JobAssessStage is NULL with COALESCE the value you're testing becomes X.
I told you "in some cases" because you have to be sure that the value you have chosen (X) is not a value that your field can take.
You can formulate your like below:
SELECT *
FROM table
WHERE 1 = 1
AND (JobAssessStage IN ('Unassessed', 'ABC')
OR JobAssessStage IS NULL);

CASE logic when removing NULLs

This is my first post, and I attempted to do a thorough search for this issue, so please accept my apologies if it has been posted elsewhere many times, but I'm wondering if anyone has encountered the following issue when attempting to remove NULLs from their result set:
case Occurrence
when NULL then '0'
else occurrence
end as Occurrence,
case Aggregate
when NULL then '0'
else Aggregate
end as Aggregate,
This didn't do anything to my NULLs; however, this did the trick:
case
when occurrence is NULL then '0'
else occurrence
end as Occurrence,
case
when aggregate is NULL then '0'
else Aggregate
end as Aggregate
Does anyone have any idea why this behaves this way? I'm using SQLServer2012.
I'm also not very versed in programming and only have less than a year SQL experience.
Thanks!
You should be using the ISNULL() or COALESCE() system function for handling nulls
something like
SELECT ISNULL(Occurrence , 0) AS Occurrence
,ISNULL(Aggregate , 0) AS Aggregate
FROM Table
OR
SELECT COALESCE(Occurrence , 0) AS Occurrence
,COALESCE(Aggregate , 0) AS Aggregate
FROM Table
The reason it didn't work in the case statement with
case Occurrence
when NULL then '0'
else occurrence
end as Occurrence,
is because it is interpreting it as
CASE
WHEN Occurrence = NULL THEN 0
ELSE Occurrence
END
Null is checked in sql server using IS NULL or IS NOT NULL if you use any other operator with null like = , <> or <, < it yields NULL hence the unexpected results.
Only for SQL Server 2012 and Later
In sql server 2012 and later versions you also have the IIF function
SELECT IIF(Occurrence IS NULL, 0, Occurrence) AS Occurrence
,IFF(Aggregate IS NULL , 0, Aggregate) AS Aggregate
FROM Table
You use simple case:
The simple CASE expression operates by comparing the first expression to the expression in each WHEN clause for equivalency. If these expressions are equivalent, the expression in the THEN clause will be returned.
Allows only an equality check.
case Occurrence
when NULL then '0'
else occurrence
end as Occurrence,
Which is executed as :
case
when occurence = NULL then '0'
else occurrence
end as Occurrence
Then expression occurence = NULL return NULL and is treated like False
Second your case use searched CASE with full condition and works fine:
case
when occurrence IS NULL then '0'
else occurrence
end as Occurrence,
So your question is about difference column IS NULL vs column = NULL
try
select 1 where null =null
select 1 where null is null
your statement looks like null equals null
select case when null is null then 1 else 0 end
select case null when null then 1 else 0 end
In your case use ISNULL this will give you the results your after
SELECT ISNULL(null,1)

Return 'Yes' or No' from select statement?

tbl_LoanSummary has Sample_Number column. I have to check if Sample_Number column is not null the return 'Y' otherwise return return 'N' from below select statement.
select a.Br_Loan_No ,a.Br_LookupKey, //return IsNull(s.Sample_Number) ='N' or 'Y'
from dbo.tbl_Br a left outer join dbo.tbl_LoanSummary s
on s.Loan_no = a.Br_Loan_No order by a.Br_Loan_No
How to do this?
You can use the case expression for this...
select a.Br_Loan_No,
a.Br_LookupKey,
CASE WHEN s.Sample_Number IS NULL THEN 'N' ELSE 'Y' END AS [HasSample]
from dbo.tbl_Br a left outer join dbo.tbl_LoanSummary s
on s.Loan_no = a.Br_Loan_No order by a.Br_Loan_No
In Oracle, you could also use
select NVL(s.Sample_Number, 'N')
to return N in case of null value
(of course you still need something to have Y in case of not null.)
You'll want to use a CASE expression. It's like an embedded if-statement or switch-statement from traditional programming languages.
SELECT a.Br_Loan_No,
a.Br_LookupKey
CASE
WHEN s.Sample_Number IS NULL THEN 'N'
ELSE 'Y'
END AS sample_number_is_not_null
FROM dbo.tbl_Br a
LEFT JOIN dbo.tbl_LoanSummary s
ON s.Loan_no = a.Br_Loan_No
ORDER BY a.Br_Loan_no
Note that you are creating a computed column here, rather than selecting the raw value of an existing column. It's generally required that you give this column a name, thus the use of the AS sample_number_is_not_null.
There are two forms of the CASE expression. One lets you compare a column or value against several choices. It is like using an implicit equals:
CASE foo
WHEN 3 THEN 'foo is 3!'
WHEN 4 THEN 'foo is 4!'
ELSE 'foo is not 3 or 4'
END
The other form, in the example at the top, lets you use arbitrary expressions in each WHEN clause. It should be noted that each WHEN clause is evaluated in order and the first one to match is the one whose THEN is used as the result. If none of the WHENs match, then the result in the ELSE is used.