Skip to Main Content

Breadcrumb

Question and Answer

Connor McDonald

Thanks for the question, Sagar.

Asked: August 27, 2017 - 10:56 am UTC

Last updated: November 28, 2018 - 12:49 am UTC

Version: 12.2.0.0.3

Viewed 1000+ times

You Asked

Hi

I have a JSON object containing complex MVA, and would like to have relational access to my JSON object using JSON_TABLE + View.

The way I am doing it right now, gives me 4 rows when I query the View, and I would like the SQL to return two rows i.e. ignoring the NULL columns in the 4 rows where my NESTED PATH objects come into picture.

I would like to store data for columns "USER_EXP_IDX, USER_EXP_CMPNY, USER_EXP_ROLE, USER_EXP_DESC" in the tow rows only, rather than have separate two rows.

LiveSQL link shared with post.

Any guidance is appreciated as to how I can achieve the same.

Thanks in advance.

with LiveSQL Test Case:

and Connor said...

Thanks for the excellent test case.

This isn't particularly an issue with JSON as such, more that you are creating two "branches" of child records (the phone and the experience)

SQL> CREATE TABLE test_user (
  2    id      RAW(16) NOT NULL,
  3    loading_date    TIMESTAMP(6) WITH TIME ZONE,
  4    user_json   CLOB CHECK (user_json IS JSON)
  5  );

Table created.

SQL>
SQL>
SQL> INSERT INTO test_user
  2    VALUES (
  3      SYS_GUID(),
  4      SYSTIMESTAMP,
  5      '{
  6       "user_key":1,
  7       "user_name":"Arthur Stygall",
  8       "user_type":"End-user",
  9       "user_status":"Active",
 10       "user_emp_type":"Full-Time",
 11       "user_login":"arthurstygall",
 12       "user_password":"test1243",
 13       "user_address":{
 14        "street":"200 Sporting Green",
 15        "city":"South San Francisco",
 16        "state":"CA",
 17        "zipCode":99236,
 18        "country":"United States of America"
 19       },
 20       "user_phone":[
 21       {
 22          "type":"Office",
 23          "number":"823-555-9969"
 24       },
 25       {
 26          "type":"Mobile",
 27          "number":"976-555-1234"
 28       }
 29       ],
 30       "user_email":"arthur.stygall@achme.com",
 31       "user_create_date":"19-JAN-10",
 32       "user_manager_name":"Ron Howard",
 33       "user_experience":[
 34            {
 35         "idx":1,
 36         "info":{
 37              "Company":"Microsoft",
 38              "Role":"Architect",
 39              "Description":"Technical architect for Microsoft Azure Cloud"
 40          }
 41            },
 42            {
 43         "idx":2,
 44         "info":{
 45              "Company":"Adobe",
 46              "Role":"PMTS",
 47              "Description":"Lead developer for Adobe Flash technology"
 48          }
 49            }
 50    ]
 51  }'
 52  );

1 row created.

SQL>
SQL>
SQL> CREATE OR REPLACE VIEW view_test_user
  2  AS
  3  SELECT d.*
  4  FROM test_user p,
  5         JSON_TABLE(
  6           p.user_json,
  7           '$'
  8           columns (
  9      USER_KEY      VARCHAR2(30 CHAR)    path '$.user_key',
 10      USER_NAME     VARCHAR2(30 CHAR)    path '$.user_name',
 11      USER_TYPE     VARCHAR2(128 CHAR)   path '$.user_type',
 12      USER_STATUS     VARCHAR2(10 CHAR)    path '$.user_status',
 13      USER_EMP_TYPE     VARCHAR2(16)         path '$.user_emp_type',
 14      USER_LOGIN      VARCHAR2(16)         path '$.user_login',
 15      USER_PASSWORD     VARCHAR2(16)         path '$.user_password',
 16      USER_DTLS_STREET    VARCHAR2(32 CHAR)    path '$.user_address.street',
 17      USER_DTLS_CITY      VARCHAR2(32 CHAR)    path '$.user_address.city',
 18      USER_DTLS_COUNTY    VARCHAR2(32 CHAR)    path '$.user_address.county',
 19      USER_DTLS_POSTCODE    VARCHAR2(10 CHAR)    path '$.user_address.postcode',
 20      USER_DTLS_STATE     VARCHAR2(2 CHAR)     path '$.user_address.state',
 21      USER_DTLS_PROVINCE    VARCHAR2(2 CHAR)     path '$.user_address.province',
 22      USER_DTLS_ZIP     VARCHAR2(8 CHAR)     path '$.user_address.zipCode',
 23      USER_DTLS_COUNTRY   VARCHAR2(32 CHAR)    path '$.user_address.country',
 24      NESTED PATH '$.user_phone[*]'
 25      columns (
 26        USER_PHONE_TYPE   VARCHAR2(24 CHAR)    path '$.type',
 27        USER_PHONE_NUMBER VARCHAR2(24 CHAR)    path '$.number'
 28        ),
 29      USER_EMAIL      VARCHAR2(1024 CHAR)  path '$.user_email',
 30      USER_CREATE_DATE    VARCHAR2(32 CHAR)    path '$.user_create_date',
 31      USER_MANAGER_NAME   VARCHAR2(32 CHAR)    path '$.user_manager_name',
 32      NESTED PATH '$.user_experience[*]'
 33      columns (
 34        USER_EXP_IDX    NUMBER(38)       path '$.idx',
 35        USER_EXP_CMPNY  VARCHAR2(256 CHAR)   path '$.info.Company',
 36        USER_EXP_ROLE VARCHAR2(14 CHAR)    path '$.info.Role',
 37        USER_EXP_DESC VARCHAR2(1024 CHAR)  path '$.info.Description'
 38        )
 39      )
 40    ) d;

View created.

SQL> col USER_PHONE_TYPE format a20 trunc
SQL> col USER_PHONE_NUMBER format a20 trunc
SQL> col USER_EXP_CMPNY format a20 trunc
SQL> col USER_EXP_ROLE format a20 trunc
SQL> col USER_EXP_DESC format a20 trunc
SQL>
SQL>
SQL> select USER_PHONE_TYPE, USER_PHONE_NUMBER, USER_EXP_IDX, USER_EXP_CMPNY, USER_EXP_ROLE, USER_EXP_DESC
  2  from view_test_user;

USER_PHONE_TYPE      USER_PHONE_NUMBER    USER_EXP_IDX USER_EXP_CMPNY       USER_EXP_ROLE        USER_EXP_DESC
-------------------- -------------------- ------------ -------------------- -------------------- --------------------
Office               823-555-9969
Mobile               976-555-1234
                                                     1 Microsoft            Architect            Technical architect
                                                     2 Adobe                PMTS                 Lead developer for A

4 rows selected.

SQL>


It's like if you had a table called DEPT, and then wanted (say) all the child EMPLOYEE records per department *and* all the (say) child PHOTOCOPIERS that are in the department. You have *two* one-to-many relationships you are trying to represent. So you've got some options:

1) Filter after the fact

SQL> select USER_EXP_IDX, USER_EXP_CMPNY, USER_EXP_ROLE, USER_EXP_DESC
  2  from view_test_user
  3  where USER_EXP_IDX is not null;

USER_EXP_IDX USER_EXP_CMPNY       USER_EXP_ROLE        USER_EXP_DESC
------------ -------------------- -------------------- --------------------
           1 Microsoft            Architect            Technical architect
           2 Adobe                PMTS                 Lead developer for A



1) Remove one of the nested tables (ie, have one view for phones, one view for experience)

SQL> CREATE OR REPLACE VIEW view_test_user
  2  AS
  3  SELECT d.*
  4  FROM test_user p,
  5         JSON_TABLE(
  6           p.user_json,
  7           '$'
  8           columns (
  9      USER_KEY      VARCHAR2(30 CHAR)    path '$.user_key',
 10      USER_NAME     VARCHAR2(30 CHAR)    path '$.user_name',
 11      USER_TYPE     VARCHAR2(128 CHAR)   path '$.user_type',
 12      USER_STATUS     VARCHAR2(10 CHAR)    path '$.user_status',
 13      USER_EMP_TYPE     VARCHAR2(16)         path '$.user_emp_type',
 14      USER_LOGIN      VARCHAR2(16)         path '$.user_login',
 15      USER_PASSWORD     VARCHAR2(16)         path '$.user_password',
 16      USER_DTLS_STREET    VARCHAR2(32 CHAR)    path '$.user_address.street',
 17      USER_DTLS_CITY      VARCHAR2(32 CHAR)    path '$.user_address.city',
 18      USER_DTLS_COUNTY    VARCHAR2(32 CHAR)    path '$.user_address.county',
 19      USER_DTLS_POSTCODE    VARCHAR2(10 CHAR)    path '$.user_address.postcode',
 20      USER_DTLS_STATE     VARCHAR2(2 CHAR)     path '$.user_address.state',
 21      USER_DTLS_PROVINCE    VARCHAR2(2 CHAR)     path '$.user_address.province',
 22      USER_DTLS_ZIP     VARCHAR2(8 CHAR)     path '$.user_address.zipCode',
 23      USER_DTLS_COUNTRY   VARCHAR2(32 CHAR)    path '$.user_address.country',
 24      USER_EMAIL      VARCHAR2(1024 CHAR)  path '$.user_email',
 25      USER_CREATE_DATE    VARCHAR2(32 CHAR)    path '$.user_create_date',
 26      USER_MANAGER_NAME   VARCHAR2(32 CHAR)    path '$.user_manager_name',
 27      NESTED PATH '$.user_experience[*]'
 28      columns (
 29        USER_EXP_IDX    NUMBER(38)       path '$.idx',
 30        USER_EXP_CMPNY  VARCHAR2(256 CHAR)   path '$.info.Company',
 31        USER_EXP_ROLE VARCHAR2(14 CHAR)    path '$.info.Role',
 32        USER_EXP_DESC VARCHAR2(1024 CHAR)  path '$.info.Description'
 33        )
 34      )
 35    ) d;

View created.

SQL>
SQL>
SQL> select USER_EXP_IDX, USER_EXP_CMPNY, USER_EXP_ROLE, USER_EXP_DESC
  2  from view_test_user;

USER_EXP_IDX USER_EXP_CMPNY       USER_EXP_ROLE        USER_EXP_DESC
------------ -------------------- -------------------- --------------------
           1 Microsoft            Architect            Technical architect
           2 Adobe                PMTS                 Lead developer for A


Rating

  (15 ratings)

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

Comments

Follow-up to response

Sagar, August 29, 2017 - 6:13 am UTC

Thanks for the response Connor.

Bit of background on my question - I am exploring usage of Oracle Database 12cs JSON document store for a use case. We will get files from different source systems - NoSQL and Relational databases (both On-prem or Cloud) in the form of JSON, CSV, XMLs etc. I am interested in exploring DB 12cs feature of using DB as JSON document store and accessing/processing data using SQL/JSON, PL/JSON and SODA for Rest & Java.

Now we will get JSON with user details data which would contain expected fields like - user_id (SA), user_name (SA), user_address (MVA), user_phone (CMVA), user_experience (CMVA), user_login (SA), user_password (SA) etc..
SA - Simple attribute
MVA - Multi-value attribute
CMVA - Complex Multi-value attribute

In your response, you suggested to have separate views to cater for two CMVAs in my use case. Now while this might work for JSON file with few CMVAs, in a JSON with say 10+ CMVAs - creating separate views could be bit messier!

Can you suggest how I should go about in such a scenario?
Also I am exploring use cases for hierarchical data support in JSON using SQL/JSON or SODA APIs. Could you guide me to any such samples?

Thanks in advance.

Follow-up to response

Sagar, August 29, 2017 - 6:24 am UTC

Thanks for the response Connor.

A bit of background for my use case - I am exploring usage of Oracle 12c as JSON document store for a use case wherein I will get files (XML, JSON, CSV) from different source systems like NoSQL and Relations databases (On-Prem or Cloud), and will load them as JSON files in Oracle 12c leveraging SQL/JSON, PL/JSON, SODA for Rest&Java features.

As for this use cases, we would get users data from source systems containing fields like user_id (SA), user_login (SA), user_password (SA), user_name (SA), user_address (MVA), user_phone (CMVA), user_experience (CMVA) etc..
SA - Simple attribute
MVA - Multi-value attribute
CMVA - Complex Multi-value attribute

Now for JSONs containing few CMVAs your approach of having multiple Views could work, but with JSONs having many CMVAs (20+), it could get messier!

Could you suggest me the right approach to follow here?

Also I am exploring use cases of Oracle 12c support for hierarchical data in JSONs. Could you guide me to some samples please?

Many Thanks in advance.
Connor McDonald
August 31, 2017 - 8:07 am UTC

I'll come back to my previous example. You have two branches in your hierarchy (phones and experience).

ONE_MANY

You can't infer a relationship between employee and photocopier. Sue doesn't own the Canon (she might, she might not). So if you're trying to flatten that into rows and columns for a report, you either have:

- separate output (dept+emps, dept+photocopiers), OR
- you lie and invent a relationship



If I may jump in...

Stew Ashton, August 29, 2017 - 2:40 pm UTC

To answer the original question as asked, this squishes the phone data and the experience data together in two rows. Why this is desirable I don't know, since it gives the false impression that row 1 of phone is related to row 1 of experience.
select * from (
  SELECT d.*, coalesce(up_rn, ue_rn) rn
  FROM test_user, 
         JSON_TABLE( 
           user_json, 
           '$' 
           columns ( 
      USER_KEY   VARCHAR2(30 CHAR)    path '$.user_key', 
      USER_NAME   VARCHAR2(30 CHAR)    path '$.user_name', 
      NESTED PATH '$.user_phone[*]' 
      columns ( 
        up_rn for ordinality,
        USER_PHONE_TYPE  VARCHAR2(24 CHAR)    path '$.type',  
        USER_PHONE_NUMBER VARCHAR2(24 CHAR)    path '$.number' 
        ), 
      NESTED PATH '$.user_experience[*]' 
      columns ( 
        ue_rn for ordinality,
        USER_EXP_IDX    NUMBER(38)      path '$.idx',  
        USER_EXP_CMPNY VARCHAR2(256 CHAR)   path '$.info.Company',  
        USER_EXP_ROLE VARCHAR2(14 CHAR)    path '$.info.Role',  
        USER_EXP_DESC VARCHAR2(1024 CHAR)  path '$.info.Description' 
        ) 
      ) 
    ) d
)
match_recognize(
  partition by user_key, rn
  measures user_name user_name, 
    p.user_phone_type user_phone_type, 
    p.user_phone_number user_phone_number,
    e.user_exp_idx user_exp_idx,
    e.user_exp_cmpny user_exp_cmpny, 
    e.user_exp_role user_exp_role, 
    e.user_exp_desc user_exp_desc
  pattern( (p|e) + )
  define p as up_rn is not null,
    e as ue_rn is not null
);

USER_KEY RN USER_NAME      USER_PHONE_TYPE USER_PHONE_NUMBER USER_EXP_IDX USER_EXP_CMPNY USER_EXP_ROLE USER_EXP_DESC
       1    Arthur Stygall Office          823-555-9969                 1 Microsoft      Architect     Technical architect for Microsoft Azure Cloud
       1  2 Arthur Stygall Mobile          976-555-1234                 2 Adobe          PMTS          Lead developer for Adobe Flash technology  

My suggestion

Stew Ashton, August 29, 2017 - 3:08 pm UTC

Put the data into SQL tables! Then you can query it the way you want to without having to deal with "union joins" among all your CMVs.
create table z_user(
  user_key varchar2(30),
  user_name varchar2(30)
);

create table z_phones(
  user_key varchar2(30),
  USER_PHONE_TYPE varchar2(30),
  USER_PHONE_NUMBER varchar2(30)
)
;

create table z_experiences(
  user_key varchar2(30),
  USER_EXP_IDX varchar2(30),
  USER_EXP_CMPNY varchar2(30),
  USER_EXP_ROLE varchar2(30),
  USER_EXP_DESC varchar2(45)
);

insert all
when rn = 1
  then into z_user values(user_key, user_name)
when up_rn is not null
  then into z_phones values(user_key, user_phone_type, user_phone_number)
when ue_rn is not null
  then into z_experiences values(user_key, user_exp_idx, user_exp_cmpny, user_exp_role, user_exp_desc)  
SELECT d.*,
  row_number() over(partition by user_key order by null) rn
FROM test_user, 
       JSON_TABLE( 
         user_json, 
         '$' 
         columns ( 
    USER_KEY   VARCHAR2(30 CHAR)    path '$.user_key', 
    USER_NAME   VARCHAR2(30 CHAR)    path '$.user_name', 
    NESTED PATH '$.user_phone[*]' 
    columns ( 
      up_rn for ordinality,
      USER_PHONE_TYPE  VARCHAR2(24 CHAR)    path '$.type',  
      USER_PHONE_NUMBER VARCHAR2(24 CHAR)    path '$.number' 
      ), 
    NESTED PATH '$.user_experience[*]' 
    columns ( 
      ue_rn for ordinality,
      USER_EXP_IDX    NUMBER(32)      path '$.idx',  
      USER_EXP_CMPNY VARCHAR2(32 CHAR)   path '$.info.Company',  
      USER_EXP_ROLE VARCHAR2(14 CHAR)    path '$.info.Role',  
      USER_EXP_DESC VARCHAR2(32 CHAR)  path '$.info.Description' 
      ) 
    ) 
  ) d;

Connor McDonald
August 31, 2017 - 8:00 am UTC

How old school of you Stew :-)

Thanks

Sagar, September 18, 2017 - 4:30 pm UTC

Thanks guys for the response.

Much appreciated!

Tried Stew last query on 12.1.0.2

Moris, November 18, 2018 - 9:16 pm UTC

hello there

ive tried on 12.1 the insert all stmt but i didit get the null in up_rn and ue_rn so it insert rows null values!!
is it a bug on the 12.1 ??

SELECT d.*,
  row_number() over(partition by pu_key order by null) rn
FROM test_pu,
       JSON_TABLE(
         pu_json,
         '$'
         columns (
    pu_KEY   VARCHAR2(30 CHAR)    path '$.pu_key',
    pu_NAME   VARCHAR2(30 CHAR)    path '$.pu_name',
    NESTED PATH '$.pu_phone[*]'
    columns (
      up_rn for ordinality,
      pu_PHONE_TYPE  VARCHAR2(24 CHAR)    path '$.type',
      pu_PHONE_NUMBER VARCHAR2(24 CHAR)    path '$.number'
      ),
    NESTED PATH '$.pu_experience[*]'
    columns (
      ue_rn for ordinality,
      pu_EXP_IDX    NUMBER(32)      path '$.idx',
      pu_EXP_CMPNY VARCHAR2(32 CHAR)   path '$.info.Company',
      pu_EXP_ROLE VARCHAR2(14 CHAR)    path '$.info.Role',
      pu_EXP_DESC VARCHAR2(32 CHAR)  path '$.info.Description'
      )
    )
  ) d;    


Error starting at line : 1 in command -
insert all
when rn = 1
  then into z_pu values(pu_key, pu_name)
when up_rn is not null
  then into z_phones values(pu_key, pu_phone_type, pu_phone_number)
when ue_rn is not null
  then into z_experiences values(pu_key, pu_exp_idx, pu_exp_cmpny, pu_exp_role, pu_exp_desc)   
 SELECT d.*
 ,  row_number() over(partition by pu_key order by null) rn
FROM view_test_pu2 d

Error at Command Line : 1 Column : 1
Error report -
SQL Error: ORA-00904: "UE_RN": invalid identifier
00904. 00000 -  "%s: invalid identifier"
*Cause:    
*Action:

Error starting at line : 1 in command -
insert all
when rn = 1
  then into z_pu values(pu_key, pu_name)
when sk_phones is not null
  then into z_phones values(pu_key, pu_phone_type, pu_phone_number)
when sk_exp is not null
  then into z_experiences values(pu_key, pu_exp_idx, pu_exp_cmpny, pu_exp_role, pu_exp_desc)   
 SELECT d.*
 ,  row_number() over(partition by pu_key order by null) rn
FROM view_test_pu2 d

Error at Command Line : 1 Column : 1
Error report -
SQL Error: ORA-00904: "SK_PHONES": invalid identifier
00904. 00000 -  "%s: invalid identifier"
*Cause:    
*Action:

18 rows inserted.


Error starting at line : 1 in command -
insert all
when rn = 1
  then into z_pu values(pu_key, pu_name)
when sk_phone is not null
  then into z_phones values(pu_key, pu_phone_type, pu_phone_number)
when sk_exp is not null
  then into z_experiences values(pu_key, pu_exp_idx, pu_exp_cmpny, pu_exp_role, pu_exp_desc)   
 SELECT d.*
 ,  row_number() over(partition by pu_key order by null) rn
FROM view_test_pu2 d


   SELECT d.*,
  row_number() over(partition by pu_key order by null) rn
FROM test_pu,
       JSON_TABLE(
         pu_json,
         '$'
         columns (
    pu_KEY   VARCHAR2(30 CHAR)    path '$.pu_key',
    pu_NAME   VARCHAR2(30 CHAR)    path '$.pu_name',
    NESTED PATH '$.pu_phone[*]'
    columns (
      up_rn for ordinality,
      pu_PHONE_TYPE  VARCHAR2(24 CHAR)    path '$.type',
      pu_PHONE_NUMBER VARCHAR2(24 CHAR)    path '$.number'
      ),
    NESTED PATH '$.pu_experience[*]'
    columns (
      ue_rn for ordinality,
      pu_EXP_IDX    NUMBER(32)      path '$.idx',
      pu_EXP_CMPNY VARCHAR2(32 CHAR)   path '$.info.Company',
      pu_EXP_ROLE VARCHAR2(14 CHAR)    path '$.info.Role',
      pu_EXP_DESC VARCHAR2(32 CHAR)  path '$.info.Description'
      )
    )
  ) d
Error at Command Line : 1 Column : 1
Error report -
SQL Error: ORA-00933: SQL command not properly ended
00933. 00000 -  "SQL command not properly ended"
*Cause:    
*Action:

PU_KEY                         PU_NAME                             UP_RN PU_PHONE_TYPE            PU_PHONE_NUMBER               UE_RN PU_EXP_IDX PU_EXP_CMPNY                     PU_EXP_ROLE    PU_EXP_DESC                              RN
------------------------------ ------------------------------ ---------- ------------------------ ------------------------ ---------- ---------- -------------------------------- -------------- -------------------------------- ----------
1                              Arthur Stygall                          1 Office                   823-555-9969                      1                                                                                                      1
1                              Arthur Stygall                          2 Mobile                   976-555-1234                      2                                                                                                      2
1                              Arthur Stygall                          3                                                            3          1 Microsoft                        Architect      Technical architect for Microsof          3
1                              Arthur Stygall                          4                                                            4          2 Adobe                            PMTS           Lead developer for Adobe Flash t          4
2                              Paul Stygall                            1 Office                   823-777-9969                      1                                                                                                      1
2                              Paul Stygall                            2 Mobile                   976-777-1234                      2                                                                                                      2
2                              Paul Stygall                            3                                                            3          1 Oracle                           Architect      Technical architect for Oracle A          3
2                              Paul Stygall                            4                                                            4          2 Adobe                            PMTS           Lead developer for Sql technolog          4

8 rows selected. 

                         

sorry i correct my post cause ive pasted the errors.

Moris, November 18, 2018 - 9:21 pm UTC

as you can see , ue_rn and u_rn ,no null values

SELECT d.*,
  row_number() over(partition by pu_key order by null) rn
FROM test_pu,
       JSON_TABLE(
         pu_json,
         '$'
         columns (
    pu_KEY   VARCHAR2(30 CHAR)    path '$.pu_key',
    pu_NAME   VARCHAR2(30 CHAR)    path '$.pu_name',
    NESTED PATH '$.pu_phone[*]'
    columns (
      up_rn for ordinality,
      pu_PHONE_TYPE  VARCHAR2(24 CHAR)    path '$.type',
      pu_PHONE_NUMBER VARCHAR2(24 CHAR)    path '$.number'
      ),
    NESTED PATH '$.pu_experience[*]'
    columns (
      ue_rn for ordinality,
      pu_EXP_IDX    NUMBER(32)      path '$.idx',
      pu_EXP_CMPNY VARCHAR2(32 CHAR)   path '$.info.Company',
      pu_EXP_ROLE VARCHAR2(14 CHAR)    path '$.info.Role',
      pu_EXP_DESC VARCHAR2(32 CHAR)  path '$.info.Description'
      )
    )
  ) d;      



PU_KEY                         PU_NAME                             UP_RN PU_PHONE_TYPE            PU_PHONE_NUMBER               UE_RN PU_EXP_IDX PU_EXP_CMPNY                     PU_EXP_ROLE    PU_EXP_DESC                              RN
------------------------------ ------------------------------ ---------- ------------------------ ------------------------ ---------- ---------- -------------------------------- -------------- -------------------------------- ----------
1                              Arthur Stygall                          1 Office                   823-555-9969                      1                                                                                                      1
1                              Arthur Stygall                          2 Mobile                   976-555-1234                      2                                                                                                      2
1                              Arthur Stygall                          3                                                            3          1 Microsoft                        Architect      Technical architect for Microsof          3
1                              Arthur Stygall                          4                                                            4          2 Adobe                            PMTS           Lead developer for Adobe Flash t          4
2                              Paul Stygall                            1 Office                   823-777-9969                      1                                                                                                      1
2                              Paul Stygall                            2 Mobile                   976-777-1234                      2                                                                                                      2
2                              Paul Stygall                            3                                                            3          1 Oracle                           Architect      Technical architect for Oracle A          3
2                              Paul Stygall                            4                                                            4          2 Adobe                            PMTS           Lead developer for Sql technolog          4

8 rows selected. 

how fix this

A reader, November 18, 2018 - 10:01 pm UTC

INSERT INTO test_pu
  VALUES (
    SYS_GUID(),
    SYSTIMESTAMP,
    '{
     "pu_key":1,
     "pu_name":"Arthur Stygall",
     "pu_type":"End-pu",
     "pu_status":"Active",
     "pu_emp_type":"Full-Time",
     "pu_login":"arthurstygall",
     "pu_password":"test1243",
     "pu_address":{
      "street":"200 Sporting Green",
      "city":"South San Francisco",
      "state":"CA",
      "zipCode":99236,
      "country":"United States of America"
     },
     "pu_phone":[
     {
        "type":"Office",
        "number":"823-555-9969"
     },
     {
        "type":"Mobile",
        "number":"976-555-1234"
     }
     ],
     "pu_email":"arthur.stygall@achme.com",
     "pu_create_date":"19-JAN-10",
     "pu_manager_name":"Ron Howard",
     "pu_experience":[
          {
       "idx":1,
       "info":{
            "Company":"Microsoft",
            "Role":"Architect",
            "Description":"Technical architect for Microsoft Azure Cloud"
        }
          },
          {
       "idx":1,
       "info":{
            "Company":"Microsoft",
            "Role":"Architect",
            "Description":"Technical architect for Microsoft Azure Cloud"
        }
          },          {
       "idx":1,
       "info":{
            "Company":"Microsoft",
            "Role":"Architect",
            "Description":"Technical architect for Microsoft Azure Cloud"
        }
          },          {
       "idx":1,
       "info":{
            "Company":"Microsoft",
            "Role":"Architect",
            "Description":"Technical architect for Microsoft Azure Cloud"
        }
          },          {
       "idx":1,
       "info":{
            "Company":"Microsoft",
            "Role":"Architect",
            "Description":"Technical architect for Microsoft Azure Cloud"
        }
          },          {
       "idx":1,
       "info":{
            "Company":"Microsoft",
            "Role":"Architect",
            "Description":"Technical architect for Microsoft Azure Cloud"
        }
          },          {
       "idx":1,
       "info":{
            "Company":"Microsoft",
            "Role":"Architect",
            "Description":"Technical architect for Microsoft Azure Cloud"
        }
          },          {
       "idx":1,
       "info":{
            "Company":"Microsoft",
            "Role":"Architect",
            "Description":"Technical architect for Microsoft Azure Cloud"
        }
          },          {
       "idx":1,
       "info":{
            "Company":"Microsoft",
            "Role":"Architect",
            "Description":"Technical architect for Microsoft Azure Cloud"
        }
          },          {
       "idx":1,
       "info":{
            "Company":"Microsoft",
            "Role":"Architect",
            "Description":"Technical architect for Microsoft Azure Cloud"
        }
          },          {
       "idx":1,
       "info":{
            "Company":"Microsoft",
            "Role":"Architect",
            "Description":"Technical architect for Microsoft Azure Cloud"
        }
          },          {
       "idx":1,
       "info":{
            "Company":"Microsoft",
            "Role":"Architect",
            "Description":"Technical architect for Microsoft Azure Cloud"
        }
          },          {
       "idx":1,
       "info":{
            "Company":"Microsoft",
            "Role":"Architect",
            "Description":"Technical architect for Microsoft Azure Cloud"
        }
          },          {
       "idx":1,
       "info":{
            "Company":"Microsoft",
            "Role":"Architect",
            "Description":"Technical architect for Microsoft Azure Cloud"
        }
          },          {
       "idx":1,
       "info":{
            "Company":"Microsoft",
            "Role":"Architect",
            "Description":"Technical architect for Microsoft Azure Cloud"
        }
          },          
          {
       "idx":2,
       "info":{
            "Company":"Adobe",
            "Role":"PMTS",
            "Description":"Lead developer for Adobe Flash technology"
        }
          }
  ]
}'
);


Error at Command Line : 1 Column : 1
Error report -
SQL Error: ORA-01704: string literal too long
01704. 00000 -  "string literal too long"
*Cause:    The string literal is longer than 4000 characters.
*Action:   Use a string literal of at most 4000 characters.
           Longer values may only be entered using bind variables.

Connor McDonald
November 26, 2018 - 11:38 am UTC

Assign it to a clob

SQL> create table test_pu(id raw(32), ts timestamp, js clob);

Table created.

SQL>
SQL> variable c clob
SQL> begin
  2   :c :=
  3       '{
  4        "pu_key":1,
  5        "pu_name":"Arthur Stygall",
  6        "pu_type":"End-pu",
  7        "pu_status":"Active",
  8        "pu_emp_type":"Full-Time",
  9        "pu_login":"arthurstygall",
 10        "pu_password":"test1243",
 11        "pu_address":{
 12         "street":"200 Sporting Green",
 13         "city":"South San Francisco",
 14         "state":"CA",
 15         "zipCode":99236,
 16         "country":"United States of America"
 17        },
 18        "pu_phone":[
 19        {
 20           "type":"Office",
 21           "number":"823-555-9969"
 22        },
 23        {
 24           "type":"Mobile",
 25           "number":"976-555-1234"
 26        }
 27        ],
 28        "pu_email":"arthur.stygall@achme.com",
 29        "pu_create_date":"19-JAN-10",
 30        "pu_manager_name":"Ron Howard",
 31        "pu_experience":[
 32             {
 33          "idx":1,
 34          "info":{
 35               "Company":"Microsoft",
 36               "Role":"Architect",
 37               "Description":"Technical architect for Microsoft Azure Cloud"
 38           }
 39             },
 40             {
 41          "idx":1,
 42          "info":{
 43               "Company":"Microsoft",
 44               "Role":"Architect",
 45               "Description":"Technical architect for Microsoft Azure Cloud"
 46           }
 47             },          {
 48          "idx":1,
 49          "info":{
 50               "Company":"Microsoft",
 51               "Role":"Architect",
 52               "Description":"Technical architect for Microsoft Azure Cloud"
 53           }
 54             },          {
 55          "idx":1,
 56          "info":{
 57               "Company":"Microsoft",
 58               "Role":"Architect",
 59               "Description":"Technical architect for Microsoft Azure Cloud"
 60           }
 61             },          {
 62          "idx":1,
 63          "info":{
 64               "Company":"Microsoft",
 65               "Role":"Architect",
 66               "Description":"Technical architect for Microsoft Azure Cloud"
 67           }
 68             },          {
 69          "idx":1,
 70          "info":{
 71               "Company":"Microsoft",
 72               "Role":"Architect",
 73               "Description":"Technical architect for Microsoft Azure Cloud"
 74           }
 75             },          {
 76          "idx":1,
 77          "info":{
 78               "Company":"Microsoft",
 79               "Role":"Architect",
 80               "Description":"Technical architect for Microsoft Azure Cloud"
 81           }
 82             },          {
 83          "idx":1,
 84          "info":{
 85               "Company":"Microsoft",
 86               "Role":"Architect",
 87               "Description":"Technical architect for Microsoft Azure Cloud"
 88           }
 89             },          {
 90          "idx":1,
 91          "info":{
 92               "Company":"Microsoft",
 93               "Role":"Architect",
 94               "Description":"Technical architect for Microsoft Azure Cloud"
 95           }
 96             },          {
 97          "idx":1,
 98          "info":{
 99               "Company":"Microsoft",
100               "Role":"Architect",
101               "Description":"Technical architect for Microsoft Azure Cloud"
102           }
103             },          {
104          "idx":1,
105          "info":{
106               "Company":"Microsoft",
107               "Role":"Architect",
108               "Description":"Technical architect for Microsoft Azure Cloud"
109           }
110             },          {
111          "idx":1,
112          "info":{
113               "Company":"Microsoft",
114               "Role":"Architect",
115               "Description":"Technical architect for Microsoft Azure Cloud"
116           }
117             },          {
118          "idx":1,
119          "info":{
120               "Company":"Microsoft",
121               "Role":"Architect",
122               "Description":"Technical architect for Microsoft Azure Cloud"
123           }
124             },          {
125          "idx":1,
126          "info":{
127               "Company":"Microsoft",
128               "Role":"Architect",
129               "Description":"Technical architect for Microsoft Azure Cloud"
130           }
131             },          {
132          "idx":1,
133          "info":{
134               "Company":"Microsoft",
135               "Role":"Architect",
136               "Description":"Technical architect for Microsoft Azure Cloud"
137           }
138             },
139             {
140          "idx":2,
141          "info":{
142               "Company":"Adobe",
143               "Role":"PMTS",
144               "Description":"Lead developer for Adobe Flash technology"
145           }
146             }
147     ]
148   }';
149  end;
150  /

PL/SQL procedure successfully completed.

SQL>
SQL> INSERT INTO test_pu
  2     VALUES (
  3       SYS_GUID(),
  4       SYSTIMESTAMP,
  5       :c);

1 row created.


Not my case

A reader, November 26, 2018 - 12:46 pm UTC

Sorry but i am not using sqlplus.
A java program is ready a json text file and inserting the whole text as string.
Cannot use variable as you did.
Any solution?

Not my case

A reader, November 26, 2018 - 12:46 pm UTC

Sorry but i am not using sqlplus.
A java program is ready a json text file and inserting the whole text as string.
Cannot use variable as you did.
Any solution?
Connor McDonald
November 27, 2018 - 4:46 am UTC

It's not difficult to transpose a string to a clob

    private CLOB getCLOB(String clobData, OracleConnection conn) {
        CLOB tempClob = null;

        try {
            //  create a new temporary CLOB
            tempClob = CLOB.createTemporary(conn, true, CLOB.DURATION_SESSION);
            // Open the temporary CLOB in readwrite mode to enable writing
            tempClob.open(CLOB.MODE_READWRITE);

            // Get the output stream to write
            //deprecated Writer tempClobWriter = tempClob.getCharacterOutputStream();
            Writer tempClobWriter = tempClob.setCharacterStream(0L);

            // Write the data into the temporary CLOB
            tempClobWriter.write(clobData);
            // Flush and close the stream
            tempClobWriter.flush();
            tempClobWriter.close();
            // Close the temporary CLOB
            tempClob.close();
        } catch (Exception exp) {
            // Free CLOB object
            // do something
            try {
                tempClob.freeTemporary();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return tempClob;
}


No answer

Moris, November 26, 2018 - 5:39 pm UTC

Didn't get response on my question on November 18, 2018 - 9:21 pm UTC see above.
You indeed answered the next one.
Connor McDonald
November 27, 2018 - 4:42 am UTC

"ive tried on 12.1 the insert all stmt but i didit get the null in up_rn and ue_rn so it insert rows null values!!"

is not really something we can digest. Perhaps more elaboration?

Something digest.

Moris, November 27, 2018 - 8:16 am UTC

Just take Stew statement..
insert all when rn = 1 then into z_user values(user_key, user_name) when up_rn is not null then into z_phones values(user_key, user_phone_type, user_phone_number) when ue_rn is not null then into z_experiences values(user_key, user_exp_idx, user_exp_cmpny, user_exp_role, user_exp_desc) SELECT d.*, row_number() over(partition by user_key order by null) rn FROM test_user, JSON_TABLE( user_json, '$' columns ( 


"when up_rn is not null ..."
Sir, up_rn is always not null ... I've try it on my 12.1 database.

I really cant make it more digestible.
Thank you

Connor McDonald
November 27, 2018 - 9:12 am UTC

12.1 bug

SQL> select * from v$version where rownum = 1;

BANNER
-----------------------------------------------------------------------------
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production


SQL> CREATE TABLE test_user (
  2    id      RAW(16) NOT NULL,
  3    loading_date    TIMESTAMP(6) WITH TIME ZONE,
  4    user_json   CLOB CHECK (user_json IS JSON)
  5  );

Table created.

SQL>
SQL> INSERT INTO test_user
  2    VALUES (
  3      SYS_GUID(),
  4      SYSTIMESTAMP,
  5      '{
  6       "user_key":1,
  7       "user_name":"Arthur Stygall",
  8       "user_type":"End-user",
  9       "user_status":"Active",
 10       "user_emp_type":"Full-Time",
 11       "user_login":"arthurstygall",
 12       "user_password":"test1243",
 13       "user_address":{
 14        "street":"200 Sporting Green",
 15        "city":"South San Francisco",
 16        "state":"CA",
 17        "zipCode":99236,
 18        "country":"United States of America"
 19       },
 20       "user_phone":[
 21       {
 22          "type":"Office",
 23          "number":"823-555-9969"
 24       },
 25       {
 26          "type":"Mobile",
 27          "number":"976-555-1234"
 28       }
 29       ],
 30       "user_email":"arthur.stygall@achme.com",
 31       "user_create_date":"19-JAN-10",
 32       "user_manager_name":"Ron Howard",
 33       "user_experience":[
 34            {
 35         "idx":1,
 36         "info":{
 37              "Company":"Microsoft",
 38              "Role":"Architect",
 39              "Description":"Technical architect for Microsoft Azure Cloud"
 40          }
 41            },
 42            {
 43         "idx":2,
 44         "info":{
 45              "Company":"Adobe",
 46              "Role":"PMTS",
 47              "Description":"Lead developer for Adobe Flash technology"
 48          }
 49            }
 50    ]
 51  }'
 52  );

1 row created.

SQL>
SQL> create table z_user(
  2    user_key varchar2(30),
  3    user_name varchar2(30)
  4  );

Table created.

SQL>
SQL> create table z_phones(
  2    user_key varchar2(30),
  3    USER_PHONE_TYPE varchar2(30),
  4    USER_PHONE_NUMBER varchar2(30)
  5  )
  6  ;

Table created.

SQL>
SQL> create table z_experiences(
  2    user_key varchar2(30),
  3    USER_EXP_IDX varchar2(30),
  4    USER_EXP_CMPNY varchar2(30),
  5    USER_EXP_ROLE varchar2(30),
  6    USER_EXP_DESC varchar2(45)
  7  );

Table created.

SQL>
SQL> insert all
  2  when rn = 1
  3    then into z_user values(user_key, user_name)
  4  when up_rn is not null
  5    then into z_phones values(user_key, user_phone_type, user_phone_number)
  6  when ue_rn is not null
  7    then into z_experiences values(user_key, user_exp_idx, user_exp_cmpny, user_exp_role, user_exp_desc)
  8  SELECT d.*,
  9    row_number() over(partition by user_key order by null) rn
 10  FROM test_user,
 11         JSON_TABLE(
 12           user_json,
 13           '$'
 14           columns (
 15      USER_KEY   VARCHAR2(30 CHAR)    path '$.user_key',
 16      USER_NAME   VARCHAR2(30 CHAR)    path '$.user_name',
 17      NESTED PATH '$.user_phone[*]'
 18      columns (
 19        up_rn for ordinality,
 20        USER_PHONE_TYPE  VARCHAR2(24 CHAR)    path '$.type',
 21        USER_PHONE_NUMBER VARCHAR2(24 CHAR)    path '$.number'
 22        ),
 23      NESTED PATH '$.user_experience[*]'
 24      columns (
 25        ue_rn for ordinality,
 26        USER_EXP_IDX    NUMBER(32)      path '$.idx',
 27        USER_EXP_CMPNY VARCHAR2(32 CHAR)   path '$.info.Company',
 28        USER_EXP_ROLE VARCHAR2(14 CHAR)    path '$.info.Role',
 29        USER_EXP_DESC VARCHAR2(32 CHAR)  path '$.info.Description'
 30        )
 31      )
 32    ) d;

9 rows created.

SQL>
SQL> commit;

Commit complete.

SQL>
SQL> set lines 200
SQL> select * from z_user;

USER_KEY                       USER_NAME
------------------------------ ------------------------------
1                              Arthur Stygall

1 row selected.

SQL> select * from z_phones;

USER_KEY                       USER_PHONE_TYPE                USER_PHONE_NUMBER
------------------------------ ------------------------------ ------------------------------
1                              Office                         823-555-9969
1                              Mobile                         976-555-1234
1
1

4 rows selected.

SQL> select * from z_experiences;

USER_KEY                       USER_EXP_IDX                   USER_EXP_CMPNY                 USER_EXP_ROLE                  USER_EXP_DESC
------------------------------ ------------------------------ ------------------------------ ------------------------------ ---------------------------------------------
1
1
1                              1                              Microsoft                      Architect                      Technical architect for Microsoft Azure Cloud
1                              2                              Adobe                          PMTS                   Lead developer for Adobe Flash technology

4 rows selected.

SQL>

SQL> select * from v$version where rownum = 1;

BANNER
--------------------------------------------------------------------------------
Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production


SQL> CREATE TABLE test_user (
  2    id      RAW(16) NOT NULL,
  3    loading_date    TIMESTAMP(6) WITH TIME ZONE,
  4    user_json   CLOB CHECK (user_json IS JSON)
  5  );

Table created.

SQL>
SQL> INSERT INTO test_user
  2    VALUES (
  3      SYS_GUID(),
  4      SYSTIMESTAMP,
  5      '{
  6       "user_key":1,
  7       "user_name":"Arthur Stygall",
  8       "user_type":"End-user",
  9       "user_status":"Active",
 10       "user_emp_type":"Full-Time",
 11       "user_login":"arthurstygall",
 12       "user_password":"test1243",
 13       "user_address":{
 14        "street":"200 Sporting Green",
 15        "city":"South San Francisco",
 16        "state":"CA",
 17        "zipCode":99236,
 18        "country":"United States of America"
 19       },
 20       "user_phone":[
 21       {
 22          "type":"Office",
 23          "number":"823-555-9969"
 24       },
 25       {
 26          "type":"Mobile",
 27          "number":"976-555-1234"
 28       }
 29       ],
 30       "user_email":"arthur.stygall@achme.com",
 31       "user_create_date":"19-JAN-10",
 32       "user_manager_name":"Ron Howard",
 33       "user_experience":[
 34            {
 35         "idx":1,
 36         "info":{
 37              "Company":"Microsoft",
 38              "Role":"Architect",
 39              "Description":"Technical architect for Microsoft Azure Cloud"
 40          }
 41            },
 42            {
 43         "idx":2,
 44         "info":{
 45              "Company":"Adobe",
 46              "Role":"PMTS",
 47              "Description":"Lead developer for Adobe Flash technology"
 48          }
 49            }
 50    ]
 51  }'
 52  );

1 row created.

SQL>
SQL> create table z_user(
  2    user_key varchar2(30),
  3    user_name varchar2(30)
  4  );

Table created.

SQL>
SQL> create table z_phones(
  2    user_key varchar2(30),
  3    USER_PHONE_TYPE varchar2(30),
  4    USER_PHONE_NUMBER varchar2(30)
  5  )
  6  ;

Table created.

SQL>
SQL> create table z_experiences(
  2    user_key varchar2(30),
  3    USER_EXP_IDX varchar2(30),
  4    USER_EXP_CMPNY varchar2(30),
  5    USER_EXP_ROLE varchar2(30),
  6    USER_EXP_DESC varchar2(45)
  7  );

Table created.

SQL>
SQL> insert all
  2  when rn = 1
  3    then into z_user values(user_key, user_name)
  4  when up_rn is not null
  5    then into z_phones values(user_key, user_phone_type, user_phone_number)
  6  when ue_rn is not null
  7    then into z_experiences values(user_key, user_exp_idx, user_exp_cmpny, user_exp_role, user_exp_desc)
  8  SELECT d.*,
  9    row_number() over(partition by user_key order by null) rn
 10  FROM test_user,
 11         JSON_TABLE(
 12           user_json,
 13           '$'
 14           columns (
 15      USER_KEY   VARCHAR2(30 CHAR)    path '$.user_key',
 16      USER_NAME   VARCHAR2(30 CHAR)    path '$.user_name',
 17      NESTED PATH '$.user_phone[*]'
 18      columns (
 19        up_rn for ordinality,
 20        USER_PHONE_TYPE  VARCHAR2(24 CHAR)    path '$.type',
 21        USER_PHONE_NUMBER VARCHAR2(24 CHAR)    path '$.number'
 22        ),
 23      NESTED PATH '$.user_experience[*]'
 24      columns (
 25        ue_rn for ordinality,
 26        USER_EXP_IDX    NUMBER(32)      path '$.idx',
 27        USER_EXP_CMPNY VARCHAR2(32 CHAR)   path '$.info.Company',
 28        USER_EXP_ROLE VARCHAR2(14 CHAR)    path '$.info.Role',
 29        USER_EXP_DESC VARCHAR2(32 CHAR)  path '$.info.Description'
 30        )
 31      )
 32    ) d;

5 rows created.

SQL>
SQL> commit;

Commit complete.

SQL>
SQL> set lines 200
SQL> select * from z_user;

USER_KEY                       USER_NAME
------------------------------ ------------------------------
1                              Arthur Stygall

1 row selected.

SQL> select * from z_phones;

USER_KEY                       USER_PHONE_TYPE                USER_PHONE_NUMBER
------------------------------ ------------------------------ ------------------------------
1                              Office                         823-555-9969
1                              Mobile                         976-555-1234

2 rows selected.

SQL> select * from z_experiences;

USER_KEY                       USER_EXP_IDX                   USER_EXP_CMPNY                 USER_EXP_ROLE                  USER_EXP_DESC
------------------------------ ------------------------------ ------------------------------ ------------------------------ ---------------------------------------------
1                              1                              Microsoft                      Architect                      Technical architect for Microsoft Azure Cloud
1                              2                              Adobe                          PMTS                           Lead developer for Adobe Flash technology

2 rows selected.

SQL>


@Moris re:INSERT ALL errors

Stew Ashton, November 27, 2018 - 9:11 am UTC

Hello,

You have taken the original example and changed the JSON, the table name and the column name.

Then you seem to say "I can't get Stew's code to run on 12.1".

Sorry, but that is not my code anymore.

What happens if you take the original example exactly as is, and then run my code exactly as is?

Best regards,
Stew

Spoke a few minutes too soon...

Stew Ashton, November 27, 2018 - 9:16 am UTC

Connor gave a real answer, please disregard my previous post.

Regards,
Stew
Connor McDonald
November 27, 2018 - 9:28 am UTC

Stew - we appreciate all the time you give here.

Toi didn't both catch it.

Moris, November 27, 2018 - 9:35 am UTC

My original question is about different behavior btw 12.1 and 12.2

Connor has just show what I found and what I asking for . Ie the reason.

So the question remains not answered.
Why there is 4 rows on 12.1 and 2 rows on 12.2?
This is so related on original question that stated why i got the rn not null in all cases on 12.1.
Do i repeat . Is it a big on 12.1? Otherwise why this different behavior?
Connor McDonald
November 28, 2018 - 12:49 am UTC

bug

More to Explore

SQL

The Oracle documentation contains a complete SQL reference.