Skip to Main Content
  • Questions
  • Create a json object that combines a person with multiple addresses

Breadcrumb

Question and Answer

Chris Saxon

Thanks for the question, Don.

Asked: August 03, 2018 - 8:30 pm UTC

Last updated: August 06, 2018 - 4:20 pm UTC

Version: 12c

Viewed 1000+ times

You Asked

I'm trying to create a json object that combines (for example) a person with multiple addresses. It could be for any parent/child relationship where there can be multiple children with multiple attributes.

-- -------------------------------------------------------------------
create table PERSON (
    PERSON_KEY number(19), 
    FNAME varchar2(20 char), 
    LNAME varchar2(20 char) 
    );
create table PERSON_ADDRESS (
    PERSON_ADDRESS_KEY number(19), 
    PERSON_KEY number(19), 
    ADDRESS varchar2(20 char), 
    CITY varchar2(20 char) 
    ); 

insert into PERSON 
select '1','Jeremy','Mallard' from dual union
select '2','Marilyn','Foster' from dual; 

insert into PERSON_ADDRESS 
select '1','1','5151 East Broadway','Tucson' from dual union
select '2','1','4001 East 4th Street','Tucson' from dual union
select '3','2','54 Snowshoe Millway','Toronto' from dual union
select '4','2','28 Garrybrook Drive','Toronto' from dual; 

commit;
-- -------------------------------------------------------------------


This is one row of the output I'm trying to generate:
{"MY_OBJ": {
    "PERSON": {
      "PERSON_KEY": 1,
      "FNAME": "Jeremy",
      "LNAME": "Mallard"
    },
    "ADDRESS": [
      {
        "PERSON_ADDRESS_KEY": 1,
        "PERSON_KEY": 1,
        "ADDRESS": "5151 East Broadway",
        "CITY": "Tucson"
      },
      {
        "PERSON_ADDRESS_KEY": 2,
        "PERSON_KEY": 1,
        "ADDRESS": "4001 East 4th Street",
        "CITY": "Tucson"
      }]
  }
}

This is the closest I've come, but it's not right.
-- -------------------------------------------------------------------
select 
    json_object(
        'PERSON_KEY' value p.PERSON_KEY, 
        'FNAME' value p.FNAME, 
        'LNAME' value p.LNAME
        ), 
    json_objectagg(
        'PERSON_ADDRESS_OBJECT' value 
        json_object(
            'PERSON_ADDRESS_KEY' value pa.PERSON_ADDRESS_KEY, 
            'PERSON_KEY' value pa.PERSON_KEY, 
            'FNAME' value pa.ADDRESS, 
            'LNAME' value pa.CITY
            )  
         ) 
from PERSON p
join PERSON_ADDRESS pa 
    on pa.PERSON_KEY = p.PERSON_KEY 
group by p.PERSON_KEY, p.FNAME, p.LNAME;


Any help is greatly appreciated.


with LiveSQL Test Case:

and Chris said...

Your address is an array of JSON objects. So you need to json_arrayagg these documents!

From there it's just a matter of placing attributes inside the right object:

select json_object ( 
         'MY_OBJ' value json_object (
           'PERSON' value json_object(
             'PERSON_KEY' value p.PERSON_KEY, 
             'FNAME' value p.FNAME, 
             'LNAME' value p.LNAME
           )
         ), 
         'ADDRESS' value json_arrayagg (
           json_object (
             'PERSON_ADDRESS_KEY' value pa.PERSON_ADDRESS_KEY, 
             'PERSON_KEY' value pa.PERSON_KEY, 
             'FNAME' value pa.ADDRESS, 
             'LNAME' value pa.CITY
           )  
         )
      ) obj
from  PERSON p
join  PERSON_ADDRESS pa 
on    pa.PERSON_KEY = p.PERSON_KEY 
group by p.PERSON_KEY, p.FNAME, p.LNAME;

OBJ
{
  "MY_OBJ": {
    "PERSON": {
      "PERSON_KEY": 1,
      "FNAME": "Jeremy",
      "LNAME": "Mallard"
    }
  },
  "ADDRESS": [
    {
      "PERSON_ADDRESS_KEY": 1,
      "PERSON_KEY": 1,
      "FNAME": "5151 East Broadway",
      "LNAME": "Tucson"
    },
    {
      "PERSON_ADDRESS_KEY": 2,
      "PERSON_KEY": 1,
      "FNAME": "4001 East 4th Street",
      "LNAME": "Tucson"
    }
  ]
}
{
  "MY_OBJ": {
    "PERSON": {
      "PERSON_KEY": 2,
      "FNAME": "Marilyn",
      "LNAME": "Foster"
    }
  },
  "ADDRESS": [
    {
      "PERSON_ADDRESS_KEY": 3,
      "PERSON_KEY": 2,
      "FNAME": "54 Snowshoe Millway",
      "LNAME": "Toronto"
    },
    {
      "PERSON_ADDRESS_KEY": 4,
      "PERSON_KEY": 2,
      "FNAME": "28 Garrybrook Drive",
      "LNAME": "Toronto"
    }
  ]
}

Rating

  (1 rating)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Don Simpson, August 06, 2018 - 4:14 pm UTC

That's excellent! and so obvious now that I'm looking at it. :)
Chris Saxon
August 06, 2018 - 4:20 pm UTC

The answer is always obvious when you see it ;)

More to Explore

SQL

The Oracle documentation contains a complete SQL reference.