【问题标题】:Oracle JSON_OBJECT NULL ON NULL clause not workingOracle JSON_OBJECT NULL ON NULL 子句不起作用
【发布时间】:2020-06-22 11:50:48
【问题描述】:

我正在尝试让 Oracle 在 SQL NULL 数据上生成 JSON 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 18c

【问题讨论】:

    标签: sql json oracle oracle18c


    【解决方案1】:

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

    在此声明,其他功能也会受到影响,例如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 是此类错误的典型且众所周知的解决方法(此类错误已经很老了)
    • @SayanMalakshinov:这可能适用于临时情况,尽管 1) 仅适用于数字或日期,而不适用于字符串 2) 仅当它未添加到每个表达式或相同的错误时重新出现。在这种情况下,我的解决方法似乎更彻底。
    • 1) ||'' for strings :) 2) 仅当它没有添加到每个表达式中,或者相同的错误重新出现时。不,你只需与其他函数调用有 1 个最小差异。也许您的解决方法更彻底,但也更难 - 每次调用额外的 cpu 负载、闩锁等
    • + 返回而不是强制转换:json_arrayagg((select a from dual) absent on null returning varchar2(10)) gist.github.com/xtender/e8e686cbfad1bae72467ed440b5e0253
    【解决方案2】:

    你发现了一个错误。 我已提交 错误 31013529 - 两个 JSON_OBJECT 在 NULL 处理程序上具有不同的返回错误结果

    我们会尽快修复它并将其包含在捆绑补丁中。 如果您需要一次性补丁,请告诉我们

    谢谢 b

    【讨论】:

    • 我一个月前安装了 oracle 19,但仍然看到这个问题。能贴出需要什么补丁吗?
    【解决方案3】:

    这对我来说似乎是一个错误:

    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) 换行会更改结果集 (https://stackoverflow.com/a/52561721/5070879) 时会出现这些奇怪的情况之一。


    我猜是某种优化机制(“公共子表达式消除”)导致 exp 在第一次/最后一次出现时被评估。如果您更改密钥,它可以正常工作:

    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

    【讨论】:

      【解决方案4】:

      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} | {“一”: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小提琴here

      【讨论】:

      • @LukasEder 补充一下,这不是我第一次看到这种模式(即以第一次/最后一次出现作为执行模板:stackoverflow.com/questions/52533487/…
      • @LukaszSzozda:我以前也见过,例如在 HSQLDB 或 MariaDB 中,尚未在 Oracle 中。
      • 这是一个错误,已提交(31013529,虽然目前尚未公开)
      • 简单的+0 是此类错误的典型且众所周知的解决方法(这种类型的错误已经很老了)
      【解决方案5】:

      为了获取值,您需要进行一些小改动:

      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}

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-06-23
        • 2021-08-16
        • 2018-08-19
        • 1970-01-01
        • 2017-01-16
        • 1970-01-01
        • 2011-06-15
        • 2013-02-17
        相关资源
        最近更新 更多