Lukas Eder
Lukas Eder

Reputation: 221135

Oracle JSON_OBJECT NULL ON NULL clause not working

I'm trying to get Oracle to produce JSON null values on SQL NULL data, as follows:

select 
  json_object(key 'a' value 1, key 'b' value null null on null)   c1, 
  json_object(key 'a' value 1, key 'b' value null absent on null) c2
from dual;

Or also:

select 
  json_object(key 'a' value a, key 'b' value b null on null)   c1, 
  json_object(key 'a' value a, key 'b' value b absent on null) c2
from (
  select 1 a, null b
  from dual
) t;

Unfortunately, both queries result in:

|C1        |C2        |
|----------|----------|
|{"a":1}   |{"a":1}   |

I would have expected this, instead:

|C1                 |C2        |
|-------------------|----------|
|{"a":1,"b":null}   |{"a":1}   |

What am I missing? I'm using Oracle XE 18c

Upvotes: 3

Views: 9932

Answers (5)

Lukas Eder
Lukas Eder

Reputation: 221135

Lukasz's answer provides a viable workaround using a correlated subquery.

For the record, other functions are also affected, e.g. JSON_ARRAYAGG:

select
  json_arrayagg(a null on null) c1,
  json_arrayagg(a absent on null) c2
from (
  select 1 a from dual union all select null a from dual
) t;

Yields:

|C1        |C2        |
|----------|----------|
|[1]       |[1]       |

Whereas this workaround...

select 
  cast(json_arrayagg((select a from dual) absent on null) as varchar2(10)) c2,
  cast(json_arrayagg((select a from dual) null on null) as varchar2(10)) c1
from (
  select 1 a from dual union all select null a from dual
) t;

Produces the correct result:

|C2        |C1        |
|----------|----------|
|[1]       |[1,null]  |

Upvotes: 2

Beda Hammerschmidt
Beda Hammerschmidt

Reputation: 436

you found a bug. I have filed Bug 31013529 - TWO JSON_OBJECT WITH DIFFERENT ON NULL HANDLER RETURN WRONG RESULTS

We'll fix it asap and include it in the bundle patches. Let us know if you need a one off patch

thanks b

Upvotes: 3

Lukasz Szozda
Lukasz Szozda

Reputation: 176014

It looks like a bug for me:

select 
  json_object(key 'a' value 1, key 'b' value null null on null)   c1
  ,(SELECT json_object(key 'a' value 1, key 'b' value null absent on null) FROM dual) c2
from dual

Output:

+-------------------+---------+
|        C1         |   C2    |
+-------------------+---------+
| {"a":1,"b":null}  | {"a":1} |
+-------------------+---------+

db<>fiddle demo

It is one of these strange occurences when wrapping with (SELECT exp FROM dual) changes the resultset (https://stackoverflow.com/a/52561721/5070879).


I guess it is some optimization mechanism("common subexpression elimination") that causes the exp is evaluated once taking the first/last occurence. If you change the key it is working fine:

select 
  json_object(key 'a' value 1, key 'b' value null null on null)   c1, 
  json_object(key 'a' value 1, key 'c' value null absent on null) c2
from dual;

db<>fiddle demo

Upvotes: 2

MT0
MT0

Reputation: 168371

There appears to be a bug on how Oracle handles JSON_OBJECT and it will take the parameter from the last JSON_on_null_clause in the statement and apply it to all of the JSON_OBJECT expressions:

CREATE TABLE t ( a,b ) AS
  SELECT 1, null FROM DUAL UNION ALL
  SELECT 2, 'bb' FROM DUAL;

If you do this:

select json_object(
         KEY 'a' VALUE a,
         KEY 'b' VALUE b null on null
       ) c1,
       json_object(
         KEY 'a' VALUE a,
         KEY 'b' VALUE b absent on null
       ) c2
from   t;

Then the output is:

C1               | C2              
:--------------- | :---------------
{"a":1}          | {"a":1}         
{"a":2,"b":"bb"} | {"a":2,"b":"bb"}

If you perform the same query with the expressions reversed:

select json_object(
         KEY 'a' VALUE a,
         KEY 'b' VALUE b absent on null
       ) c2,
       json_object(
         KEY 'a' VALUE a,
         KEY 'b' VALUE b null on null
       ) c1
from   t;

Then the output is:

C2               | C1              
:--------------- | :---------------
{"a":1,"b":null} | {"a":1,"b":null}
{"a":2,"b":"bb"} | {"a":2,"b":"bb"}

db<>fiddle here

Upvotes: 3

user12467638
user12467638

Reputation: 37

you have a small change in order to get the values:

select 
 json_object(key 'a' value 1, key 'b' value null )   c1, 
 json_object(key 'a' value 1 ) c2
from dual;

The result is C1: C2: {"a":1,"b":null} {"a":1}

Upvotes: 0

Related Questions