sqloracle-databaseplsqloracle19c

What's the best way to get grouped data from a table into a JSON object as tree structure


I need to get grouped data from ORACLE table into a JSON object as tree structure

Oracle version 19c if that matters

The table will be like this:

create table a_table (
    store    varchar2(100),
    brand    varchar2(100),
    product  varchar2(100),
    quantity number,
    amount   number
);

insert into a_table t (store, brand, product, quantity, amount) values ('All Motors Store', 'BWM', 'Car', 22, 57000);
insert into a_table t (store, brand, product, quantity, amount) values ('All Motors Store', 'BWM', 'Motorbike', 66, 37000);
insert into a_table t (store, brand, product, quantity, amount) values ('All Motors Store', 'CGM', 'Car', 88, 61000);
insert into a_table t (store, brand, product, quantity, amount) values ('All Motors Store', 'CGM', 'Motorbike', 77, 25000);
insert into a_table t (store, brand, product, quantity, amount) values ('All Motors Store', 'CGM', 'Bicycle', 14, 2000);
insert into a_table t (store, brand, product, quantity, amount) values ('Vehicle Store', 'BWM', 'Car', 2, 40000);
insert into a_table t (store, brand, product, quantity, amount) values ('Vehicle Store', 'BWM', 'Motorbike', 6, 22000);
insert into a_table t (store, brand, product, quantity, amount) values ('Vehicle Store', 'BWM', 'Bicycle', 6, 2300);
insert into a_table t (store, brand, product, quantity, amount) values ('Vehicle Store', 'CGM', 'Car', 8, 50000);
insert into a_table t (store, brand, product, quantity, amount) values ('Vehicle Store', 'CGM', 'Motorbike', 7, 21000);
commit;

And the result structure must be like this:

{
    "items": [
        {
            "key": "All Motors Store",
            "summary": [267, 182000],
            "items": [
                {
                    "key": "BWM",
                    "summary": [88, 94000],
                    "items": [
                        {
                            "key": "Car",
                            "summary": [22, 57000]
                        },
                        {
                            "key": "Motorbike",
                            "summary": [66, 37000]
                        }
                    ]
                },
                {
                    "key": "CGM",
                    "summary": [179, 88000],
                    "items": [
                        {
                            "key": "Bicycle",
                            "summary": [14, 2000]
                        },
                        {
                            "key": "Car",
                            "summary": [88, 61000]
                        },
                        {
                            "key": "Motorbike",
                            "summary": [77, 25000]
                        }
                    ]
                }
            ]
        },
        {
            "key": "Vehicle Store",
            "summary": [29, 135300],
            "items": [
                {
                    "key": "BWM",
                    "summary": [14, 64300],
                    "items": [
                        {
                            "key": "Bicycle",
                            "summary": [6, 2300]
                        },
                        {
                            "key": "Car",
                            "summary": [2, 40000]
                        },
                        {
                            "key": "Motorbike",
                            "summary": [6, 22000]
                        }
                    ]
                },
                {
                    "key": "CGM",
                    "summary": [15, 71000],
                    "items": [
                        {
                            "key": "Car",
                            "summary": [8, 50000]
                        },
                        {
                            "key": "Motorbike",
                            "summary": [7, 21000]
                        }
                    ]
                }
            ]
        }
    ],
    "summary": [296, 317300]
}

What would be the best way to do this?


Solution

  • GROUP BY store, brand and aggregate and then use a second pass to GROUP BY store and aggregate again and then use a third pass to aggregate over the entire result set:

    SELECT JSON_OBJECT(
             KEY 'items' VALUE JSON_ARRAYAGG(
               JSON_OBJECT(
                 KEY 'key' VALUE store,
                 KEY 'summary' VALUE JSON_ARRAY(SUM(brand_quantity), SUM(brand_amount)),
                 KEY 'items' VALUE JSON_ARRAYAGG(json FORMAT JSON)
               )
               RETURNING CLOB
             ),
             KEY 'summary' VALUE JSON_ARRAY(
               SUM(SUM(brand_quantity)),
               SUM(SUM(brand_amount))
             )
             RETURNING CLOB
           ) AS json
    FROM   (
      SELECT store,
             SUM(quantity) AS brand_quantity,
             SUM(amount) AS brand_amount,
             JSON_OBJECT(
               KEY 'key' VALUE brand,
               KEY 'summary' VALUE JSON_ARRAY(SUM(quantity), SUM(amount)),
               KEY 'items' VALUE JSON_ARRAYAGG(
                 JSON_OBJECT(
                   KEY 'key' VALUE product,
                   KEY 'summary' VALUE JSON_ARRAY(quantity, amount)
                   RETURNING CLOB
                 )
                 RETURNING CLOB
               )
               RETURNING CLOB
             ) AS json
      FROM   a_table
      GROUP BY store, brand
    )
    GROUP BY store
    

    Which, for the sample data, outputs:

    JSON
    {"items":[{"key":"All Motors Store","summary":[267,182000],"items":[{"key":"BWM","summary":[88,94000],"items":[{"key":"Car","summary":[22,57000]},{"key":"Motorbike","summary":[66,37000]}]},{"key":"CGM","summary":[179,88000],"items":[{"key":"Car","summary":[88,61000]},{"key":"Bicycle","summary":[14,2000]},{"key":"Motorbike","summary":[77,25000]}]}]},{"key":"Vehicle Store","summary":[29,135300],"items":[{"key":"BWM","summary":[14,64300],"items":[{"key":"Car","summary":[2,40000]},{"key":"Bicycle","summary":[6,2300]},{"key":"Motorbike","summary":[6,22000]}]},{"key":"CGM","summary":[15,71000],"items":[{"key":"Car","summary":[8,50000]},{"key":"Motorbike","summary":[7,21000]}]}]}],"summary":[296,317300]}

    fiddle