Not In operator eliminates NULL values rows in a table - sql

I would like to retrieve all rows with values except 1,2,3,4,5 in my COLUMNA in TABLEA .
SELECT * FROM TABLEA WHERE COLUMNA NOT IN (1,2,3,4,5)
But this eliminates the rows with NULL values in COLUMNA too.
I don't want to eliminate NULL values rows and would like to include those rows in the resultset.
Alternatively, I can try below query for the same
SELECT * FROM TABLEA WHERE COLUMNA NOT IN (1,2,3,4,5) OR COLUMNA IS NULL.
But I would like to know, why is it necessary to add this OR condition?

Why is the additional necessary?
NULL comparisons almost always results in NULL, rather than true or false. A WHERE clause filters out all non-true values, so they get filtered out.
This is how SQL defines NULL. Why is NULL defined like this?
NULL does not mean "missing" in SQL. It means "unknown". So, the result of <unknown> not in (1, 2, 3, 4, 5) is "unknown", because the value could be 1 or it might be 0. Hence it gets filtered.
I will also note that the SQL standard includes NULL-safe comparisons, IS NOT DISTINCT FROM and IS DISTINCT FROM corresponding to = and <> respectively. These treat NULL as just "any other value", so two NULL values are considered equal. However, there is no construct for NULL-safe IN and NOT IN, as far as I know.

Try the following:
SELECT * FROM TABLEA WHERE ISNULL(COLUMNA,0) NOT IN (1,2,3,4,5)

Related

Null query result cant fetch in Select query in Oracle

I have below query which i am trying to run but not returning the expected result. The ISIN field value which is Null in EXPORT_BB is also getting ignore and not showing the result with the condition given in NOT IN clause. The export_blacklist has only one row value and which is not Null but still i dont for what reason the null value is getting ignored.
Select * from EXPORT_BB where ISIN NOT IN
(
SELECT
ISIN
FROM
export_blacklist);
If i run only select query without the NOT IN clause then i can see values which is NULL for ISIN field.
JUst for test i tried below query and its also resulting nothing. Is it bug in Oracle 18c or something is missing?
select 'null is not in set' from dual where null not in (select 1 from dual);
Any comparison of NULL with =, <>, <, > or in a IN or NOT IN clause will return NULL, so that row is not included in the results (because only rows for which the returned value is TRUE will be included in the results).
Change your code with a condition for the case that ISIN is NULL:
SELECT * FROM EXPORT_BB
WHERE ISIN NOT IN (SELECT ISIN FROM export_blacklist)
OR ISIN IS NULL
NULL values doesn't work with NOT IN it's the normal behaviour.
You have to convert the NULL to another value to be able to operate with it or use IS NULL/IS NOT NULL
Select * from EXPORT_BB where NVL(ISIN, 999999) NOT IN
(
SELECT
NVL(ISIN, 999999)
FROM
export_blacklist);
Comparing to a null value in Oracle always returns false.
Is NULL >= 1? No.
Is NULL < 1? No.
Is NULL in your set? Regardless of what your set is, the answer is no.
Is NULL not in your set? Again, no.
It is the expected behaviour. NOt related to 18c it is the same way from Oracle 7 onwards
NOT IN doesnt consider nulls.
NOT EXISTS does consider nulls.
Consider the following example in db fiddle
https://dbfiddle.uk/?rdbms=oracle_18&fiddle=8be0a790d8172093a032602345038e8e
See a discussion on this
https://asktom.oracle.com/pls/apex/asktom.search?tag=in-vs-exists-and-not-in-vs-not-exists
As you have been answered by collegues you have to specify that you wanna return null values too.
Namely
SELECT *
FROM EXPORT_BB
WHERE ISIN NOT IN (SELECT ISIN FROM EXPORT_BLACKLIST)
OR ISIN IS NULL;

What will happen in SQL, when the WHERE clause is fed with a NULL condition?

How many tuples does the result of the following SQL query contain?
SELECT A.Id FROM A
WHERE A.Age > ALL(NULL)
A consist of 4 tuples, and ID is a Primary key.
Should the answer be 4, or 0?
It is going to return no rows.
Why? You are confusing NULL with the empty set. You have a single value that you are comparing to. The value is NULL. Almost any comparison is going to be NULL -- which is treated as false. So, the query returns no rows.
This is quite different from an empty set. If there are no rows in the set of values, then the query will return all rows. For instance:
SELECT count(*)
FROM (VALUES (1,1), (1,2), (1,3), (1,4)) a(id, age)
WHERE A.Age > ALL (SELECT 0 WHERE 1=0);

SQL NOT IN function not returning expected result

Total number of records in table i1450:
Total number with condition where i.BROJ is equal to field REFERENCA in other table:
Shouldn't it return difference between last two results (which is 64) when I use NOT IN in WHERE clause?
Both of columns are of varchar type.
If you have any NULL values in the REFERENCA column from the FpsPmtOrderRQ table then the NOT IN clause will not work as expected - (the reason why)
A solution is to remove NULL values from the result returned by the subselect.
SELECT COUNT(*)
FROM i1450 j
WHERE i.BROJ NOT IN (SELECT REFERENCA FROM FpsPmtOrderRQ WHERE REFERENCA IS NOT NULL)
If the sub-query returns a null value, the IN will not be true. Do NOT EXISTS instead.
select count(*)
from i1450 i
where not exists (select 1 from FpsPmtOrderRQ f
where i.broj = f.REFERENCA)
I think you need to coalesce your field to handle nulls. That is probably why you get 0.
By doing:
where coalesce(I.BROJ,'n/a') not in (select coalesce(REFERENCA,'')
or something similar, you would exclude nulls, and return a proper count.

Excluding a Null value returns 0 rows in a sub query

I'm trying to clean up some data in SQL server and add a foreign key between the two tables.
I have a large quantity of orphaned rows in one of the tables that I would like to delete. I don't know why the following query would return 0 rows in MS SQL server.
--This Query returns no Rows
select * from tbl_A where ID not in ( select distinct ID from tbl_B
)
When I include IS NOT NULL in the subquery I get the results that I expect.
-- Rows are returned that contain all of the records in tbl_A but Not in tbl_B
select * from tbl_A where ID not in ( select distinct ID from tbl_B
where ID is not null )
The ID column is nullable and does contain null values. IF I run just the subquery I get the exact same results except the first query returns one extra NULL row as expected.
This is the expected behavior of the NOT IN subquery. When a subquery returns a single null value NOT IN will not match any rows.
If you don't exclusively want to do a null check, then you will want to use NOT EXISTS:
select *
from tbl_A A
where not exists (select distinct ID
from tbl_B b
where a.id = b.id)
As to why the NOT IN is causing issues, here are some posts that discuss it:
NOT IN vs. NOT EXISTS vs. LEFT JOIN / IS NULL
NOT EXISTS vs NOT IN
What's the difference between NOT EXISTS vs. NOT IN vs. LEFT JOIN WHERE IS NULL?
Matching on NULL with equals (=) will return NULL or UNKNOWN as opposed to true/false from a logic standpoint. E.g. see http://msdn.microsoft.com/en-us/library/aa196339(v=sql.80).aspx for discussion.
If you want to include finding NULL values in table A where there is no NULL in table B (if B is the "parent" and A is the "child" in the "foreign key" relationship you desire) then you would need a second statement, something like the following. Also I would recommend qualifying the ID field with a table prefix or alias since the field names are the same in both tables. Finally, I would not recommend having NULL values as the key. But in any case:
select * from tbl_A as A where (A.ID not in ( select distinct B.ID from tbl_B as B ))
or (A.ID is NULL and not exists(select * from tbl_B as B where B.ID is null))
The problem is the non-comparability of nulls. If you are asking "not in" and there are nulls in the subquery it cannot say that anything anything is definitely not in becuase it is looking at those nulls as "unknown" and so the answer is always "unknown" in the three value logic that SQL uses.
Now of course that is all assuming you have ANSI_NULLS ON (which is the default) If you turn that off then suddenly NULLS become comparable and it will give you results, and probably the results you expect.
If the ids are never negative, you might consider something like:
select *
from tbl_A
where coalesce(ID, -1) not in ( select distinct coalesce(ID, -1) from tbl_B )
(Or if id is a string, use something line coalesce(id, '<null>')).
This may not work in all cases, but it has the virtue of simplicity on the coding level.
You probably have ANSI NULLs switched off. This compares null values so null=null will return true.
Prefix the first query with
SET ANSI_NULLS ON
GO

Can Anyone explain why NULL is used in this query?

Also what will be the scenarios where this query is used
select * from TableA where exists
(select null from TableB where TableB.Col1=TableA.Col1)
As the query is in an EXISTS then you can return anything. It is not even evaluated.
In fact, you can replace the null with (1/0) and it will not even produce a divide by zero error.
The NULL makes no sense. It's simply bad SQL.
The exists clause is supposed to use SELECT *.
People make up stories about the cost of SELECT *. They claim it does an "extra" metadata query. It doesn't. They claim it's a "macro expansion" and requires lots of extra parse time. It doesn't.
The EXISTS condition is considered "to be met" if the subquery returns at least one row.
The syntax for the EXISTS condition is:
SELECT columns
FROM tables
WHERE EXISTS ( subquery );
Please note that "Select Null from mytable" will return number of rows in mytable but all will contain only one column with null in the cell as the requirement of outer query is just to check whether any row fall in the given given condition like in your case it is "TableB.Col1=TableA.Col1"
you can change null to 1, 0 or any column name available in the table. 1/0 may not be a good idea :)
It's a tacky way of selecting all records in TableA, which have a matching record (Col1=Col1) in TableB. They might equally well have selected '1', or '*', for instance.
A more human-readable way of achieving the same would be
SELECT * FROM TableA WHERE Col1 IN ( SELECT Col1 IN TableB )
Please, please, all ....
EXISTS returns a BOOLEAN i.e. TRUE or FALSE. If the result set is non empty then return TRUE. Correlation of the sub-query is important as in the case above.
i.e Give me all the rows in A where AT LEAST one col1 exists in B.
It does not matter what is in the select list. Its just a matter of style.