So I have a SQL statement that was not returning data like it should (MSSQL Server), in part of the query I had this
and t.Invc_Sts_Cd <> 2
turns out if I changed that to
and (t.Invc_Sts_Cd <> 2 OR t.Invc_Sts_Cd IS NULL)
then it returned the data I expected, I would have thought those 2 things would be equivalent but obviously not in TSQL.
Here is the full Statement
SELECT t.tm_sht_id,0 FROM tm_sht t INNER JOIN cand c ON c.cand_id = t.cand_id LEFT JOIN SOW_Resource sr on c.Req_Id = sr.Req_Id and (sr.Invoice_Timesheets=1 OR sr.Invoice_Timesheets is NULL) WHERE t.tm_sht_sts_cd = 3 AND t.apvd_dt >= @Last_Run_Time and c.clnt_org_id = @Org_Id and (t.Suspend_Fg <> 1) and (t.Invc_Sts_Cd <> 2 OR t.Invc_Sts_Cd IS NULL)
My question is why do those return different data sets?
Advertisement
Answer
t.Invc_Sts_Cd <> 2
and (t.Invc_Sts_Cd <> 2 OR t.Invc_Sts_Cd IS NULL)
are not equivalent, but they are similar.
The key thing you need to understand here is how NULL
values work. Nothing is equal to or not equal to NULL
, including NULL
itself; NULL = NULL
isn’t TRUE
(though is isn’t FALSE
either, but I come to that shortly). The only way to evaluate against a NULL
is using IS NULL
and IS NOT NULL
.
When doing a comparison against NULL
, if you don’t use IS (NOT) NULL
then the result will be UNKNOWN
. For a expression like WHERE Column = 1
then it isn’t a problem when Column
has the value NULL
, as it isn’t 1
. For other expressions, it does.
For WHERE Column <> 2
, when Column
has the value NULL
it gives result the UNKNOWN
, which importantly is not TRUE
. Thus the row does not meet to criteria.
The same is true for an expression like WHERE NOT(Column = 1)
. If Column
has the value NULL
, then Column = 1
= UNKNOWN
and NOT(UNKNOWN)
is still UNKNOWN
.
Therefore, if you have NULL
values, and are performiong comparisons which rely on them, you must include IS NULL
and/or IS NOT NULL
logic.