Oracle bug? Query runs with either of the columns selected, but not both. Throws error "ORA-00937: not a single-group group function"

huangapple go评论53阅读模式
英文:

Oracle bug? Query runs with either of the columns selected, but not both. Throws error "ORA-00937: not a single-group group function"

问题

我正在经历一种我认为是Oracle中的错误行为,但我不确定该怎么办。

它可以在Oracle Database 21c Express Edition Release 21.0.0.0.0 - Production - Version 21.3.0.0.0上的以下查询中重现:

select json_object(
    key 'foo' value json_arrayagg((select * from dual)),
    key 'nested' value (select json_object(key 'bar' value 2) from dual)
)
from dual;

运行此查询将引发以下错误,其中位置 133将光标定位在单词'bar'的开头:

[42000][937] ORA-00937: 不是单一分组函数 位置:133

编辑:关于为什么不简化为直接的json_object()调用,实际的查询生成会产生类似以下的查询:

  key 'aggregates' value (
    select json_object(key 'min' value min("TOTAL"))
    from (
      select "INVOICE".*
      from "INVOICE"
      where "INVOICE"."BILLINGCOUNTRY" = 'Canada'
      order by
        "INVOICE"."BILLINGADDRESS" asc nulls last,
        "INVOICE"."INVOICEID" asc nulls last
      offset 0 rows
      fetch next 30 rows only
    ) "INVOICE"
  ) format json

然而,如果您注释掉其中一个键/值对,查询会运行:

Oracle bug? Query runs with either of the columns selected, but not both. Throws error "ORA-00937: not a single-group group function"

Oracle bug? Query runs with either of the columns selected, but not both. Throws error "ORA-00937: not a single-group group function"

如果将嵌套的json_object从select语句中解开,它也会运行:

Oracle bug? Query runs with either of the columns selected, but not both. Throws error "ORA-00937: not a single-group group function"

英文:

I'm experiencing behavior which I believe is a bug in Oracle and I'm unsure what to do about it.

It can be reproduced on Oracle Database 21c Express Edition Release 21.0.0.0.0 - Production - Version 21.3.0.0.0 with the following query:

select json_object(
    key 'foo' value json_arrayagg((select * from dual)),
    key 'nested' value (select json_object(key 'bar' value 2) from dual)
)
from dual;

Running this query will throw the following error, where position 133 places the cursor at the start of the word 'bar':

> [42000][937] ORA-00937: not a single-group group function Position: 133

EDIT: as to why not simplify to a direct json_object() call, the real query generation produces queries like:

  key 'aggregates' value (
    select json_object(key 'min' value min("TOTAL"))
    from (
      select "INVOICE".*
      from "INVOICE"
      where "INVOICE"."BILLINGCOUNTRY" = 'Canada'
      order by
        "INVOICE"."BILLINGADDRESS" asc nulls last,
        "INVOICE"."INVOICEID" asc nulls last
      offset 0 rows
      fetch next 30 rows only
    ) "INVOICE"
  ) format json

However, if you comment out either of the key/value pairs, the query runs:

Oracle bug? Query runs with either of the columns selected, but not both. Throws error "ORA-00937: not a single-group group function"

Oracle bug? Query runs with either of the columns selected, but not both. Throws error "ORA-00937: not a single-group group function"

It also runs if you unwrap the nested json_object from a select statement:

Oracle bug? Query runs with either of the columns selected, but not both. Throws error "ORA-00937: not a single-group group function"

答案1

得分: 2

以下是已翻译的内容:

You can simplify the query to:

select json_object(
         key 'foo' value (select json_arrayagg(dummy) from dual),
         key 'nested' value (select json_object(key 'bar' value 2) from dual)
       ) AS json
from   dual;

Then to:

select json_object(
         key 'foo' value (select json_arrayagg(dummy) from dual),
         key 'nested' value json_object(key 'bar' value 2)
       ) AS json
from   dual;

and then further to:

select json_object(
         key 'foo' value json_arrayagg(dummy),
         key 'nested' value json_object(key 'bar' value 2)
       ) AS json
from   dual;

Which all output:

JSON
{"foo":["X"],"nested":{"bar":2}}

fiddle


As for your update, you can move the JSON_OBJECT out of the sub-query and return the minimum:

SELECT JSON_OBJECT(
         key   'aggregates'
         value JSON_OBJECT(
           key   'min'
           value ( select MIN(TOTAL)
                   from   ( select TOTAL
                            from   INVOICE
                            where  BILLINGCOUNTRY = 'Canada'
                            order by
                                   BILLINGADDRESS asc nulls last,
                                   INVOICEID asc nulls last
                            offset 0 rows
                            fetch next 30 rows only
                          )
                 )
         )
       ) AS json
FROM   DUAL;

Which, for the sample data:

CREATE TABLE invoice (total, billingcountry, billingaddress, invoiceid) AS
SELECT DBMS_RANDOM.VALUE(110,120), 'Canada', 'ABC', LEVEL FROM DUAL CONNECT BY LEVEL <= 10 UNION ALL
SELECT 100, 'Canada', 'ABC', 11 FROM DUAL UNION ALL
SELECT DBMS_RANDOM.VALUE(110,120), 'Canada', 'ABC', LEVEL + 11 FROM DUAL CONNECT BY LEVEL <= 29 UNION ALL
SELECT 90, 'Canada', 'ABC', 41 FROM DUAL;

Outputs:

JSON
{"aggregates":{"min":100}}

fiddle

英文:

You can simplify the query to:

select json_object(
         key &#39;foo&#39; value (select json_arrayagg(dummy) from dual),
         key &#39;nested&#39; value (select json_object(key &#39;bar&#39; value 2) from dual)
       ) AS json
from   dual;

Then to:

select json_object(
         key &#39;foo&#39; value (select json_arrayagg(dummy) from dual),
         key &#39;nested&#39; value json_object(key &#39;bar&#39; value 2)
       ) AS json
from   dual;

and then further to:

select json_object(
         key &#39;foo&#39; value json_arrayagg(dummy),
         key &#39;nested&#39; value json_object(key &#39;bar&#39; value 2)
       ) AS json
from   dual;

Which all output:

JSON
{"foo":["X"],"nested":{"bar":2}}

fiddle


As for your update, you can move the JSON_OBJECT out of the sub-query and return the minimum:

SELECT JSON_OBJECT(
         key   &#39;aggregates&#39;
         value JSON_OBJECT(
           key   &#39;min&#39;
           value ( select MIN(TOTAL)
                   from   ( select TOTAL
                            from   INVOICE
                            where  BILLINGCOUNTRY = &#39;Canada&#39;
                            order by
                                   BILLINGADDRESS asc nulls last,
                                   INVOICEID asc nulls last
                            offset 0 rows
                            fetch next 30 rows only
                          )
                 )
         )
       ) AS json
FROM   DUAL;

Which, for the sample data:

CREATE TABLE invoice (total, billingcountry, billingaddress, invoiceid) AS
SELECT DBMS_RANDOM.VALUE(110,120), &#39;Canada&#39;, &#39;ABC&#39;, LEVEL FROM DUAL CONNECT BY LEVEL &lt;= 10 UNION ALL
SELECT 100, &#39;Canada&#39;, &#39;ABC&#39;, 11 FROM DUAL UNION ALL
SELECT DBMS_RANDOM.VALUE(110,120), &#39;Canada&#39;, &#39;ABC&#39;, LEVEL + 11 FROM DUAL CONNECT BY LEVEL &lt;= 29 UNION ALL
SELECT 90, &#39;Canada&#39;, &#39;ABC&#39;, 41 FROM DUAL;

Outputs:

JSON
{"aggregates":{"min":100}}

fiddle

答案2

得分: 0

Output:

data
{"rows":[{"InvoiceId":1,"BillingCountry":"Canada"},{"InvoiceId":2,"BillingCountry":"Canada"},{"InvoiceId":3,"BillingCountry":"Canada"}],"aggregates":{"min":10}}
英文:

In case anyone runs across this in the future, a workaround discovered by a coworker is to move the json_arrayagg() into the subquery that produces the json_object():

with INVOICE_DATA(INVOICEID, BILLINGCOUNTRY, TOTAL) as (
    SELECT 1 as INVOICEID, &#39;Canada&#39; as BILLINGCOUNTRY, 10 as TOTAL FROM DUAL UNION ALL
    SELECT 2 as INVOICEID, &#39;Canada&#39; as BILLINGCOUNTRY, 20 as TOTAL FROM DUAL UNION ALL
    SELECT 3 as INVOICEID, &#39;Canada&#39; as BILLINGCOUNTRY, 30 as TOTAL FROM DUAL
)

select json_object(
  -- Removed json_arrayagg(&quot;j&quot;) here
  key &#39;rows&#39; value &quot;j&quot; format json,
  key &#39;aggregates&#39; value (
    select json_object(key &#39;min&#39; value min(&quot;TOTAL&quot;))
    from (
      select &quot;INVOICE_DATA&quot;.*
      from &quot;INVOICE_DATA&quot;
    ) &quot;INVOICE&quot;
  ) format json
  returning clob
) &quot;data&quot;
from (
  --- json_arrayagg call moved to wrap &quot;j&quot; directly here
  select json_arrayagg(json_object(
    key &#39;InvoiceId&#39; value &quot;INVOICEID&quot;,
    key &#39;BillingCountry&#39; value &quot;BILLINGCOUNTRY&quot;
    returning clob
  )) &quot;j&quot;
  from (
    select &quot;INVOICE_DATA&quot;.*
    from &quot;INVOICE_DATA&quot;
  ) &quot;INVOICE&quot;
) &quot;alias_70049180&quot;

Output:

data
{"rows":[{"InvoiceId":1,"BillingCountry":"Canada"},{"InvoiceId":2,"BillingCountry":"Canada"},{"InvoiceId":3,"BillingCountry":"Canada"}],"aggregates":{"min":10}}

huangapple
  • 本文由 发表于 2023年6月22日 02:50:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/76526290.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定