Oracle Предложение JSON_OBJECT NULL ON NULL не работает - PullRequest
1 голос
/ 10 марта 2020

Я пытаюсь получить Oracle для получения JSON null значений на SQL NULL данных следующим образом:

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;

Или также:

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;

К сожалению, оба запроса приводят к:

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

Вместо этого я бы ожидал:

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

Чего мне не хватает? Я использую Oracle XE 18 c

Ответы [ 5 ]

3 голосов
/ 11 марта 2020

вы нашли ошибку. Я подал ошибку 31013529 - ДВА JSON_OBJECT С РАЗНЫМ НА NULL HANDLER ВОЗВРАЩАЮТСЯ НЕПРАВИЛЬНЫМИ РЕЗУЛЬТАТАМИ

Мы исправим это как можно скорее и включим в патчи пакета. Дайте нам знать, если вам нужен одноразовый патч

спасибо b

1 голос
/ 10 марта 2020

Похоже, есть ошибка в том, как Oracle обрабатывает JSON_OBJECT, и он будет принимать параметр из последнего JSON_on_null_clause в выражении и применять его ко всем JSON_OBJECT выражениям:

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

Если вы сделаете это:

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;

Тогда вы получите:

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

Если вы выполните тот же запрос с обращенными выражениями:

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;

Тогда вывод будет:

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

db <> Fiddle здесь

1 голос
/ 10 марта 2020

Для меня это выглядит как ошибка:

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

Вывод:

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

db <> fiddle demo

Это один из этих странных случаев, когда перенос с (SELECT exp FROM dual) изменяет набор результатов ({ ссылка }).


Я полагаю, что это какой-то механизм оптимизации (" устранение общего подвыражения "), которое вызывает опыт, оценивается один раз при первом / последнем вхождении. Если вы поменяете ключ, он будет работать нормально:

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

0 голосов
/ 11 марта 2020

Ответ Лукаша предоставляет жизнеспособный обходной путь с использованием коррелированного подзапроса.

Для записи также затрагиваются другие функции, например 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;

Выход:

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

В то время как этот обходной путь ...

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;

Дает правильный результат:

|C2        |C1        |
|----------|----------|
|[1]       |[1,null]  |
0 голосов
/ 10 марта 2020

у вас есть небольшое изменение, чтобы получить значения:

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

Результат: C1: C2: {"a": 1, "b": null} {"a": 1 }

...