I have a bit column on a table in a SQL Server 2012 database.
I am trying to retrieve all the rows where this bit column is either NULL or NOT TRUE.
This query does not bring back what it should: (returns 0 rows)
Select *
from table
where bit_column_value <> 1
This query brings back the correct rows:
Select *
from table
where bit_column_value IS NULL
Now, I'd be happy to use the second query, but my issue is that, in a similar query for another table, the reverse of the above is true, where the first way works, but the second way does not!
Could someone assist in explaining what the difference is in the above? I have specifically updated the relevant bit columns to be NULL and this does not change the results. (Thought maybe there was a difference between "Empty" and Null values.
Thanks in advance for any explanations.
The reason <> doesn't work is that SQL treats NULL as unknown - it doesn't know what NULL is supposed to mean, so it evaluates both = and <> on a NULL value as UNKNOWN (which is treated as false in a where clause or join condition). For more info, read this: Why does NULL = NULL evaluate to false in SQL server.
If there's an index on it, using the ISNULL function will mean the index can't be used, so to
ensure the query can use the index just use OR:
SELECT *
FROM TableName
WHERE
bit_column_value IS NULL OR bit_column_value = 0
your best bet would be to write the query as such:
SELECT
*
FROM
table
WHERE
ISNULL(bit_column_value, 0) = 0
This should return all the NULL and FALSE records.
Without seeing your table structure and data, I cannot really comment on why you are getting different results from your 2 queries.
MSDN says that the BIT type can store values 0, 1 or NULL. (The fact that a BIT value is NULL must be stored separately from the bit value itself, since the bit values can be compressed so that 8 BIT values are stored in a byte.)
Remember that a condition in a WHERE clause selects a row when the condition is TRUE. For most binary predicates (conditions), if you compare NULL with some value, the result is NULL or UNKNOWN (not TRUE). So, for example, if the value in a column is NULL, then column = 0 evaluates to NULL or UNKNOWN, and so does column <> 0.
Looking at your queries:
SELECT * FROM table WHERE bit_column_value <> 1
Where the value in the bit_column_value column is 1, the condition is FALSE so the row is not returned; where the value is 0, the condition is TRUE so the row is returned; and where the value is NULL, the condition is also NULL or UNKNOWN so the row is not returned.
SELECT * FROM table WHERE bit_column_value IS NULL
According to the SQL standard, the IS [NOT] NULL predicate, and the related IS [NOT] {TRUE|FALSE|UNKNOWN} predicates, are slightly different. The IS NULL test returns TRUE if the tested value is NULL; otherwise, they return FALSE (and never return UNKNOWN). The IS [NOT] {TRUE|FALSE|UNKNOWN} tests are similar; they return TRUE if the value is of the specified type and FALSE otherwise (not UNKNOWN). For example:
Column IS TRUE IS FALSE IS UNKNOWN IS NOT TRUE IS NOT FALSE IS NOT UNKNOWN
FALSE FALSE TRUE FALSE TRUE FALSE TRUE
TRUE TRUE FALSE FALSE FALSE TRUE TRUE
NULL FALSE FALSE TRUE TRUE TRUE FALSE
So, in your second query, only the rows where the bit_column_value value is NULL (which is separate from both 0 and 1) will be selected — not the TRUE, nor the FALSE.
I am trying to retrieve all the rows where this bit column is either NULL or NOT TRUE.
Try writing the query directly from your specification:
SELECT * FROM table WHERE bit_column_value IS NULL OR bit_column_value IS NOT TRUE
SELECT * FROM table WHERE bit_column_value IS NULL OR bit_column_value = FALSE
SELECT * FROM table WHERE bit_column_value IS NULL OR bit_column_value <> TRUE
SELECT * FROM table WHERE bit_column_value IS NOT TRUE
Given the truth table above, query 4 would yield the result you want — with the major caveat that I'm not certain that MS SQL Server supports the IS [NOT] {TRUE|FALSE|UNKNOWN}. Judging from MSDN on Predicates, the IS [NOT] {TRUE|FALSE|UNKNOWN} predicates are not supported (but I might have missed the correct part of the manual). If that's correct, you need to use one of query 2 or 3.
(There are some extra complications with these predicates when the value is not a simple column but is a row value. However, that's not relevant to your question or problem; doubly not since MS SQL Server does not seem to support them.)
Please check your table data, if it's contain value = 0 ?
SQL Bit data type can only have value either 0, 1 or NULL, if you insert other value, it's considered to 1 (Exception : If you insert 'False' it will became 0, 'True' will became 1).
For example :
insert into t1 values (1),(2),(1),(3),(-1),(0),(NULL),('false'),('true')
The result :
1, 1, 1, 1, 1, 0, NULL, 0, 1
I think this is because that all the data have NULL values in this column. So:
Select *
from table
where bit_column_value <> 1;
Won't give you the result. Since NULL is unknown. And this:
Select *
from table
where bit_column_value IS NULL;
Will give you the result you are looking for.
But you have a misconception of representing true and false using the bit data type.
You are representing false as NULL, 0 is empty and true is any other value. The bit data types works as #IswantoSan explained in his answer; It should be 0 or 1 or NULL:
0 is false,
1 is true,
NULL is empty.
Therefore to get:
true values use the where bit_column_value = 1.
false values use the where bit_column_value = 0.
NULL or empty where bit_column_value IS NULL.
NULL or not true:where bit_column_value IS NULL or bit_column_value = 0`.
The other thing to note is that NULL and empty are two different things, they are not the same. In case of the BIT data type empty is NULL not 0, because 0 is supposed to be false. But consider a string data type like VARCHAR for example then the empty string '' is totally different from the NULL value.
Related
I have a SQL table that has a bit column named "Split".
I need to create a stored procedure that receives a parameter named WithSplit of type bit.
If WithSplit is false then I need to get all the records that have the "Split" column equal to false.
If WithSplit is true, then I need to get the records having the "Split" column value either true or false.
That is , if WithSplit is false then get only the records where split=withsplit, else get all records.
How should this be achieved?
I have found the answer:
(Split = #WithSplit or #WithSplit = case when #WithSplit =1 then 1 end)
Is there a way in sql to, by default bring back values regardless of if they are true or false?
for example I have a column, 'Mandatory' which datatype is a bit.
Is there a way to bring back records where the column 'Mandatory' is either true or false or null?
something like
Select * From Table Where Mandatory = .... etc
select * from Table
where mandatory is null or mandatory in (0,1)
If the mandatory is a bit, this code is definitely true. There is no other possibility.
Let me assume you are using SQL Server -- because it supports bit but not boolean.
You can use:
where mandatory = 1
or
where mandatory = 'true'
resolved by doing this
ISNULL(Mandatory,0) =
CASE
WHEN #Mandatory = 0 THEN 0
WHEN #Mandatory = 1 THEN 1
WHEN #Mandatory = 2 THEN ISNULL(Mandatory,0)
essentially saying that when 2 is inputted, it will bring back all values for true, false and null. works very well
The question is how to run a binary logic into trinary logic.
Binary = There are distinct, actual values: in regards to this question the values [True] or [False]
Trinary = There are distinct, actual values plus unknown values: in regards to this question the values [ True | False | NULL ]
It is not possible to include unknown values in a single WHERE condition. Instead it has to be checked separately:
WHERE mandatory IN (0, 1) -- check whether TRUE or FALSE against bit
OR mandatory IS NULL -- also include UNKNOWN
This approach is better than using a function as a function in a WHERE condition can (and will) lead more often than not to performance losses.
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?
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.
Remember, NULL means you don't know what the value is. This is subtly different than not having a value at all. When you don't know what the value is, it's still possible the value might be 2, and therefore NULL <> 2 could still possibly be false... but, again, the result is you don't know.
Therefore, if t.Invc_Sts_Cd is NULL, then t.Invc_Sts_Cd <> 2 must evaluate as... NULL, because we don't know what the result is. And NULL is falsy when you force it into a true/false boolean situation.
This is not about T-SQL, but SQL in general. NULL is the unknown value. If you compare it with some value, the result is hence unknown (i.e. it could or could not match the value).
So both
and t.Invc_Sts_Cd <> 2
and
and t.Invc_Sts_Cd = 2
exclude NULLs from the result, because for a NULL in Invc_Sts_Cd neither expression results in TRUE.
The crux here is that the logical comparison:
t.Invc_Sts_Cd <> 2
is actually false when the Invc_Sts_Cd value is NULL. The reason for this is that comparing NULL to any other value yields the value NULL, which will evaluate to false when it appears inside a WHERE clause.
The second version of your logic is correct:
and (t.Invc_Sts_Cd <> 2 OR t.Invc_Sts_Cd IS NULL)
This will be true when either Invc_Sts_Cd is not equal to 2, or this value happens to be NULL.
I have table, in which a column has empty fields.when i try to run simple query like below it is not
returning the data.
select * from table1 where "colunm1" = ''
But below two queries returns data
1,
select * from table1
where coalesce("colunm1", '') = ''
2,
select * from table1
where "colunm1" is null
Can someone tell me the reason?
TIA
You have describe the behavior of a column that is NULL. NULL is not the same as an empty string.
It fails any equality comparison. However, you can use is null or (less preferentially) coalesce().
The only database that treats an empty string like a NULL value, is Oracle.
Logically, for a DBMS, that would be wrong.
Relational DBMSs are all about :
set theory
Boolean algebra
A NULL value is a value that we don't know. A string literal of '' is a string whose value we know. It is a string with no characters, with a length of 0. We don't know of a NULL as a string how long it is, how many and, if any, which, characters it contains.
So it is only logical that:
the comparison '' = '' will evaluate to TRUE
the comparison NULL = NULL will evaluate to FALSE , as any comparison with a NULL value will evaluate to FALSE.
And functions like COALESCE() or NVL(), IFNULL(), ISNULL() will return the first parameter if it does not contain a NULL value. That is consistent.
Except in Oracle
In SQL , why does 10/NULL evaluate to NULL (or unknown) ? Example :
if((10/NULL) is NULL)
DBMS_OUTPUT.PUT_LINE("Null.");
However , 1 = NULL being a COMPARISON is considered as FALSE. Shouldn't 10/NULL also be considered as FALSE ?
I am referring to SQL only . Not any DBMS in particular. And it might be a duplicate but I didn't know what keywords to put in search for this query.
Shouldn't 10/NULL also be considered as FALSE?
No, because:
Any arithmetic expression containing a null always evaluates to null. For example, null added to 10 is null. In fact, all operators (except concatenation) return null when given a null operand.
Emphasis mine, taken from the Oracle manual: http://docs.oracle.com/cd/E11882_01/server.112/e26088/sql_elements005.htm#i59110
And this is required by the SQL standard.
Edit, as the question was for RDBMS in general:
SQL Server
When SET ANSI_NULLS is ON, an operator that has one or two NULL expressions returns UNKNOWN
Link to the the manual:
MySQL
An expression that contains NULL always produces a NULL value unless otherwise indicated in the documentation for a particular function or operator
Link to the manual
DB2
if either operand can be null, the result can be null, and if either is null, the result is the null value
Link to the manual:
PostgreSQL
Unfortunately I could not find such an explicit statement in the PostgreSQL manual, although I sure it behaves the same.
Warning: The "(except concatenation)" is an Oracle only and non-standard exception. (The empty string and NULL are almost identical in Oracle). Concatenating nulls gives null in all other DBMS.
1 = null is not null. It is actually unknown. As well as any other null operation.
The equality predicate 1 = NULL evaluates to NULL. But NULL in a boolean comparison is considered false.
If you do something like NOT( 1 = NULL ), 1 = NULL evaluates to NULL, NOT( NULL ) evaluates to NULL and so the condition as a whole ends up evaluating to false.
Oracle has a section in their documentation on handling NULL values in comparisons and conditional statements-- other databases will handle things in an very similar manner.
10/something means that you are counting how much "something" will be in 10
in this case you're counting how much "nothing" will be in 10 - that's infinity, unknown..
1 = NULL is false because one does not equal nothing
The NULLIF function accepts two parameters. If the first parameter is equal to the second parameter, NULLIF returns Null. Otherwise, the value of the first parameter is returned.
NULLIF(value1, value2)
NVL
The NVL function accepts two parameters. It returns the first non-NULL parameter or NULL if all parameters are NULL.
also check this conditional outcomes:
This "null equals UNKNOWN truth value" proposition introduces an inconsistency into SQL 3VL. One major problem is that it contradicts a basic property of nulls, the property of propagation. Nulls, by definition, propagate through all SQL expressions. The Boolean truth values do not have this property. Consider the following scenarios in SQL:1999, in which two Boolean truth values are combined into a compound predicate. According to the rules of SQL 3VL, and as shown in the 3VL truth table shown earlier in this article, the following statements hold:
( TRUE OR UNKNOWN ) → TRUE
( FALSE AND UNKNOWN ) → FALSE
However, because nulls propagate, treating null as UNKNOWN results in the following logical inconsistencies in SQL 3VL:
( TRUE OR NULL ) → NULL ( = UNKNOWN )
( FALSE AND NULL ) → NULL ( = UNKNOWN )
The SQL:1999 standard does not define how to deal with this inconsistency, and results could vary between implementations. Because of these inconsistencies and lack of support from vendors the SQL Boolean datatype did not gain widespread acceptance. Most SQL DBMS platforms now offer their own platform-specific recommendations for storing Boolean-type data.
Note that in the PostgreSQL implementation of SQL, the null value is used to represent all UNKNOWN results and the following evaluations occur:
( TRUE OR NULL ) → TRUE
( FALSE AND NULL ) → FALSE
( FALSE OR NULL ) IS NULL → TRUE
( TRUE AND NULL ) IS NULL → TRUE