Check for != values when column contains records with NULLs - oracle

I have a number of tables that mix 'real' values with nulls in columns. From exerience, issuing a SELECT against these that looks like:
SELECT column1, column2, column3 FROM mytable WHERE column1 != 'a value';
...doesn't return the records I expect. In the current table I am working on, this returns an empty recordset, even though I know I have records in the table with NULLs in column1, and other records in the table that have the value I am "!="ing in column1. I am expecting, in this case, to see the records with NULLs in column1 (and, of course, anything else if there were other not 'a value' values in column1.
Experimenting with NVL in the WHERE clause doesn't seem to give me anything different:
SELECT column1, column2, column3 FROM mytable WHERE NVL(column1, '') != 'a value';
...is also returning an empty recordset.
Using 'IS NULL' will technically give me the correct recordset in my current example, but of course if any records change to something like 'another value' in column1, then IS NULL will exclude those.

NULL can't be compared in the same way that other values can be. You must use IS NULL. If you want to include NULL values, add an OR to the WHERE clause:
SELECT column1, column2, column3 FROM mytable WHERE column1 != 'a value' OR column1 IS NULL

The query doesn't work because SQL handles equality checks (!=) different from checking if null (IS NULL).
What you could do here is something like:
SELECT column1, column2, column3
FROM mytable
WHERE column1 != 'a value' OR column1 is null;
See Not equal <> != operator on NULL.

What you were trying was correct. You just need change it a little. see below-
SELECT column1, column2, column3 FROM mytable WHERE NVL(column1, '0') != 'a value';
Instead of empty string, pass any character in NVL's second argument.

"Experimenting with NVL in the WHERE clause doesn't seem to give me anything different"
That's true:
SQL> select * from mytable;
COLUMN1 COLUMN2 COLUMN3
-------------------- ---------- ---------
a value 1 25-JUL-17
not a value 2 25-JUL-17
whatever 3 25-JUL-17
4 26-JUL-17
SQL> SELECT column1, column2, column3 FROM mytable WHERE NVL(column1, '') != 'a value';
COLUMN1 COLUMN2 COLUMN3
-------------------- ---------- ---------
not a value 2 25-JUL-17
whatever 3 25-JUL-17
SQL>
This is because your experiment didn't go far enough. For historical reasons Oracle treats an empty string as null so your nvl() statement effectively just subs one null for another. But if you had used a proper value in your call you would have got the result you wanted:
SQL> SELECT column1, column2, column3 FROM mytable WHERE NVL(column1, 'meh') != 'a value';
COLUMN1 COLUMN2 COLUMN3
-------------------- ---------- ---------
not a value 2 25-JUL-17
whatever 3 25-JUL-17
4 26-JUL-17
SQL>
The alternative approach is to explicitly test for NULL and test for the excluding value...
SQL> SELECT column1, column2, column3 FROM mytable
2 where column1 is null or column1 != 'a value';
COLUMN1 COLUMN2 COLUMN3
-------------------- ---------- ---------
not a value 2 25-JUL-17
whatever 3 25-JUL-17
4 26-JUL-17
SQL>
The second approach is probably more orthodox.

1) Undocumented Oracle function SYS_OP_MAP_NONNULL. (It exists from oracle10)
with abc as ( select 'a value' as col1 from dual
union all
select '' as col1 from dual)
select * from abc
where SYS_OP_MAP_NONNULL(col1) != SYS_OP_MAP_NONNULL('a value')
;
2) LNNVL - Check table in the documentation for clarification.
with abc as ( select 'a value' as col1 from dual
union all
select '' as col1 from dual)
select * from abc
where lnnvl( col1 = 'a value');
;

Related

Filtering columns only "if" certain condition is satisfied

I am having table as below
And I want output as below
I tried doing something as below
SELECT * FROM TABLE_NAME WHERE COLUMN2 = 'PQR' AND COLUMN3 IS NOT NULL
But it also removes 3rd and 4th row from 1st table. Whereas in output of the query I need to remove only rows which are having Column2 as PQR and Column3 as NOT NULL
I also tried to use case statements but I'm not able to get actual idea of how to implement it.
EDIT 1:-
Also I thought of trying one more thing now.
SELECT * FROM TABLE_NAME WHERE COLUMN2 IN ('PQR', 'XYZ', 'RST') AND COLUMN3 IS NOT NULL
But the problem is in actual table COLUMN2 is having more than 150 distinct values which I can't go on mentioning in IN clause.
not(COLUMN2 = 'PQR' AND COLUMN3 IS NOT NULL)
Example:
SQL> ;
1 with -- test data:
2 t(column1,column2,column3) as (
3 select 'ABC','PQR',cast(null as int) from dual union all
4 select 'DEF','PQR',123 from dual union all
5 select 'GHI','XYZ',cast(null as int) from dual union all
6 select 'JKL','RST',cast(null as int) from dual
7 ) -- test query:
8 select *
9 from t
10* where not(COLUMN2 = 'PQR' AND COLUMN3 IS NOT NULL)
SQL> /
COL COL COLUMN3
--- --- ----------
ABC PQR NULL
GHI XYZ NULL
JKL RST NULL
or lnnvl(COLUMN2 = 'PQR') or COLUMN3 IS NULL
Example:
with -- test data:
t(column1,column2,column3) as (
select 'ABC','PQR',cast(null as int) from dual union all
select 'DEF','PQR',123 from dual union all
select 'GHI','XYZ',cast(null as int) from dual union all
select 'JKL','RST',cast(null as int) from dual
) -- test query:
select *
from t
where lnnvl(COLUMN2 = 'PQR') or COLUMN3 IS NULL;
COL COL COLUMN3
--- --- ----------
ABC PQR NULL
GHI XYZ NULL
JKL RST NULL
What you want is (if I understood correctly)
NOT (COLUMN2 = 'PQR' AND COLUMN3 IS NOT NULL)
which is equivalent to
COLUMN2!='PQR' OR COLUMN3 IS NULL

Oracle CASE WHEN - ORA-00936: missing expression

I am new to oracle and below is my SQL.
SELECT * FROM TABLE1 WHERE COLUMN1 = 'YES'
AND COLUMN2 IN (
CASE WHEN EXISTS(SELECT * FROM TABLE1 WHERE COLUMN1 = 'YES' AND COLUMN2 NOT LIKE '%NO%')
THEN
SELECT COLUMN2 FROM TABLE1 WHERE COLUMN1 = 'YES' AND COLUMN2 NOT LIKE '%YES%'
ELSE
SELECT COLUMN2 FROM TABLE1 WHERE COLUMN1 = 'YES' AND COLUMN2 NOT LIKE '%YES%' END)
it is giving ORA-00936: missing expression at then statement. What am I doing wrong?
The subqueries after THEN and ELSE must be enclosed inside parentheses:
SELECT * FROM TABLE1 WHERE COLUMN1 = 'YES'
AND COLUMN2 IN (
CASE
WHEN EXISTS (SELECT * FROM TABLE1 WHERE COLUMN1 = 'YES' AND COLUMN2 NOT LIKE '%NO%')
THEN (SELECT COLUMN2 FROM TABLE1 WHERE COLUMN1 = 'YES' AND COLUMN2 NOT LIKE '%YES%')
ELSE (SELECT COLUMN2 FROM TABLE1 WHERE COLUMN1 = 'YES' AND COLUMN2 NOT LIKE '%YES%')
END
)
This will work only if these subqueries don't return more than 1 row.
Also, both subqueries are the same. Is this a typo?
And IN can be changed to = since CASE returns only 1 value.

return null if no rows found oracle query with IN clause

I have a table with three columns.
I query that table with IN clause.
select column1 from table1 where column1 in (1,2,3) order by column2, column3
The table1 contains only values 1 and 2 in column1. I want to return the not available value also in my result, and that should be sorted in the bottom.
example data
column1 column 2 column 3
1 100 11
2 101 50
output, the not available values should be in the last.
column1 column 2 column 3
1 100 11
2 101 50
3 null null
I tried with subquery with NVL, like select nvl((select.. in(1,2,3)),null) from dual, due to IN Clause, I am getting single row subquery returns more than one row issue, which is expected.
Also tried with the union but nothing works. Great if any help. Thanks
I think you can do it with a union all:
select column1 from table1 where column1 in (1,2,3) order by column2, column3
union all
select null from table1 where column1 not in (1,2,3) order by column2, column3
If you can't take 1,2,3 values from another table you can try with:
with t1 as (
select col1,col2,col3
from tab1
where cod_flusso in ('1','2','3')),
t2 as (
select '1' as col1,null,null
from dual
union
select '2',null,null
from dual
union
select '3',null,null
from dual)
select t2.col1,col2,col3
from t2
left outer join t1
on t1.col1= t2.col1
It's better if you can store 1,2,3 values in a second table, then use left outer join.

Oracle queries acting strange why this is happening? Am i doing something wrong?

First sorry if i have a bad english:
select * from table2 where column1='000022071001';
Returns nothing!
select * from table1 where column1 not in (select column1 from table2);
Returns nothing
select * from table1 where column1='000022071001';
IT RETURN VALUES!
This aint logical, if column1 value '000022071001' from table1 is not in table2 , why the second query returns nothing?
What am i doing wrong?
There will be some NULL values in the column1 in the table2 causing this issue
Try this
select * from table1 where column1 not in
(select column1
from table2
WHERE column1 is not null)

change the value of a query when inserting

tab1
column1 =4
column2 = (empty column )
column3 = also empty
what I want is when I insert data into column2
column2 = test
I want column 2 to have the data of column1 , I want to have such result
column 2= 4test
I know I can achieve that with a trigger or procedure , I am asking you if there is another way when I insert it
Try
update tab1 set column2 = column1 || 'test' where condition;

Resources