Skip to content

Commit 762ba12

Browse files
authored
Create JSON-to-Duality-View-Migrator-Tutorial.sql (#439)
1 parent 2d92243 commit 762ba12

File tree

1 file changed

+237
-0
lines changed

1 file changed

+237
-0
lines changed
Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
/*
2+
** Copyright (c) 2025 Oracle and/or its affiliates
3+
** The Universal Permissive License (UPL), Version 1.0
4+
**
5+
** Subject to the condition set forth below, permission is hereby granted to any
6+
** person obtaining a copy of this software, associated documentation and/or data
7+
** (collectively the "Software"), free of charge and under any and all copyright
8+
** rights in the Software, and any and all patent rights owned or freely
9+
** licensable by each licensor hereunder covering either (i) the unmodified
10+
** Software as contributed to or provided by such licensor, or (ii) the Larger
11+
** Works (as defined below), to deal in both
12+
**
13+
** (a) the Software, and
14+
** (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
15+
** one is included with the Software (each a "Larger Work" to which the Software
16+
** is contributed by such licensors),
17+
**
18+
** without restriction, including without limitation the rights to copy, create
19+
** derivative works of, display, perform, and distribute the Software and make,
20+
** use, sell, offer for sale, import, export, have made, and have sold the
21+
** Software and the Larger Work(s), and to sublicense the foregoing rights on
22+
** either these or other terms.
23+
**
24+
** This license is subject to the following condition:
25+
** The above copyright notice and either this complete permission notice or at
26+
** a minimum a reference to the UPL must be included in all copies or
27+
** substantial portions of the Software.
28+
**
29+
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30+
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31+
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
32+
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
33+
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
34+
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
35+
** SOFTWARE.
36+
*/
37+
38+
-- TITLE
39+
-- Working with the JSON-To-Duality Migrator using SQL
40+
--
41+
-- DESCRIPTION
42+
-- This tutorial script walks you through an example of working with
43+
-- the JSON-To-Duality Migrator using Conference scheduling data
44+
-- through SQL.
45+
--
46+
-- PREREQUISITES
47+
-- Ensure that you have Oracle Database 23ai installed and running on a
48+
-- port. Ensure that the compatible parameter is set to 23.0.0.0.
49+
--
50+
-- USAGE
51+
-- Connect to the database as a regular (non-SYS) user and run this
52+
-- script. The user must have the DB_DEVELOPER_ROLE and privileges
53+
-- on the default tablespace.
54+
-- A demo user can be created using this statement:
55+
-- CREATE USER <user> IDENTIFIED BY <password> QUOTA UNLIMITED ON <default tablespace>;
56+
-- GRANT DB_DEVELOPER_ROLE TO <user>;
57+
--
58+
-- NOTES
59+
-- Please go through the duality view documentation
60+
-- (https://docs.oracle.com/en/database/oracle/oracle-database/23/jsnvu/index.html)
61+
-- before this to learn more about duality views and their advantages.
62+
63+
-- We start by populating the initial JSON data. We have three collections,
64+
-- Speaker, Attendee, and Sessions.
65+
66+
CREATE TABLE IF NOT EXISTS SPEAKER (data JSON);
67+
CREATE TABLE IF NOT EXISTS ATTENDEE (data JSON);
68+
CREATE TABLE IF NOT EXISTS SESSIONS (data JSON);
69+
70+
INSERT INTO SPEAKER VALUES
71+
('{"_id" : 101,
72+
"name" : "Abdul J.",
73+
"phoneNumber" : "222-555-011",
74+
"yearsAtOracle" : 25,
75+
"department" : "Product Management",
76+
"sessionsTaught" : [ {"sessionName" : "JSON and SQL", "type" : "Online", "credits" : 3},
77+
{"sessionName" : "PL/SQL or Javascript", "type" : "In-person", "credits" : 5} ]}'
78+
),
79+
('{"_id" : 102,
80+
"name" : "Betty Z.",
81+
"yearsAtOracle" : 30,
82+
"department" : "Autonomous Databases",
83+
"sessionsTaught" : [ {"sessionName" : "Oracle ADB on iPhone", "type" : "Online", "credits" : 3},
84+
{"sessionName" : "MongoDB API Internals", "type" : "In-person", "credits" : 4} ]}'
85+
),
86+
('{"_id" : 103,
87+
"name" : "Colin J.",
88+
"phoneNumber" : "222-555-023",
89+
"yearsAtOracle" : 27,
90+
"department" : "In-Memory and Data",
91+
"sessionsTaught" : [ {"sessionName" : "JSON Duality Views", "type" : "Online", "credits" : 3} ]}'
92+
);
93+
94+
INSERT INTO ATTENDEE VALUES
95+
('{"_id" : 1,
96+
"name" : "Donald P.",
97+
"age" : 20,
98+
"phoneNumber" : "222-111-021",
99+
"grade" : "A",
100+
"sessions" : [ {"sessionName" : "JSON and SQL", "credits" : 3},
101+
{"sessionName" : "PL/SQL or Javascript", "credits" : 5},
102+
{"sessionName" : "MongoDB API Internals", "credits" : 4},
103+
{"sessionName" : "JSON Duality Views", "credits" : 3},
104+
{"sessionName" : "Oracle ADB on iPhone", "credits" : 3} ]}'
105+
),
106+
('{"_id" : 2,
107+
"name" : "Elena H.",
108+
"age" : 22,
109+
"phoneNumber" : "222-112-022",
110+
"grade" : "B",
111+
"sessions" : [ {"sessionName" : "JSON Duality Views", "credits" : 3},
112+
{"sessionName" : "MongoDB API Internals", "credits" : 4},
113+
{"sessionName" : "JSON and SQL", "credits" : 3} ]}'
114+
),
115+
('{"_id" : 3,
116+
"name" : "Francis K.",
117+
"age" : 23,
118+
"phoneNumber" : "222-112-022",
119+
"grade" : "C",
120+
"sessions" : [ {"sessionName" : "MongoDB API Internals", "credits" : 4},
121+
{"sessionName" : "JSON and SQL", "credits" : 3} ]}'
122+
),
123+
('{"_id" : 4,
124+
"name" : "Jatin S.",
125+
"age" : 24,
126+
"phoneNumber" : "222-113-023",
127+
"grade" : "D",
128+
"sessions" : [ {"sessionName" : "JSON Duality Views", "credits" : 3} ]}'
129+
);
130+
131+
INSERT INTO SESSIONS VALUES
132+
('{"_id" : "10",
133+
"sessionName" : "JSON and SQL",
134+
"creditHours" : 3,
135+
"attendeesEnrolled" : [ {"_id" : 1, "name" : "Donald P."}, {"_id" : 3, "name" : "Francis K."} ]}'
136+
),
137+
('{"_id" : "20",
138+
"sessionName" : "PL/SQL or Javascript",
139+
"creditHours" : 5,
140+
"attendeesEnrolled" : [ {"_id" : 1, "name" : "Donald P."} ]}'
141+
),
142+
('{"_id" : "30",
143+
"sessionName" : "MongoDB API Internals",
144+
"creditHours" : 4,
145+
"attendeesEnrolled" : [ {"_id" : 1, "name" : "Donald P."}, {"_id" : 2, "name" : "Elena H."}, {"_id" : 3, "name" : "Francis K."} ]}'
146+
),
147+
('{"_id" : "40",
148+
"sessionName" : "Oracle ADB on iPhone",
149+
"creditHours" : 3,
150+
"attendeesEnrolled" : [{"_id" : 1, "name" : "Donald P."}]}'
151+
),
152+
('{"_id" : "50",
153+
"sessionName" : "JSON Duality Views",
154+
"creditHours" : 3,
155+
"attendeesEnrolled" : [ {"_id" : 1, "name" : "Donald P."}, {"_id" : 2, "name" : "Elena H."}, {"_id" : 4, "name" : "Jatin S."} ]}'
156+
);
157+
158+
COMMIT;
159+
160+
-- Next, we run the JSON-to-Duality Migrator by invoking the
161+
-- infer_and_generate_schema procedure.
162+
163+
SET SERVEROUTPUT ON
164+
DECLARE
165+
schema_sql CLOB;
166+
BEGIN
167+
-- Infer relational schema
168+
schema_sql :=
169+
DBMS_JSON_DUALITY.INFER_AND_GENERATE_SCHEMA(
170+
JSON('{"tableNames" : [ "ATTENDEE", "SPEAKER", "SESSIONS" ],
171+
"useFlexFields" : true,
172+
"updatability" : true,
173+
"minFieldFrequency" : 0,
174+
"minTypeFrequency" : 0}'
175+
)
176+
);
177+
178+
-- Print DDL script
179+
DBMS_OUTPUT.PUT_LINE('DDL Script: ');
180+
DBMS_OUTPUT.PUT_LINE(schema_sql);
181+
182+
-- Create relational schema
183+
EXECUTE IMMEDIATE schema_sql;
184+
END;
185+
/
186+
187+
-- Let’s check the objects created by the tool.
188+
-- Note that the relational schema is completely normalized - one table is
189+
-- created per logical entity, one for speaker (speaker_root), one for attendee
190+
-- (attendee_root), and one for sessions (sessions_root). The many-to-many
191+
-- relationship between attendees and sessions is automatically identified and
192+
-- a mapping table is created to map attendees to sessions.
193+
194+
SELECT object_name, object_type
195+
FROM user_objects
196+
WHERE created > sysdate-1/24
197+
ORDER BY object_type DESC;
198+
199+
-- Now, let’s validate the schema, which shows no errors (no rows selected) for
200+
-- each duality view, which means that there are no validation failures.
201+
202+
SELECT * FROM DBMS_JSON_DUALITY.VALIDATE_SCHEMA_REPORT(table_name => 'SESSIONS', view_name => 'SESSIONS_DUALITY');
203+
SELECT * FROM DBMS_JSON_DUALITY.VALIDATE_SCHEMA_REPORT(table_name => 'ATTENDEE', view_name => 'ATTENDEE_DUALITY');
204+
SELECT * FROM DBMS_JSON_DUALITY.VALIDATE_SCHEMA_REPORT(table_name => 'SPEAKER', view_name => 'SPEAKER_DUALITY');
205+
206+
-- Let’s create error logs to log errors for documents that do not get imported
207+
-- successfully.
208+
209+
BEGIN
210+
DBMS_ERRLOG.CREATE_ERROR_LOG(dml_table_name => 'SESSIONS', err_log_table_name => 'SESSIONS_ERR_LOG', skip_unsupported => TRUE);
211+
DBMS_ERRLOG.CREATE_ERROR_LOG(dml_table_name => 'ATTENDEE', err_log_table_name => 'ATTENDEE_ERR_LOG', skip_unsupported => TRUE);
212+
DBMS_ERRLOG.CREATE_ERROR_LOG(dml_table_name => 'SPEAKER', err_log_table_name => 'SPEAKER_ERR_LOG', skip_unsupported => TRUE);
213+
END;
214+
/
215+
216+
-- Let’s import the data into the duality views.
217+
218+
BEGIN
219+
DBMS_JSON_DUALITY.IMPORT_ALL(
220+
JSON('{"tableNames" : [ "SESSIONS","ATTENDEE","SPEAKER" ],
221+
"viewNames" : [ "SESSIONS_DUALITY","ATTENDEE_DUALITY","SPEAKER_DUALITY" ],
222+
"errorLog" : [ "SESSIONS_ERR_LOG","ATTENDEE_ERR_LOG","SPEAKER_ERR_LOG" ]}'
223+
)
224+
);
225+
END;
226+
/
227+
228+
-- The error logs are empty, showing that there are no import errors — there
229+
-- are no documents that did not get imported.
230+
231+
SELECT ora_err_number$, ora_err_mesg$, ora_err_tag$ FROM SESSIONS_ERR_LOG;
232+
SELECT ora_err_number$, ora_err_mesg$, ora_err_tag$ FROM ATTENDEE_ERR_LOG;
233+
SELECT ora_err_number$, ora_err_mesg$, ora_err_tag$ FROM SPEAKER_ERR_LOG;
234+
235+
-- Super simple, isn’t it?
236+
-- Download the Oracle Database 23ai Free version from oracle.com/database/free
237+
-- and try it today!

0 commit comments

Comments
 (0)