Как объединить различные значения из нескольких списков с помощью Oracle JSON_OBJECT и JSON_ARRAYAGG

#sql #json #oracle

Вопрос:

Необходимо создать Json_Object, который может содержать несколько вложенных Json_objects, Json_arrays и Json_arrayaggs внутри.

Я создал эту таблицу с некоторыми фиктивными данными, чтобы продемонстрировать проблему:

  create table test_tbl(
test_col1 varchar2(20), 
test_col2 varchar2(20), 
test_col3 varchar2(20),
test_col4 varchar2(20),
test_col5 varchar2(20),
test_col6 varchar2(20)

);

insert into test_tbl values('val0', 'val1', 'val2', 'val7', 'val11', 'val12');
insert into test_tbl values('val0', 'val3', 'val4', 'val7','val11', 'val12');
insert into test_tbl values('val0', 'val5', 'val6', 'val7','val13', 'val14');
insert into test_tbl values('val0', 'val5', 'val6', 'val7','val11', 'val12');
insert into test_tbl values('val0', 'val5', 'val6', 'val8','val11','val12');
insert into test_tbl values('val1', 'val9', 'val10', 'val7','val11', 'val12');
insert into test_tbl values('val1', 'val9', 'val10', 'val7','val13', 'val14');
 

При использовании следующего запроса для создания Json_object:

   SELECT JSON_OBJECT (
         'output' VALUE JSON_ARRAYAGG(
           JSON_OBJECT(
             'common' VALUE test_col1,
             'list'   VALUE JSON_ARRAYAGG(
               JSON_OBJECT(
                 'key1' VALUE test_col2,
                 'key2' VALUE test_col3
               )
             ),
            'anotherlist' VALUE JSON_ARRAYAGG(
               JSON_OBJECT(
                 'key1' VALUE test_col5,
                 'key2' VALUE test_col6
               )
             )
           )
         )
       )
FROM   (
  SELECT DISTINCT
         test_col1, test_col2, test_col3, test_col5, test_col6
  FROM   test_tbl
  WHERE  test_col4 = 'val7'
)
GROUP BY
       test_col1
 

Это приводит к следующему json с повторяющимися парами ключей и значений в агрегированном массиве —

 {
  "output": [
    {
      "common": "val0",
      "list": [
        {
          "key1": "val5",
          "key2": "val6"
        },
        {
          "key1": "val3",
          "key2": "val4"
        },
        {
          "key1": "val1",
          "key2": "val2"
        },
        {
          "key1": "val5",
          "key2": "val6"
        }
      ],
      "anotherlist": [
        {
          "key1": "val13",
          "key2": "val14"
        },
        {
          "key1": "val11",
          "key2": "val12"
        },
        {
          "key1": "val11",
          "key2": "val12"
        },
        {
          "key1": "val11",
          "key2": "val12"
        }
      ]
    },
    {
      "common": "val1",
      "list": [
        {
          "key1": "val9",
          "key2": "val10"
        },
        {
          "key1": "val9",
          "key2": "val10"
        }
      ],
      "anotherlist": [
        {
          "key1": "val11",
          "key2": "val12"
        },
        {
          "key1": "val13",
          "key2": "val14"
        }
      ]
    }
  ]
}
 

В то время как мой ожидаемый Json :

 {
  "output": [
    {
      "common": "val0",
      "list": [
        {
          "key1": "val5",
          "key2": "val6"
        },
        {
          "key1": "val3",
          "key2": "val4"
        },
        {
          "key1": "val1",
          "key2": "val2"
        }
      ],
      "anotherlist": [
        {
          "key1": "val13",
          "key2": "val14"
        },
        {
          "key1": "val11",
          "key2": "val12"
        }
      ]
    },
    {
      "common": "val1",
      "list": [
        {
          "key1": "val9",
          "key2": "val10"
        }
      ],
      "anotherlist": [
        {
          "key1": "val11",
          "key2": "val12"
        },
        {
          "key1": "val13",
          "key2": "val14"
        }
      ]
    }
  ]
}
 

Заранее спасибо за любые предложения о том, как получить ожидаемый Json выше.

Ответ №1:

Используйте один DISTINCT подзапрос для первой пары столбцов, а затем используйте второй DISTINCT подзапрос для другой пары столбцов и JOIN на общем test_col1 :

 SELECT JSON_OBJECT (
         'output' VALUE JSON_ARRAYAGG(
           JSON_OBJECT(
             'common'      VALUE c23.test_col1,
             'list'        VALUE c23.list,
             'anotherlist' VALUE c56.anotherlist
           )
         )
       )
FROM   (
         SELECT test_col1,
                JSON_ARRAYAGG(
                  JSON_OBJECT(
                    'key1' VALUE test_col2,
                    'key2' VALUE test_col3
                  )
                ) AS list
         FROM   ( SELECT DISTINCT
                         test_col1, test_col2, test_col3
                  FROM   test_tbl
                  WHERE  test_col4 = 'val7'
         )
         GROUP BY test_col1
       ) c23
       INNER JOIN (
         SELECT test_col1,
                JSON_ARRAYAGG(
                  JSON_OBJECT(
                    'key1' VALUE test_col5,
                    'key2' VALUE test_col6
                  )
                ) AS anotherlist
         FROM   ( SELECT DISTINCT
                         test_col1, test_col5, test_col6
                  FROM   test_tbl
                  WHERE  test_col4 = 'val7'
         )
         GROUP BY test_col1
       ) c56
       ON ( c23.test_col1 = c56.test_col1 )
 

Выходы:

 {
  "output" : [
    {
      "common" : "val0",
      "list" : [
        {"key1" : "val1","key2" : "val2"},
        {"key1" : "val5","key2" : "val6"},
        {"key1" : "val3","key2" : "val4"}
       ],
      "anotherlist" : [
        {"key1" : "val11","key2" : "val12"},
        {"key1" : "val13","key2" : "val14"}
      ]
    },
    {
      "common" : "val1",
      "list" : [{"key1" : "val9","key2" : "val10"}],
      "anotherlist" : [
        {"key1" : "val11","key2" : "val12"},
        {"key1" : "val13","key2" : "val14"}
      ]
    }
  ]
}
 

Комментарии:

1. спасибо, теперь мне нужно расширить это, чтобы создать аналогичные узлы-братья в «другом списке» и «списке». Я пытаюсь создать подзапрос в подзапросе по аналогичным строкам и использовать предложение group by для подзапроса, которое включает уникальные ключи от обоих родителей, но конечный результат в конечном итоге содержит дубликаты.