본문 바로가기
3. 데이터관리

오라클 데이터베이스 23c - JSON Relational Duality Views

by xTech 2024. 3. 27.

관계형 데이터 모델은 데이터 정규화를 사용하여 무결성을 보장하고 중복을 피함으로 데이터 저장/관리에 매우 효율적입니다. JSON 데이터 모델인 경우 계층이 구조화된 형태로 저장 & 직접 맵핑하기 때문에 데이터 접근/처리 시 복잡성을 피할 수는 있으나 저장 형식으로는 이상적이지 않습니다.

 

 오라클 데이터베이스의 최신 버전인 23c에서 새롭게 제공되는 기능인 JSON Relational Duality Views는 JSON 타입의 데이터를 관리하는 측면에서 개발자에게 혁신적인 유연성과 간편성을 제공하는 기능입니다. 앞서 오라클 데이터베이스에서 JSON 데이터를 어떻게 사용할 수 있는지 알아보았는데, JSON Relational Duality Views 를 활용한다면 특정 데이터 모델을 특정 데이터베이스를 선택하지 않아도 두 모델을 모두 사용할 수 있습니다.

 

이 기능은 기존 관계형 데이터모델, 테이블에 데이터베이스 객체인 뷰를 생성하고 이 뷰를 통해서 JSON 타입의 데이터를 관리할 수 있도록 지원합니다.  JSON 모델의 유연성과 데이터 접근 편의성을 사용하면서 관계형 모델의 저장 효율성과 이점을 동시에 누릴 수 있습니다.

 

간단한 예제를 통해서 기능을 확인해보도록 하겠습니다.

 

1.  기존과 동일하게 행과 열로 이루어진 테이블을 하나 생성합니다.

CREATE TABLE IF NOT EXISTS team
(team_id INTEGER GENERATED BY DEFAULT ON NULL AS IDENTITY,
name    VARCHAR2(255) NOT NULL UNIQUE,
points  INTEGER NOT NULL,
CONSTRAINT team_pk PRIMARY KEY(team_id));


CREATE TABLE IF NOT EXISTS driver
(driver_id INTEGER GENERATED BY DEFAULT ON NULL AS IDENTITY,
name      VARCHAR2(255) NOT NULL UNIQUE,
points    INTEGER NOT NULL,
team_id   INTEGER,
CONSTRAINT driver_pk PRIMARY KEY(driver_id),
CONSTRAINT driver_fk FOREIGN KEY(team_id) REFERENCES team(team_id));

 

 

2.  생성한 테이블에 JSON Relational Duality Views 를 생성합니다.

CREATE OR REPLACE JSON RELATIONAL DUALITY VIEW team_dv AS
SELECT JSON {'teamId'  IS t.team_id,
            'name'    IS t.name,
            'points'  IS t.points,
            'driver'  IS
                [ SELECT JSON {'driverId' IS d.driver_id,
                                'name'     IS d.name,
                                'points'   IS d.points WITH NOCHECK}
                    FROM driver d WITH INSERT UPDATE
                    WHERE d.team_id = t.team_id ]}
    FROM team t WITH INSERT UPDATE DELETE;

 

 

3. 생성된 뷰에 데이터를 Insert해보는데, JSON 형태로 진행합니다.

INSERT INTO team_dv VALUES ('{"teamId" : 301,
                          "name"   : "Red Bull",
                          "points" : 0,
                          "driver" : [ {"driverId" : 101,
                                        "name"     : "Max Verstappen",
                                        "points"   : 0},
                                       {"driverId" : 102,
                                        "name"     : "Sergio Perez",
                                        "points"   : 0} ]}');

INSERT INTO team_dv VALUES ('{"teamId" : 302,
                            "name"   : "Ferrari",
                            "points" : 0,
                            "driver" : [ {"driverId" : 103,
                                            "name"     : "Charles Leclerc",
                                            "points"   : 0},
                                        {"driverId" : 104,
                                            "name"     : "Carlos Sainz Jr",
                                            "points"   : 0} ]}');

INSERT INTO team_dv VALUES ('{"teamId" : 2,
                            "name"   : "Mercedes",
                            "points" : 0,
                            "driver" : [ {"driverId" : 105,
                                            "name"     : "George Russell",
                                            "points"   : 0},
                                        {"driverId" : 106,
                                            "name"     : "Lewis Hamilton",
                                            "points"   : 0} ]}');
COMMIT;

 

4. 데이터 조회를 SQL로 테이블에서 해보겠습니다.

SQL> select * from team;

   TEAM_ID NAME                                         POINTS
---------- ---------------------------------------- ----------
       301 Red Bull                                          0
       302 Ferrari                                           0
         2 Mercedes                                          0

SQL> select * from driver ;

 DRIVER_ID NAME                                         POINTS    TEAM_ID
---------- ---------------------------------------- ---------- ----------
       101 Max Verstappen                                    0        301
       102 Sergio Perez                                      0        301
       103 Charles Leclerc                                   0        302
       104 Carlos Sainz Jr                                   0        302
       105 George Russell                                    0          2
       106 Lewis Hamilton                                    0          2

6 rows selected.

SQL>

 

5. 데이터 조회를 SQL로 뷰에서 해보겠습니다.

SQL> select * from team_dv dv
WHERE dv.data.name LIKE 'Mercedes%';  2  

DATA
--------------------------------------------------------------------------------
{"_metadata":{"etag":"536001F31A8718819AEEF28EC20D8677","asof":"0000000000115798



SQL> SELECT json_serialize(data PRETTY) FROM team_dv dv
WHERE dv.data.name LIKE 'Mercedes%';  2  

JSON_SERIALIZE(DATAPRETTY)
------------------------------------------------------------
{
  "_metadata" :
  {
    "etag" : "536001F31A8718819AEEF28EC20D8677",
    "asof" : "000000000011579A"
  },
  "teamId" : 2,
  "name" : "Mercedes",
  "points" : 0,
  "driver" :
  [
    {
      "driverId" : 105,
      "name" : "George Russell",
      "points" : 0
    },
    {
      "driverId" : 106,
      "name" : "Lewis Hamilton",
      "points" : 0
    }
  ]
}


SQL> SELECT json_serialize(data PRETTY) FROM team_dv dv
WHERE dv.data.name LIKE 'Ferrari%';  2  

JSON_SERIALIZE(DATAPRETTY)
------------------------------------------------------------
{
  "_metadata" :
  {
    "etag" : "7B62699FECECFF392143BA7A335E5E47",
    "asof" : "000000000011579C"
  },
  "teamId" : 302,
  "name" : "Ferrari",
  "points" : 0,
  "driver" :
  [
    {
      "driverId" : 103,
      "name" : "Charles Leclerc",
      "points" : 0
    },
    {
      "driverId" : 104,
      "name" : "Carlos Sainz Jr",
      "points" : 0
    }
  ]
}


SQL>

 

 

6. 데이터 조작을 해보겠습니다.

   

-- 뷰에 신규 팀 정보와 새로운 드라이버의 정보를 입력해보고, 테이블에 각각 새로운 정보도 넣었습니다.

INSERT INTO team_dv VALUES ('{"teamId" : 888,
                            "name"   : "NVIDIA",
                            "points" : 0,
                            "driver" : [ {"driverId" : 555,
                                            "name"     : "MR.KIM",
                                            "points"   : 0},
                                        {"driverId" : 666,
                                            "name"     : "MR.KO",
                                            "points"   : 0} ]}');

INSERT INTO team values (999,'BITCOIN',0) ;
INSERT INTO driver values (777,'MR.JEONG',0,999 ); 
INSERT INTO driver values(888,'MR.DOH',0,999 );

COMMIT;

-- 뷰를 통해 JSON형태로 한번에 조회 가능합니다.

SQL> SELECT json_serialize(data PRETTY) FROM team_dv dv where dv.data.teamId in (888,999)  ;

JSON_SERIALIZE(DATAPRETTY)
------------------------------------------------------------
{
  "_metadata" :
  {
    "etag" : "EF833BD9790304C28A9FEA8EC8169A5D",
    "asof" : "00000000001158DB"
  },
  "teamId" : 888,
  "name" : "NVIDIA",
  "points" : 0,
  "driver" :
  [
    {
      "driverId" : 555,
      "name" : "MR.KIM",
      "points" : 0
    },
    {
      "driverId" : 666,
      "name" : "MR.KO",
      "points" : 0
    }
  ]
}

{
  "_metadata" :
  {
    "etag" : "9B02801782554D6196B7043E7F544AEB",
    "asof" : "00000000001158DB"
  },
  "teamId" : 999,
  "name" : "BITCOIN",
  "points" : 0,
  "driver" :
  [
    {
      "driverId" : 777,
      "name" : "MR.JEONG",
      "points" : 0
    },
    {
      "driverId" : 888,
      "name" : "MR.DOH",
      "points" : 0
    }
  ]
}


SQL> 


-- 뷰를 통해ㅐ 특정 필드 업데이트 테스트 ( 팀 이름을 BITCOIN에서 DOGE로 업데이트 )
SQL> UPDATE team_dv dv
SET data = json_transform(data, SET '$.name' = 'DOGE')
WHERE dv.data.name LIKE 'BITCOIN%';  2    3  

1 row updated.

SQL> commit;

Commit complete.

SQL> SELECT json_serialize(data PRETTY) FROM team_dv dv where dv.data.name = 'DOGE'  ;

JSON_SERIALIZE(DATAPRETTY)
------------------------------------------------------------
{
  "_metadata" :
  {
    "etag" : "31DA57AC231010919768518EEF6DC05C",
    "asof" : "00000000001158FC"
  },
  "teamId" : 999,
  "name" : "DOGE",
  "points" : 0,
  "driver" :
  [
    {
      "driverId" : 777,
      "name" : "MR.JEONG",
      "points" : 0
    },
    {
      "driverId" : 888,
      "name" : "MR.DOH",
      "points" : 0
    }
  ]
}

-- 뷰를 통해 여러 필드 업데이트 테스트 ( 팀 점수와 드라이버 이름,점수를 한번에 업데이트  )

SQL> SELECT json_serialize(data PRETTY) FROM team_dv dv where dv.data.name = 'NVIDIA' ;

JSON_SERIALIZE(DATAPRETTY)
------------------------------------------------------------
{
  "_metadata" :
  {
    "etag" : "EF833BD9790304C28A9FEA8EC8169A5D",
    "asof" : "000000000011593C"
  },
  "teamId" : 888,
  "name" : "NVIDIA",
  "points" : 0,
  "driver" :
  [
    {
      "driverId" : 555,
      "name" : "MR.KIM",
      "points" : 0
    },
    {
      "driverId" : 666,
      "name" : "MR.KO",
      "points" : 0
    }
  ]
}

SQL> UPDATE team_dv dv
SET data = ('{_metadata : {"etag" : "EF833BD9790304C28A9FEA8EC8169A5D"},
                "teamId" : 888,
                "name"   : "NVIDIA",
                "points" : 100,
                "driver" : [ {"driverId" : 555,
                            "name"     : "MR.RYU",
                            "points"   : 88},
                            {"driverId" : 666,
                            "name"     : "MR.KO",
                            "points"   : 99} ]}')
    WHERE dv.data.name LIKE 'NVIDIA%';  2    3    4    5    6    7    8    9   10   11   12  

1 row updated.

SQL> commit;

Commit complete.

SQL> SELECT json_serialize(data PRETTY) FROM team_dv dv where dv.data.name = 'NVIDIA' ;

JSON_SERIALIZE(DATAPRETTY)
------------------------------------------------------------
{
  "_metadata" :
  {
    "etag" : "9E6AFF219E9B063BE95E33241A5C58CA",
    "asof" : "0000000000115AE5"
  },
  "teamId" : 888,
  "name" : "NVIDIA",
  "points" : 100,
  "driver" :
  [
    {
      "driverId" : 555,
      "name" : "MR.RYU",
      "points" : 88
    },
    {
      "driverId" : 666,
      "name" : "MR.KO",
      "points" : 99
    }
  ]
}


SQL>

 

 

 

개인 시간을 투자하여 작성된 글로서, 글의 내용에 오류가 있을 수 있으며, 글 속의 의견은 개인적인 의견입니다

댓글