21.12 コンバータの使用(useFlexFields=false)

useFlexFields = falseを指定したJSON-to-Dualityコンバータの使用を示します。それ以外は、構成はデフォルトです(minFieldFrequencyおよびminTypeFrequencyを除く)。ドキュメント・セットをサポートするために必要なデータベース・オブジェクトが推測され、それらを構築するためのSQL DDLコードが生成されます。

false値のuseFlexFieldsDBMS_JSON_DUALITY.infer_schemaに渡します。それ以外は、このコールは「コンバータの使用(デフォルトの動作)」の例「INFER_SCHEMAおよびGENERATE_SCHEMA (useFlexFields = true)」と同じです。また、infer_schemaによって返されるJSONスキーマは、useFlexFieldstrueの場合でもfalseの場合でも同じです。

DBMS_JSON_DUALITY.generate_schemaのコールも同じです。生成されるDDLコードの違いは、次の点のみです:

  • useFlexFieldsfalseの場合、二面性ビューの基礎となる表にはフレックス列がありません。

  • useFlexFieldsfalseの場合、二面性ビューはフレックス列を参照しません。

例21-31 GENERATE_SCHEMAからのDDLコード(useFlexFields = false)

ファンクションDBMS_JSON_DUALITY.generate_schemaは、useFlexFields = falseでファンクションinfer_schemaによって生成されたJSONスキーマが渡された場合、ここに示す生成されたDDLコードを生成します。

このDDLコードと、useFlexFields = trueで生成されたコードとの違いは、ここでは基礎となる表にフレックス列がなく、二面性ビューのフレックス列への参照がないことのみです。

BEGIN
EXECUTE IMMEDIATE 'CREATE TABLE student_dormitory(
   dorm_id  number  GENERATED BY DEFAULT ON NULL AS IDENTITY,
   dorm_name  varchar2(64),
   PRIMARY KEY(dorm_id)
)';

EXECUTE IMMEDIATE 'CREATE TABLE map_course_root_to_student_root(
   map_course_id  varchar2(64)  DEFAULT ON NULL SYS_GUID(),
   map_student_id  number  GENERATED BY DEFAULT ON NULL AS IDENTITY,
   PRIMARY KEY(map_course_id,map_student_id)
)';

EXECUTE IMMEDIATE 'CREATE TABLE student_root(
   age  number,
   name  varchar2(64),
   dorm_id  number,
   advisor_id  number,
   student_id  number  GENERATED BY DEFAULT ON NULL AS IDENTITY,
   PRIMARY KEY(student_id)
)';

EXECUTE IMMEDIATE 'CREATE TABLE teacher_root(
   "_id"  number  GENERATED BY DEFAULT ON NULL AS IDENTITY,
   name  varchar2(64),
   salary  number,
   department  varchar2(64),
   phone_number  json VALIDATE ''{"oneOf" : [{ "type" :"string"},
                                             { "type" :"array"}]}'',
   PRIMARY KEY("_id")
)';

EXECUTE IMMEDIATE 'CREATE TABLE course_root(
   name  varchar2(64),
   avg_grade  json VALIDATE ''{"oneOf" : [{ "type" :"number"},
                                          { "type" :"string"}]}'',
   course_id  varchar2(64)  DEFAULT ON NULL SYS_GUID(),
   class_type  varchar2(64),
   credit_hours  json VALIDATE ''{"oneOf" : [{ "type" :"number"},
                                             { "type" :"string"}]}'',
   "_id_teacher_root"  number,
   PRIMARY KEY(course_id)
)';

EXECUTE IMMEDIATE 'ALTER TABLE map_course_root_to_student_root
ADD CONSTRAINT fk_map_course_root_to_student_root_to_course_root FOREIGN KEY (map_course_id) REFERENCES course_root(course_id) DEFERRABLE';
EXECUTE IMMEDIATE 'ALTER TABLE map_course_root_to_student_root
ADD CONSTRAINT fk_map_course_root_to_student_root_to_student_root FOREIGN KEY (map_student_id) REFERENCES student_root(student_id) DEFERRABLE';
EXECUTE IMMEDIATE 'ALTER TABLE student_root
ADD CONSTRAINT fk_student_root_to_student_dormitory FOREIGN KEY (dorm_id) REFERENCES student_dormitory(dorm_id) DEFERRABLE';
EXECUTE IMMEDIATE 'ALTER TABLE student_root
ADD CONSTRAINT fk_student_root_to_teacher_root FOREIGN KEY (advisor_id) REFERENCES teacher_root("_id") DEFERRABLE';
EXECUTE IMMEDIATE 'ALTER TABLE course_root
ADD CONSTRAINT fk_course_root_to_teacher_root FOREIGN KEY ("_id_teacher_root") REFERENCES teacher_root("_id") DEFERRABLE';
EXECUTE IMMEDIATE 'CREATE INDEX IF NOT EXISTS fk_map_course_root_to_student_root_to_course_root_index ON map_course_root_to_student_root(map_course_id)';
EXECUTE IMMEDIATE 'CREATE INDEX IF NOT EXISTS fk_map_course_root_to_student_root_to_student_root_index ON map_course_root_to_student_root(map_student_id)';
EXECUTE IMMEDIATE 'CREATE INDEX IF NOT EXISTS fk_student_root_to_student_dormitory_index ON student_root(dorm_id)';
EXECUTE IMMEDIATE 'CREATE INDEX IF NOT EXISTS fk_student_root_to_teacher_root_index ON student_root(advisor_id)';
EXECUTE IMMEDIATE 'CREATE INDEX IF NOT EXISTS fk_course_root_to_teacher_root_index ON course_root("_id_teacher_root")';

EXECUTE IMMEDIATE 'CREATE OR REPLACE JSON RELATIONAL DUALITY VIEW STUDENT AS
student_root @insert @update @delete
{
  _id : student_id
  age
  name
  courses: map_course_root_to_student_root @insert @update @delete @array
  {
    ora$mapCourseId: map_course_id
    ora$mapStudentId: map_student_id
    course_root @unnest @insert @update @object
    {
      name
      avgGrade: avg_grade
      courseNumber: course_id
    }
  }
  advisorId:advisor_id
  dormitory: student_dormitory @insert @update @object
  {
    dormId: dorm_id
    dormName: dorm_name
  }
  studentId @generated (path: "$._id")
}';

EXECUTE IMMEDIATE 'CREATE OR REPLACE JSON RELATIONAL DUALITY VIEW TEACHER AS
teacher_root @insert @update @delete
{
  "_id"
  name
  salary
  department
  phoneNumber: phone_number
  coursesTaught: course_root @insert @update @delete @array
  {
    name
    courseId: course_id
    classType: class_type
  }
  studentsAdvised: student_root @insert @update @delete @array
  {
    name
    dormId:dorm_id
    studentId: student_id
  }
}';

EXECUTE IMMEDIATE 'CREATE OR REPLACE JSON RELATIONAL DUALITY VIEW COURSE AS
course_root @insert @update @delete
{
  _id : course_id
  name
  teacher: teacher_root @insert @update @object
  {
    name
    teacherId: "_id"
  }
  courseId @generated (path: "$._id")
  students: map_course_root_to_student_root @insert @update @delete @array
  {
    ora$mapCourseId: map_course_id
    ora$mapStudentId: map_student_id
    student_root @unnest @insert @update @object
    {
      name
      studentId: student_id
    }
  }
  creditHours: credit_hours
}';

EXECUTE IMMEDIATE 'CREATE OR REPLACE TRIGGER INSERT_TRIGGER_STUDENT
  BEFORE INSERT
  ON STUDENT
  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(''studentId''));
    :new.data := inp_jsonobj.to_json;
  END IF;
END;';

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;

次の例「VALIDATE_SCHEMA_REPORT (useFlexFields = false)」は、まれなフィールドNotesがコースのドキュメント・セットの外れ値であることを示しています。

コンバータによって作成されたフレックス列がない場合、コンバータによってマップされていないフィールド(単純なSQLスカラー列に格納できないフィールドなど)のインポート時にエラーがログに記録されます。useFlexFieldstrue (デフォルト値)のとき、マップされていないフィールドNotesは、フレックス・フィールドに格納されることで、コースのドキュメントに保持されます。ただし、useFlexFieldsfalseの場合、フィールドNotesはインポート時にエラーとしてログに記録されます。

DDLコードを生成してから実行すると、二面性ビューとその基礎となる表が作成されます。

DDLコードの実行後、入力表および二面性ビューの各種類(学生、教師、コース)に対してコンバータ・ファンクションDBMS_JSON_DUALITY.validate_schema_reportを実行して、変換を検証します。

例21-32 VALIDATE_SCHEMA_REPORT (useFlexFields = false)

このコードは、「コンバータの使用(デフォルトの動作)」の例「VALIDATE_SCHEMA_REPORT (デフォルト・ケース(useFlexFields = true))」と同じです。

SELECT * FROM DBMS_JSON_DUALITY.validate_schema_report(
                                  table_name => 'STUDENT_TAB',
                                  view_name  => 'STUDENT');
SELECT * FROM DBMS_JSON_DUALITY.validate_schema_report(
                                  table_name => 'TEACHER_TAB',
                                  view_name  => 'TEACHER');
SELECT * FROM DBMS_JSON_DUALITY.validate_schema_report(
                                  table_name => 'COURSE_TAB',
                                  view_name  => 'COURSE');

学生の表およびビューに関してレポートされるエラーは、「コンバータの使用(デフォルトの動作)」の例「VALIDATE_SCHEMA_REPORT (デフォルト・ケース(useFlexFields = true))」と同じです。(つまり、フィールドageが文字列値"Nineteen")。

教師の表およびビューに関するエラーはレポートされません(useFlexFields = trueの場合と同様)。

ただし、コースの表およびビューに関するエラーが(useFlexFields = trueの場合と同様に)レポートされないかわりに、useFlexFields = falseの場合、フィールド出現の外れ値フィールドNotesに関するエラーがレポートされます。これは、デフォルトの場合、そのフィールドがフレックス列に格納されるためです。

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

ERRORS
------
[{"schemaPath":"$","instancePath":"$","code":"JZN-00501","error":"JSON schema va
lidation failed"},{"schemaPath":"$.additionalProperties","instancePath":"$","cod
e":"JZN-00518","error":"invalid additional properties:  'Notes'"},{"schemaPath":
"$.additionalProperties","instancePath":"$.Notes","code":"JZN-00502","error":"JS
ON boolean schema was false"}]

useFlexFields = trueの場合と同様に、インポートの前に、Luis Jの学生の入力ドキュメントのageフィールドを変更して、文字列値"Nineteen"ではなく数値19を指定できます。また、データからフィールドNotesを削除することも、含めることができるようにminTypeFrequencyの値を緩和(低く)することもできます。