Why does CASE evalulate the ELSE clause? - oracle

Oracle 11g: Consider the following two CASE Statements
SEARCHED CASE
with null_table as (select null as null_set from dual )
select
case
when (null_set is null) then 'NULL INDEED'
else 'NOTNULL?'
end as AM_I_NULL_OR_NOT
from null_table
SIMPLE CASE
with null_table as (select null as null_set from dual )
select
case null_set
when (null) then 'NULL INDEED'
else 'NOTNULL?'
end as AM_I_NULL_OR_NOT
from null_table
The Searched CASE evaluates null_set as expected, yet, Simple CASE appears not to do so.
Questions:
How do I perform a Simple CASE evaluation on null_set ?
Why does the Simple CASE evaluate as it does?

In Oracle, null cannot be compared against using the = operator.
For example:
select * from dual where null = null; -- No result
select * from dual where 1 = 1; -- gives a result
So what you can do is use NVL to replace null by another value :
with null_table as (select null as null_set from dual )
select
case nvl(null_set,'X')
when 'X' then 'NULL INDEED'
else 'NOTNULL?'
end as AM_I_NULL_OR_NOT
from null_table
(make sure your field can never be equal to the value, X in the example.)

Related

ORA-01722: invalid number in Update query

I have following query and getting ORA-01722: invalid number
UPDATE SCHEDULE SET IS_ACTIVE = 0 WHERE REMINDER_ID IN ( SELECT replace('1,2', '''', '') as xtx FROM DUAL);
When I tried following way it executes , SELECT replace('1,2', '''', '') FROM DUAL;
I am getting (1,2) but this is not happening in the first query.
Got it and working - x_reminder_id = "'12,13'"
MERGE INTO SCHEDULE dst
USING (
SELECT REGEXP_SUBSTR(x_reminder_id, '\d+', 1, LEVEL) AS id
FROM DUAL
CONNECT BY LEVEL <= LEAST(
REGEXP_COUNT(x_reminder_id, '\d+')
)
) src
ON (src.id = dst.REMINDER_ID)
WHEN MATCHED THEN
UPDATE
SET IS_ACTIVE = 0;

ORA-00932 if collection used in recursive CTE in where clause

I have recursive CTE with column of collection type (sys.ku$_vcnt is used here because it is built-in, problem can be reproduced for any collection type). When the collection column is used in recursive part of CTE in where clause, query fails with ORA-00932: inconsistent datatypes: expected UDT got SYS.KU$_VCNT error.
This is minimized example, in real case the collection content is inspected in where clause. Any occurence of collection seems enough for query to fail - for instance not null check as shown in following example:
with r (l, dummy_coll, b) as (
select 1 as l, sys.ku$_vcnt(), null from dual
union all
select l + 1
, r.dummy_coll
, case when r.dummy_coll is not null then 'not null' else 'null' end as b
from r
where l < 5 and r.dummy_coll is not null
)
select * from r;
If and r.dummy_coll is not null is removed from where clause, the query succeeds. Occurence of collection in select clause is not problem (the b column shows the collection is actually not null).
Why does not it work and how to force Oracle to see collection column from previous recursion level in where clause?
Reproduced in Oracle 11 and Oracle 18 (dbfiddle).
Thanks!
Yeah that looks like a bug to me. A scalar select seems to be a workaround. Would that work in your case?
SQL> with r (l, dummy_coll, b) as (
2 select 1 as l, sys.ku$_vcnt(), null from dual
3 union all
4 select l + 1
5 , r.dummy_coll
6 , case when r.dummy_coll is not null then 'not null' else 'null' end as b
7 from r
8 where l < 5 and ( select r.dummy_coll from dual ) is not null
9 )
10 select * from r;
L,DUMMY_COLL,B
1,KU$_VCNT(),
2,KU$_VCNT(),not null
3,KU$_VCNT(),not null
4,KU$_VCNT(),not null
5,KU$_VCNT(),not null

IN , NOT IN for null value in oracle

In oracle why "Not in" doesn't work on null values but "IN" works
For eg
with temp(n,p) as (
select 1,2 from dual union all
select 3,2 from dual union all
select 4,6 from dual union all
select 5,6 from dual union all
select 2,8 from dual union all
select 6,8 from dual union all
select 8,null from dual
)
1. Select * from temp where n in (2,6,8,null);
2. Select * from temp where n not in (2,6,8,null);
First Statement will give the output = 2,6,8
Second statement will not give any output
Can someone please explain why?
NOT IN essentially works like this:
col NOT IN (value_a, value_b, value_c)
-- is the same as
col != value_a && col != value_b && col != value_c
If one of the values is null, the whole expression evaluates to null, not true (which you probably expect).
You can read more about it here: https://jonathanlewis.wordpress.com/2007/02/25/not-in/

PL/SQL: ORA-00936: missing expression in update query using case AND condition

I have the below query where i am using update query using case statement. I am running this query inside procedure. I am getting an error in the third line of update query as PL/SQL: ORA-00936: missing expression in update query using case statement. I want to use && condition in my first case of update query but its failing. The procedure is very big and thts why i did not mention in my question.
update
CAPTURING set LAST_TASK_ID=
CASE WHEN (SELECT MAX(ID) from TEMP_SOAP_MONITORING AND LAST_TASK_ID ) IS NULL THEN SELECT MAX(ID) from SOAP_MONITORING#FONIC_RETAIL
CASE WHEN (SELECT MAX(ID) from TEMP_SOAP_MONITORING) IS NULL THEN LAST_TASK_ID + 1 ELSE (SELECT MAX(ID) from TEMP_SOAP_MONITORING) END,
CAPTURING_DATE = CURRENT_TIMESTAMP, LAST_CAPTURED_DATE = LAST_CAPT_DATE where DB_TABLE='TEMP_SOAP_MONITORING';
Your conditions and checks were all tangled up: I've untangled them to do what I think you are trying to accomplish.
UPDATE CAPTURING
SET
LAST_TASK_ID = CASE
WHEN (SELECT MAX(ID) from TEMP_SOAP_MONITORING) IS NULL AND LAST_TASK_ID IS NULL THEN (SELECT MAX(ID) FROM SOAP_MONITORING#FONIC_RETAIL)
WHEN (SELECT MAX(ID) from TEMP_SOAP_MONITORING) IS NULL THEN LAST_TASK_ID + 1
ELSE (SELECT MAX(ID) from TEMP_SOAP_MONITORING) END,
CAPTURING_DATE = CURRENT_TIMESTAMP,
LAST_CAPTURED_DATE = LAST_CAPT_DATE
WHERE DB_TABLE = 'TEMP_SOAP_MONITORING';

Select statement inside NVL

I'm trying to run the following query:
select a.*,
case when NVL (SELECT max(b.field1)
FROM b
where b.field2 = a.tbl_a_PK , 'TRUE') = 'TRUE'
then 'has no data in b'
else 'has data in b' end as b_status
from a
I checked and the select inside the nvl returns only 1 value (so there shouldn't be a problem there).
However I'm getting 'ORA-00936: missing expression'
NVL() requires 2 parameters: expression to test and default value e.g. nvl(some_field, 111). You just need to isolate query parameter by braces and provide second parameter like in this statement:
select nvl( (select 1 from dual), 34) from dual
In your variant parser expects comma after SELECT keyword and can't parse remaining string.
Exactly your statement must look like this:
select
a.*,
case when NVL(
( SELECT max(b.field1)
FROM b
where b.field2 = a.tbl_a_PK
),
'TRUE'
) = 'TRUE'
then 'has no data in b'
else 'has data in b' end as b_status
from a
Hope this helps ...
Update
In terms of performance is better to use exists rather then max :
select
a.*,
case when exists
( SELECT null
FROM b
where b.field2 = a.tbl_a_PK
and
b.field2 is not null
and
rownum = 1
),
then 'has data in b'
else 'has no data in b' end as b_status
from a
If you're searching for records in a which have/don't have associated records in b
select a.*,
case when b.field2 is null then 'has no data in b'
else 'has data in b'
as b_status
from a left outer join b
on a.tbl_a_PK = b.field2;
Should do it
the NVL(string1, replace_with) function requires 2 parameters, see docs here:
http://www.techonthenet.com/oracle/functions/nvl.php
Ora 10g docs: http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions105.htm
Since you know the problem, this query can fix it:
select a.*,
case
when (SELECT NVL(b.field2, 0) FROM b where b.field2 = a.tbl_a_PK and rownum = 1) > 0 then
'has data in b'
else
'has no data in b'
end b_status
from a
and runs faster.
You don't need max() to check if the value exists in another table, simply check if the primary key is not null.

Resources