Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

Bug do Oracle produz valores agregados duplicados em JSON_ARRAYAGG


Parece ser um bug. O plano de execução não sugere nenhum DISTINCT operação que está sendo aplicada:
---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |       |       |     6 (100)|          |
|   1 |  SORT GROUP BY     |      |     1 |    26 |            |          |
|*  2 |   TABLE ACCESS FULL| T2   |     1 |    26 |     3   (0)| 00:00:01 |
|   3 |  SORT GROUP BY     |      |     1 |    13 |            |          |
|   4 |   TABLE ACCESS FULL| T1   |     2 |    26 |     3   (0)| 00:00:01 |
---------------------------------------------------------------------------

Solução 1


Use um HAVING COUNT(*) = COUNT(*) fictício predicado:
select json_arrayagg(json_object(
  key 't1_id' value t1_id,
  key 't2' value (
    select json_arrayagg(json_object(
      key 't2_value' value t2_value
    ))
    from (
      select distinct t2.t2_value
      from t2
      where t2.t1_id = t1.t1_id
    ) t
    having count(*) = count(*) -- Workaround
  ) format json
))
from t1;

Isso produz o resultado correto:
[{
  "t1_id":1,
  "t2":[{ "t2_value":1 }]
}, {
  "t1_id":2,
  "t2":[{ "t2_value":2 }, { "t2_value":3 }]
}]

O plano agora é:
------------------------------------------------------------------------------
| Id  | Operation             | Name | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |      |       |       |     7 (100)|          |
|*  1 |  FILTER               |      |       |       |            |          |
|   2 |   SORT GROUP BY       |      |     1 |    13 |            |          |
|   3 |    VIEW               |      |     1 |    13 |     4  (25)| 00:00:01 |
|   4 |     SORT UNIQUE       |      |     1 |    26 |     4  (25)| 00:00:01 | <--
|*  5 |      TABLE ACCESS FULL| T2   |     1 |    26 |     3   (0)| 00:00:01 |
|   6 |  SORT GROUP BY        |      |     1 |    13 |            |          |
|   7 |   TABLE ACCESS FULL   | T1   |     2 |    26 |     3   (0)| 00:00:01 |
------------------------------------------------------------------------------

Solução 2


Use um UNION para impor distinção:
select json_arrayagg(json_object(
  key 't1_id' value t1_id,
  key 't2' value (
    select json_arrayagg(json_object(
      key 't2_value' value t2_value
    ))
    from (
      select distinct t2.t2_value
      from t2
      where t2.t1_id = t1.t1_id
      union select null from dual where 1 = 0 -- Dummy union
    ) t
  ) format json
))
from t1;

O plano agora é:
------------------------------------------------------------------------------
| Id  | Operation             | Name | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |      |       |       |     6 (100)|          |
|   1 |  SORT GROUP BY        |      |     1 |    13 |            |          |
|   2 |   VIEW                |      |     2 |    26 |     3   (0)| 00:00:01 |
|   3 |    SORT UNIQUE        |      |     2 |    26 |     3   (0)| 00:00:01 | <--
|   4 |     UNION-ALL         |      |       |       |            |          |
|*  5 |      TABLE ACCESS FULL| T2   |     1 |    26 |     3   (0)| 00:00:01 |
|*  6 |      FILTER           |      |       |       |            |          |
|   7 |       FAST DUAL       |      |     1 |       |     2   (0)| 00:00:01 |
|   8 |  SORT GROUP BY        |      |     1 |    13 |            |          |
|   9 |   TABLE ACCESS FULL   | T1   |     2 |    26 |     3   (0)| 00:00:01 |
------------------------------------------------------------------------------

E o resultado também está correto