Autonomous Database 23ai：Object StorageにあるJSONデータからJSON Relational Dualityビューを作成してデータをインポートしてみた

# はじめに

Oracle Database 23aiの複数の新機能を利用して、Object StorageにあるJSONデータをもとにしてJSON Ralational Dualityビューを作成し、作成したJSON Relationa Dualityビューにデータをインポートしてみました。

今回利用したOracle Database 23aiの新機能は以下の機能です。

**・外部表におけるJSONデータ型のデータへのアクセスおよびダイレクト・ロードのサポート**
**・JSON-to-Dualityコンバーター**
**・JSON-to-Dualityインポーター**


# 1. 事前準備

今回の検証では、コース（講義）情報のJSONデータを格納しているファイルcourse_data.jsonを使用しました。

```json:course_data.json
[
 {"courseId":"MATH101","name":"Algebra","creditHours":3,"students":[{"studentId":1,"name":"Donald P."}],"teacher":{"teacherId":101,"name":"Abdul J."},"Notes":"Prerequisite for Advanced Algebra"},
 {"courseId":"MATH102","name":"Calculus","creditHours":4,"students":[{"studentId":2,"name":"Elena H."},{"studentId":10,"name":"Ming L."}],"teacher":{"teacherId":101,"name":"Abdul J."}},
 {"courseId":"CS101","name":"Algorithms","creditHours":5,"students":[{"studentId":3,"name":"Francis K."},{"studentId":4,"name":"Georgia D."}],"teacher":{"teacherId":102,"name":"Betty Z."}},
 {"courseId":"CS102","name":"Data Structures","creditHours":3,"students":[{"studentId":5,"name":"Hye E."},{"studentId":7,"name":"Jatin S."},{"studentId":8,"name":"Katie H."}],"teacher":{"teacherId":102,"name":"Betty Z."}},
 {"courseId":"MATH103","name":"Advanced Algebra","creditHours":"3","students":[{"studentId":6,"name":"Ileana D."},{"studentId":9,"name":"Luis F."}],"teacher":{"teacherId":103,"name":"Colin J."}}
]
```

このcourse_data.jsonをOCI Object StorageのバケットJSONにアップロードしました。

![スクリーンショット 2024-07-11 14.30.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/784824/29edfd57-ba36-de90-1191-a9b27a73850f.png)

また、今回はAutonomous DatabaeからObject Storageにアクセスする際のクレデンシャルとして、リソース・プリンシパル（OCI$RESOURCE_PRINCIPAL）を使用しました。
リソース・プリンシパルの詳細はこちらのマニュアルをご参照ください。

https://docs.oracle.com/cd//E83857_01/paas/autonomous-database/serverless/adbsb/resource-principal.html#GUID-E283804C-F266-4DFB-A9CF-B098A21E496A

# 2. インライン外部表によるObjest Storage上にあるJSONデータの参照

Oracle Database 23aiから、外部表において、JSONデータ型へのアクセスとダイレクトロードがサポートされています。

今回は、ORACLE_BIGDATAアクセスドライバーを使用したインライン外部表を使用して、Object Storage上にあるJSONデータにアクセスしてみます。

まずは、SELECT COUNT(*)で、Object Storage上のJSONファイルに正しくアクセスできるかを確認してみます。

```
SQL> SELECT COUNT(*)
  2  FROM EXTERNAL(
  3  	    (data JSON)
  4  	     TYPE oracle_bigdata
  5  	     ACCESS PARAMETERS(
  6  		 com.oracle.bigdata.json.path = '$[*]'
  7  		 com.oracle.bigdata.fileformat = jsondoc
  8  		 com.oracle.bigdata.credential.name = OCI$RESOURCE_PRINCIPAL
  9  	     )
 10  	     LOCATION ('https://objectstorage.ap-tokyo-1.oraclecloud.com/n/********/b/JSON/o/course_data.json')
 11  	     REJECT LIMIT UNLIMITED);

  COUNT(*)
----------
	     5

SQL> 
```

インライン外部表を使用して、Object Storage上のJSONデータにアクセスできることが確認できました。

次に、実際のインライン外部表の内容を確認してみます。

```
SQL> set long 1000
SQL> set pagesize 500
SQL> SELECT JSON_SERIALIZE (data RETURNING CLOB PRETTY) data
  2  FROM EXTERNAL(
  3  	    (data JSON)
  4  	     TYPE oracle_bigdata
  5  	     ACCESS PARAMETERS(
  6  		 com.oracle.bigdata.json.path = '$[*]'
  7  		 com.oracle.bigdata.fileformat = jsondoc
  8  		 com.oracle.bigdata.credential.name = OCI$RESOURCE_PRINCIPAL
  9  	     )
 10  	     LOCATION ('https://objectstorage.ap-tokyo-1.oraclecloud.com/n/********/b/JSON/o/course_data.json')
 11  	     REJECT LIMIT UNLIMITED);

DATA
--------------------------------------------------------------------------------
{
  "courseId" : "MATH101",
  "name" : "Algebra",
  "creditHours" : 3,
  "students" :
  [
    {
      "studentId" : 1,
      "name" : "Donald P."
    }
  ],
  "teacher" :
  {
    "teacherId" : 101,
    "name" : "Abdul J."
  },
  "Notes" : "Prerequisite for Advanced Algebra"
}

{
  "courseId" : "MATH102",
  "name" : "Calculus",
  "creditHours" : 4,
  "students" :
  [
    {
      "studentId" : 2,
      "name" : "Elena H."
    },
    {
      "studentId" : 10,
      "name" : "Ming L."
    }
  ],
  "teacher" :
  {
    "teacherId" : 101,
    "name" : "Abdul J."
  }
}

{
  "courseId" : "CS101",
  "name" : "Algorithms",
  "creditHours" : 5,
  "students" :
  [
    {
      "studentId" : 3,
      "name" : "Francis K."
    },
    {
      "studentId" : 4,
      "name" : "Georgia D."
    }
  ],
  "teacher" :
  {
    "teacherId" : 102,
    "name" : "Betty Z."
  }
}

{
  "courseId" : "CS102",
  "name" : "Data Structures",
  "creditHours" : 3,
  "students" :
  [
    {
      "studentId" : 5,
      "name" : "Hye E."
    },
    {
      "studentId" : 7,
      "name" : "Jatin S."
    },
    {
      "studentId" : 8,
      "name" : "Katie H."
    }
  ],
  "teacher" :
  {
    "teacherId" : 102,
    "name" : "Betty Z."
  }
}

{
  "courseId" : "MATH103",
  "name" : "Advanced Algebra",
  "creditHours" : "3",
  "students" :
  [
    {
      "studentId" : 6,
      "name" : "Ileana D."
    },
    {
      "studentId" : 9,
      "name" : "Luis F."
    }
  ],
  "teacher" :
  {
    "teacherId" : 103,
    "name" : "Colin J."
  }
}


SQL> 
```

Object Storage上にあるファイルcourse_data.json内の各JSONドキュメントが、列値として返ってくること確認できました。

# 3. インライン外部表を使用したCTASによる表の作成

インライン外部表を使用して、Object Storage上にあるJSONデータを参照できることがわかったので、CTAS（CREATE TABLE AS SELECT）でObject Storage上にあるJSONデータから実表course_jsonを作成してみます。

```
SQL> CREATE TABLE course_json AS
  2  SELECT *
  3  FROM EXTERNAL(
  4  	    (data JSON)
  5  	     TYPE oracle_bigdata
  6  	     ACCESS PARAMETERS(
  7  		 com.oracle.bigdata.json.path = '$[*]'
  8  		 com.oracle.bigdata.fileformat = jsondoc
  9  		 com.oracle.bigdata.credential.name = OCI$RESOURCE_PRINCIPAL
 10  	     )
 11  	     LOCATION ('https://objectstorage.ap-tokyo-1.oraclecloud.com/n/********/b/JSON/o/course_data.json')
 12  	     REJECT LIMIT UNLIMITED);

Table created.

SQL> SELECT tname FROM tab
  2  WHERE tname LIKE 'COURSE%';

TNAME
--------------------------------------------------------------------------------
COURSE_JSON

SQL>
```
表course_jsonが問題なく作成できました。

course_json表の構造を確認してみます。
```
SQL> desc course_json
 Name					                   Null?    Type
 ----------------------------------------- -------- ----------------------------
 DATA						                        JSON

SQL>
```
course_json表は、dataという名前のJSONデータ型の列のみを持つことがわかります。

course_json表のレコード数を確認してみます。
```
SQL> SELECT COUNT(*) FROM course_json;

  COUNT(*)
----------
	     5

SQL>
```

ファイルcourse_data内のJSONドキュメントの数と同じ5件のレコードが作成されています。

では、course_json表に格納されているJSONデータを確認してみます。

```
SQL> set long 1000
SQL> set pagesize 500
SQL> SELECT JSON_SERIALIZE (data RETURNING CLOB PRETTY) data FROM course_json;

DATA
--------------------------------------------------------------------------------
{
  "courseId" : "MATH101",
  "name" : "Algebra",
  "creditHours" : 3,
  "students" :
  [
    {
      "studentId" : 1,
      "name" : "Donald P."
    }
  ],
  "teacher" :
  {
    "teacherId" : 101,
    "name" : "Abdul J."
  },
  "Notes" : "Prerequisite for Advanced Algebra"
}

{
  "courseId" : "MATH102",
  "name" : "Calculus",
  "creditHours" : 4,
  "students" :
  [
    {
      "studentId" : 2,
      "name" : "Elena H."
    },
    {
      "studentId" : 10,
      "name" : "Ming L."
    }
  ],
  "teacher" :
  {
    "teacherId" : 101,
    "name" : "Abdul J."
  }
}

{
  "courseId" : "CS101",
  "name" : "Algorithms",
  "creditHours" : 5,
  "students" :
  [
    {
      "studentId" : 3,
      "name" : "Francis K."
    },
    {
      "studentId" : 4,
      "name" : "Georgia D."
    }
  ],
  "teacher" :
  {
    "teacherId" : 102,
    "name" : "Betty Z."
  }
}

{
  "courseId" : "CS102",
  "name" : "Data Structures",
  "creditHours" : 3,
  "students" :
  [
    {
      "studentId" : 5,
      "name" : "Hye E."
    },
    {
      "studentId" : 7,
      "name" : "Jatin S."
    },
    {
      "studentId" : 8,
      "name" : "Katie H."
    }
  ],
  "teacher" :
  {
    "teacherId" : 102,
    "name" : "Betty Z."
  }
}

{
  "courseId" : "MATH103",
  "name" : "Advanced Algebra",
  "creditHours" : "3",
  "students" :
  [
    {
      "studentId" : 6,
      "name" : "Ileana D."
    },
    {
      "studentId" : 9,
      "name" : "Luis F."
    }
  ],
  "teacher" :
  {
    "teacherId" : 103,
    "name" : "Colin J."
  }
}


SQL>
```
上記の結果から、course_json表が、ファイルcourse_data内の各JSONドキュメントと同じ内容のJSON型の列値を持つことがわかりました。

以上で、インライン外部表を使用して、Object Storageにあるファイル内のJSONデータからCTASで実表が作成できることがわかりました。

# JSON-to-Dualityコンバーターを使用したJSON Relatioanl Dualityビューの作成

Oracle Database 23aiでは、JSONドキュメントを使用する利点とリレーショナル・モデルの利点の両方を享受できる新機能、JSON Relationl Duality（JSONとリレーショナルの二面性）が実装されています。

JSON Relational Dualiyの詳細はこちらのマニュアルをご参照ください。

https://docs.oracle.com/cd/F82042_01/jsnvu/overview-json-relational-duality-views.html

JSON Relational Dualityでは、JSON Relational Dualityビューという新しいビューを使用して、JSONとリレーショナルの二面性を実現します。
具体的には、データはリレーショナル表の行データとして格納し、そのリレーショナル・データにJSONドキュメントとしてアクセスするためのインターフェースを提供するのが、JSON Relational Dualityビューになります。

Oracle Database 23ai（23.4）では、既存のJSONドキュメント・セットからJSON Relational Dualityビューおよびそのベースとなるデータベース・オブジェクト（表、インデックス、制約、トリガー等）を作成するDDLを生成するためのJSON-to-Dualityコンバーターというツールが用意されています。

ここでは、JSON-to-Dualityコンバーターを使用して、先ほど作成したcourse_json表に格納されているJSONドキュメントを元にしたJSON Relational Dualityビューを作成してみます。

JSON Relational Dualityビューおよびそのベースとなるデータベース・オブジェクトのDDLの生成には、DBMS_JSON_DUALITY.INFER_AND_GENERATE_SCHEMAファンクションを使用します。
パラメータtableNamesには、JSONドキュメントが格納されている表の名前、パラメータviewNamesには作成するJSON Relational Dualityビューの名前を指定します。

こちらのPL/SQLブロックを実行すると、DBMS_JSON_DUALITY.INFER_AND_GENERATE_SCHEMAファンクションを実行して表course_json内のJSONドキュメントの構造、データを元に、JSON Relational Dualityビューcourseおよびそのベースとなるデータベース・オブジェクトのDDLを生成し、その結果を変数schema_sqlに格納、最後にDBMS_OUTPUT.PUT_LINEプロシージャでschema_sqlの内容（生成されたDDL）を表示します。

```
DECLARE
    schema_sql CLOB;
BEGIN
    schema_sql :=
        DBMS_JSON_DUALITY.INFER_AND_GENERATE_SCHEMA(
            JSON('{"tableNames"   : ["COURSE_JSON"],
                   "viewNames"    : ["COURSE"],
                   "minFrequency" : 0}'
            )
        );
  DBMS_OUTPUT.PUT_LINE('DDL Script: ');
  DBMS_OUTPUT.PUT_LINE(schema_sql);
END;
/
```

PL/SQLブロックを実際に実行してみます。

```
SQL> set linesize 200
SQL> set serveroutput on
SQL> DECLARE
  2  	 schema_sql CLOB;
  3  BEGIN
  4  	 schema_sql :=
  5  	     DBMS_JSON_DUALITY.INFER_AND_GENERATE_SCHEMA(
  6  		 JSON('{"tableNames"   : ["COURSE_JSON"],
  7  			    "viewNames"    : ["COURSE"],
  8  			    "minFrequency" : 0}'
  9  		 )
 10  	     );
 11      DBMS_OUTPUT.PUT_LINE('DDL Script: ');
 12      DBMS_OUTPUT.PUT_LINE(schema_sql);
 13  END;
 14  /
DDL Script:
BEGIN 
EXECUTE IMMEDIATE 'CREATE TABLE course_root(
   name  varchar2(64)  /* UNIQUE */,
   notes  varchar2(64),
   course_id  varchar2(64)  DEFAULT ON NULL SYS_GUID(),
   credit_hours  varchar2(64),
   teacher_id_course_teacher  number,
   ora$flex  JSON(Object),
   PRIMARY KEY(course_id)
)';

EXECUTE IMMEDIATE 'CREATE TABLE course_students(
   name  varchar2(64)  /* UNIQUE */,
   student_id  number GENERATED BY DEFAULT ON NULL AS IDENTITY,
   course_id_course_root  varchar2(64),
   ora$flex  JSON(Object),
   PRIMARY KEY(student_id)
)';

EXECUTE IMMEDIATE 'CREATE TABLE course_teacher(
   name varchar2(64)  /* UNIQUE */,
   teacher_id  number  GENERATED BY DEFAULT ON NULL AS IDENTITY,
   ora$flex  JSON(Object),
   PRIMARY KEY(teacher_id)
)';

EXECUTE IMMEDIATE 'ALTER TABLE course_root
ADD CONSTRAINT fk_course_root_to_course_teacher FOREIGN KEY (teacher_id_course_teacher) REFERENCES course_teacher(teacher_id)';
EXECUTE IMMEDIATE 'ALTER TABLE course_students
ADD CONSTRAINT fk_course_students_to_course_root FOREIGN KEY (course_id_course_root) REFERENCES course_root(course_id)';

EXECUTE IMMEDIATE 'CREATE INDEX IF NOT EXISTS fk_course_root_to_course_teacher_index ON
course_root(teacher_id_course_teacher)';
EXECUTE IMMEDIATE 'CREATE INDEX IF NOT EXISTS fk_course_students_to_course_root_index ON course_students(course_id_course_root)';

EXECUTE IMMEDIATE 'CREATE OR REPLACE JSON RELATIONAL DUALITY VIEW COURSE AS 
course_root @insert @update @delete
{ 
  _id : course_id
  name
  Notes: notes
  teacher: course_teacher @insert @update
  { 
    name
    teacherId: teacher_id
    ora$flex @flex
  } 
  courseId @generated (path: "$._id")
  students: course_students @insert @update @delete
  { 
    name
    studentId: student_id
    ora$flex @flex
  } 

  creditHours: credit_hours
  ora$flex @flex
}'; 

EXECUTE IMMEDIATE 'CREATE OR REPLACE TRIGGER INSERT_TRIGGER_COURSE
  BEFORE INSERT
  ON COURSE
  FOR EACH ROW
DECLARE 
  inp_jsonobj json_object_t;
BEGIN
  inp_jsonobj := json_object_t(:new.data);
  IF NOT inp_jsonobj.has(''_id'') 
  THEN 
    inp_jsonobj.put(''_id'', inp_jsonobj.get(''courseId''));
    :new.data := inp_jsonobj.to_json;
  END IF;
END;'; 
END;


PL/SQL procedure successfully completed.

SQL> 
```

生成されたスクリプトには、以下のデータベース・オブジェクトのDDLが含まれていることがわかります。
（スクリプト内での出現順）
|オブジェクトの種類|オブジェクト名|
|:-------:|:------------------|
| 表           | course_root |
| 表           | course_students |
| 表           | course_teacher |
| 参照整合性制約 | fk_course_root_to_course_teacher |
| 参照整合性制約 | fk_course_students_to_course_root |
| インデックス   | fk_course_root_to_course_teacher_index |
| インデックス   | fk_course_students_to_course_root_index |
| JSON Relational Dualityビュー | courese |
| トリガー | INSERT_TRIGGER_COURSE |

上記のPL/SQLブロックは、あくまでDDLスクリプトの生成して表示するだけなので、この時点ではデータベース・オブジェクトは作成されていません。
必要に応じて、DDLスクリプトを編集してからスクリプトを実行してデータベース・オブジェクトを作成することが可能です。

ここでは、生成されたDDLスクリプトをそのまま実行してみます。

先ほどのPL/SQLブロックのDBMS_OUTPUT.PUT_LINEの部分を修正して、生成されたDDLスクリプトがそのまま実行されるように変更します。

```
DECLARE
    schema_sql CLOB;
BEGIN
    schema_sql :=
        DBMS_JSON_DUALITY.INFER_AND_GENERATE_SCHEMA(
            JSON('{"tableNames"   : ["COURSE_JSON"],
                   "viewNames"    : ["COURSE"],
                   "minFrequency" : 0}'
            )
        );
    EXECUTE IMMEDIATE schema_sql;
END;
/
```
修正したPL/SQLブロックを実際に実行してみます。
```
SQL> DECLARE
  2  	 schema_sql CLOB;
  3  BEGIN
  4  	 schema_sql :=
  5  	     DBMS_JSON_DUALITY.infer_and_generate_schema(
  6  		 JSON('{"tableNames"   : ["COURSE_JSON"],
  7  			"viewNames"    : ["COURSE"],
  8  			"minFrequency" : 0}'
  9  		 )
 10  	     );
 11  	 EXECUTE IMMEDIATE schema_sql;
 12  END;
 13  /

PL/SQL procedure successfully completed.

SQL>
```

PL/SQLブロックが問題なく実行できました。

作成された表を確認してみます。
```
SQL> SELECT tname FROM tab
  2  WHERE tname LIKE 'COURSE%';

TNAME
--------------------------------------------------------------------------------
COURSE_JSON
COURSE_ROOT
COURSE_STUDENTS
COURSE_TEACHER

SQL>
```
course_root、course_students、course_teacherという名前の3つの表が作成されていることがわかりました。

course_root表の構造を確認してみます。
```
SQL> desc course_root
 Name					                   Null?    Type
 ----------------------------------------- -------- ----------------------------
 NAME						                        VARCHAR2(64)
 NOTES						                        VARCHAR2(64)
 COURSE_ID				                   NOT NULL VARCHAR2(64)
 CREDIT_HOURS					                    VARCHAR2(64)
 TEACHER_ID_COURSE_TEACHER			                NUMBER
 ORA$FLEX					                        JSON

SQL> 
```
course_students表の構造を確認してみます。
```
SQL> desc course_students
 Name					                   Null?    Type
 ----------------------------------------- -------- ----------------------------
 NAME						                        VARCHAR2(64)
 STUDENT_ID				                   NOT NULL NUMBER
 COURSE_ID_COURSE_ROOT				                VARCHAR2(64)
 ORA$FLEX					                        JSON

SQL>
```
course_teacher表の構造を確認してみます。
```
SQL> desc course_teacher
 Name					                   Null?    Type
 ----------------------------------------- -------- ----------------------------
 NAME						                        VARCHAR2(64)
 TEACHER_ID				                   NOT NULL NUMBER
 ORA$FLEX					                        JSON

SQL>
```

作成された参照整合性制約を確認してみます。
```
SQL> col constraint_name for a40
SQL> col table_name for a20
SQL> SELECT constraint_name, constraint_type, table_name
  2  FROM user_constraints
  3  WHERE constraint_type = 'R';

CONSTRAINT_NAME 			             C TABLE_NAME
---------------------------------------- - --------------------
FK_COURSE_ROOT_TO_COURSE_TEACHER	     R COURSE_ROOT
FK_COURSE_STUDENTS_TO_COURSE_ROOT	     R COURSE_STUDENTS

SQL>
```
fk_course_root_to_course_teacher、fk_course_students_to_course_rootという名前の2つの参照整合性制約が作成されていることがわかりました。

次に、作成されたトリガーを確認してみます。
```
SQL> SELECT trigger_name FROM user_triggers;

TRIGGER_NAME
--------------------------------------------------------------------------------
INSERT_TRIGGER_COURSE

SQL>
```
トリガーinsert_trigger_courseが作成されていることがわかりました。

最後に、作成されたJSON Relational Dualityビューを確認してみます。
```
SQL> SELECT view_name FROM user_json_duality_views;

VIEW_NAME
--------------------------------------------------------------------------------
COURSE

SQL>
```
JSON Relational Dualityビューcourseが作成されていることがわかりました。

JSON Relational Dualiyビューcourseの構造を確認してみます。

```
SQL> desc course
 Name					                   Null?    Type
 ----------------------------------------- -------- ----------------------------
 DATA						                        JSON

SQL>
```
JSON Relational Dualiyビューcourseは、dataという名前のJSONデータ型の列のみを持つことがわかります。

以上で、JSON-to-Dualityコンバーターを使用して、表に格納されているJSONドキュメント・セットからJSON Relation Dualityビュー、およびそのベースとなるデータベース・オブジェクトが簡単に作成できることが確認できました。

# JSON-to-Dualityインポーターを使用したJSON Relational DualityビューへのJSONデータのインポート

Oracle Database 23ai（23.4）では、既存のJSONドキュメント・セットからJSON-to-Dualityコンバーターを使用して作成したJSON Relational DualityビューにJSONドキュメントをインポートするためのJSON-to-Dualityコンバーターというツールも用意されています。

ここでは、JSON-to-Dualityインポーターを使用して、先ほど作成したcourse_json表に格納されているJSONドキュメントをJSON Relational Dualityビューcourseにインポートしてみます。

JSON Relational DualityビューにJSONドキュメント・セットをインポートするには、DBMS_JSON_DUALITY.IMPORTプロシージャを使用します。
パラメータtable_nameには、JSONドキュメント・セットが格納されている表の名前、パラメータview_nameにはJSONドキュメントをインポートするJSON Relational Dualityビューの名前、err_log_nameにはエラーを記録するエラーログ表の名前をそれぞれ指定します。

こちらのPL/SQLブロックを実行すると、DBMS_JSON_DUALITY.IMPORTプロシージャを実行してcourse_json表内のJSONドキュメントをJSON Relational Dualityビューcourseにインポートし、エラーが発生した場合はエラーをcourse_err_log表に記録します。

```
BEGIN
    DBMS_JSON_DUALITY.IMPORT(
        table_name   => 'COURSE_JSON',
        view_name    => 'COURSE',
        err_log_name => 'COURSE_ERR_LOG'
    );
END;
```
では、実施にインポートを実行してみます。

まず、DBMS_ERRLOG.CREATE_ERROR_LOGプロシージャを実行して、JSON Relational Dualityビューcourseに対するエラーログ表を作成します。

```
SQL> BEGIN
  2  	 DBMS_ERRLOG.CREATE_ERROR_LOG(
  3  	     dml_table_name	=> 'COURSE',
  4  	     err_log_table_name => 'COURSE_ERR_LOG',
  5  	     skip_unsupported	=> TRUE
  6  	 );
  7  END;
  8  /

PL/SQL procedure successfully completed.

SQL> 
```

次に、DBMS_JSON_DUALITY.IMPORTプロシージャを実行して、course_json表内のJSONドキュメントをJSON Relational Dualityビューcourseにインポートします。

```
SQL> BEGIN
  2  	 DBMS_JSON_DUALITY.IMPORT(
  3  	     table_name   => 'COURSE_JSON',
  4  	     view_name	  => 'COURSE',
  5  	     err_log_name => 'COURSE_ERR_LOG'
  6  	 );
  7  END;
  8  /

PL/SQL procedure successfully completed.

SQL>
```
DBMS_JSON_DUALITY.IMPORTプロシージャが問題なく実行できました。

エラーログ表course_error_logを確認してみます。
```
SQL> SELECT * FROM course__err_log;

no rows selected

SQL>
```
エラーログ表にエラーが記録されていないので、特にエラーは発生しなかったようです。

JSON Relational Dualityビューcourseのレコード数を確認してみます。
```
SQL> SELECT COUNT(*) FROM COURSE;

  COUNT(*)
----------
	     5

SQL>
```
course_json表のレコード数と同じ5件のレコードが格納されていることがわかりました。

では、JSON Relational Dualityビューcourseの実際のデータを確認してみます。
```
SQL> SELECT JSON_SERIALIZE (data RETURNING CLOB PRETTY) data FROM course;

DATA
--------------------------------------------------------------------------------
{
  "_id" : "MATH101",
  "_metadata" :
  {
    "etag" : "E5C7FBA1676755981ED5565EB51B9D0D",
    "asof" : "000025D776D205BE"
  },
  "name" : "Algebra",
  "Notes" : "Prerequisite for Advanced Algebra",
  "teacher" :
  {
    "name" : "Abdul J.",
    "teacherId" : 101
  },
  "students" :
  [
    {
      "name" : "Donald P.",
      "studentId" : 1
    }
  ],
  "creditHours" : "3",
  "courseId" : "MATH101"
}

{
  "_id" : "MATH102",
  "_metadata" :
  {
    "etag" : "4E0F7B42BE1DA62F0EA97529A7211EFF",
    "asof" : "000025D776D205BE"
  },
  "name" : "Calculus",
  "Notes" : null,
  "teacher" :
  {
    "name" : "Abdul J.",
    "teacherId" : 101
  },
  "students" :
  [
    {
      "name" : "Elena H.",
      "studentId" : 2
    },
    {
      "name" : "Ming L.",
      "studentId" : 10
    }
  ],
  "creditHours" : "4",
  "courseId" : "MATH102"
}

{
  "_id" : "CS101",
  "_metadata" :
  {
    "etag" : "A0294CD59A1EF883526B7F252649CE39",
    "asof" : "000025D776D205BE"
  },
  "name" : "Algorithms",
  "Notes" : null,
  "teacher" :
  {
    "name" : "Betty Z.",
    "teacherId" : 102
  },
  "students" :
  [
    {
      "name" : "Francis K.",
      "studentId" : 3
    },
    {
      "name" : "Georgia D.",
      "studentId" : 4
    }
  ],
  "creditHours" : "5",
  "courseId" : "CS101"
}

{
  "_id" : "CS102",
  "_metadata" :
  {
    "etag" : "C8D0EFB5870F98B7E5AD771B2A9AEB43",
    "asof" : "000025D776D205BE"
  },
  "name" : "Data Structures",
  "Notes" : null,
  "teacher" :
  {
    "name" : "Betty Z.",
    "teacherId" : 102
  },
  "students" :
  [
    {
      "name" : "Hye E.",
      "studentId" : 5
    },
    {
      "name" : "Jatin S.",
      "studentId" : 7
    },
    {
      "name" : "Katie H.",
      "studentId" : 8
    }
  ],
  "creditHours" : "3",
  "courseId" : "CS102"
}

{
  "_id" : "MATH103",
  "_metadata" :
  {
    "etag" : "588780259587A1A6E2B25413286896C6",
    "asof" : "000025D776D205BE"
  },
  "name" : "Advanced Algebra",
  "Notes" : null,
  "teacher" :
  {
    "name" : "Colin J.",
    "teacherId" : 103
  },
  "students" :
  [
    {
      "name" : "Ileana D.",
      "studentId" : 6
    },
    {
      "name" : "Luis F.",
      "studentId" : 9
    }
  ],
  "creditHours" : "3",
  "courseId" : "MATH103"
}


SQL>
```
JSON Relational Dualityビューcourseの内容は、course_json表に格納されているJSONデータに、メタデータ（_metadata）が追加された形になっていることがわかりました。
_metadataには、etag（JSONドキュメントを構成するリレーショナル表の列値から算出されるハッシュ値、JSON Relational Dualityビューにおけるロックフリーの同時実行性制御で使用される）とasof（データベースのSCN値）が含まれます。

JSON Relational Dualityビューcourseのベースとなっている各リレーショナル表の内容を確認してみます。

couse_root表の件数を確認してみます。
```
SQL> SELECT COUNT(*) FROM course_root;

  COUNT(*)
----------
	     5

SQL>
```
couse_root表の内容を確認してみます。
```
SQL> col name for a20
SQL> col notes for a35
SQL> col course_id for a10
SQL> col credit_hours for a11
SQL> SELECT * FROM course_root;

NAME		         NOTES				                 COURSE_ID  CREDIT_HOUR TEACHER_ID_COURSE_TEACHER ORA$FLEX
-------------------- ----------------------------------- ---------- ----------- ------------------------- --------------------------------------------------------------------------------
Algebra 	         Prerequisite for Advanced Algebra	 MATH101    3				                  101
Calculus						                         MATH102    4				                  101
Algorithms						                         CS101	    5				                  102
Data Structures 					                     CS102	    3				                  102
Advanced Algebra					                     MATH103    3				                  103

SQL> 
```
course_course表には、5件のコースの情報が格納されていることがわかりました。

course_teacher表の件数を確認してみます。
```
SQL> SELECT COUNT(*) FROM course_teacher;

  COUNT(*)
----------
	     3

SQL>
```
course_teacher表の内容を確認してみます。
```
SQL> col name for a10
SQL> set linesize 200
SQL> SELECT * FROM course_teacher;

NAME	   TEACHER_ID ORA$FLEX
---------- ---------- --------------------------------------------------------------------------------
Abdul J.	      101
Betty Z.	      102
Colin J.	      103

SQL>
```
course_teacher表には、3件の教師の情報が格納されていることがわかりました。

course_students表の件数を確認してみます。
```
SQL> SELECT COUNT(*) FROM course_students;

  COUNT(*)
----------
	    10

SQL>
```
course_students表の内容を確認してみます。
```
SQL> col name for a20
SQL> col course_id_course_root for a21
SQL> set linesize 200
SQL> SELECT * FROM course_students;

NAME		         STUDENT_ID COURSE_ID_COURSE_ROOT ORA$FLEX
-------------------- ---------- --------------------- --------------------------------------------------------------------------------
Donald P.		              1 MATH101
Elena H.		              2 MATH102
Ming L. 		             10 MATH102
Francis K.		              3 CS101
Georgia D.		              4 CS101
Hye E.			              5 CS102
Jatin S.		              7 CS102
Katie H.		              8 CS102
Ileana D.		              6 MATH103
Luis F. 		              9 MATH103

10 rows selected.

```
course_students表には、10件の学生の情報が格納されていることがわかりました。

以上で、JSON-to-Dualityインポーターを使用して、表に格納されているJSONドキュメント・セットをJSON Relation Dualityビュー（実際にはDualityビューのベースとなっているリレーショナル表）に簡単にロードできることが確認できました。

# まとめ

JSONデータ型を使用したインライン外部表、JSON-to-Dualityコンバーター、JSON-to-DualityインポーターといったOracle Database 23aiの新機能を活用して、Object Storage上にあるJSONデータをAutonomous Database 23ai内のJSON Relational Dualityビューに簡単に移行できることが確認できました。

# 参考情報
・[Loading External JSON Data](https://docs.oracle.com/en/database/oracle/oracle-database/23/adjsn/loading-external-json-data.html#ADJSN-GUID-52EFC452-5E65-4148-8070-1FA588A6E697)
・[ORACLE_BIGDATA Access Parameters](https://docs.oracle.com/en/database/oracle/oracle-database/19/sutil/oracle_bigdata_access_driver.html#GUID-38B1FCCF-C459-47B5-9A57-FAE4E53F3DF5)
・[JSONリレーショナル二面性ビューの概要](https://docs.oracle.com/cd/F82042_01/jsnvu/overview-json-relational-duality-views.html)
・[JSON-To-Duality Converter](https://docs.oracle.com/en/database/oracle/oracle-database/23/jsnvu/json-duality.html#GUID-54C2C235-DC92-4CB5-8287-93DF89F794E2)
・[JSON-To-Duality Importer](https://docs.oracle.com/en/database/oracle/oracle-database/23/jsnvu/json-duality.html#GUID-EA839259-6134-449D-9873-A154BA432AAF)