Home > Software design >  Oracle json SQL with arrays to multi field
Oracle json SQL with arrays to multi field

Time:06-15

here is json column in Oracle DB table.

table name : test1

ITEM_ID CAT1 CAT2 POS_VAL_JSON
ITEM1 A 1 {"X" : [1,2,3], "Y" : [1,2,3]}

table name : test2

ITEM_ID CAT1 CAT2 X Y
ITEM1 A 1 {1,2,3} {1,2,3}

How can I get data like this from table1 and table2 each ?

X Y ITEM_ID
1 1 ITEM1
2 2 ITEM1
3 3 ITEM1

CodePudding user response:

You can use JSON_TABLE to get the X values with FOR ORDINALITY to get an index and then the same for the Y values and join:

SELECT x, y, item_id
FROM   test1 t
       CROSS JOIN LATERAL (
         SELECT idx, x
         FROM   JSON_TABLE(
                  t.pos_val_json,
                  '$.X[*]'
                  COLUMNS (
                    idx FOR ORDINALITY,
                    x   NUMBER PATH '$'
                  )
                )
       ) x
       INNER JOIN LATERAL (
         SELECT idx, y
         FROM   JSON_TABLE(
                  t.pos_val_json,
                  '$.Y[*]'
                  COLUMNS (
                    idx FOR ORDINALITY,
                    y   NUMBER PATH '$'
                  )
                )
       ) y
       ON (x.idx = y.idx)

Which, for the sample data:

CREATE TABLE test1 (
  ITEM_ID      VARCHAR2(20),
  CAT1         VARCHAR2(20),
  CAT2         NUMBER,
  POS_VAL_JSON CLOB CHECK (POS_VAL_JSON IS JSON)
);

INSERT INTO test1 (ITEM_ID, CAT1, CAT2, POS_VAL_JSON)
VALUES ('ITEM1', 'A', 1, '{"X" : [1,2,3], "Y" : [1,2,3]}');

Outputs:

X Y ITEM_ID
1 1 ITEM1
2 2 ITEM1
3 3 ITEM1

Similarly, for test2 you can use:

SELECT x.x, y.y, t.item_id
FROM   test2 t
       CROSS JOIN LATERAL (
         SELECT idx, x
         FROM   JSON_TABLE(
                  t.X,
                  '$[*]'
                  COLUMNS (
                    idx FOR ORDINALITY,
                    x   NUMBER PATH '$'
                  )
                )
       ) x
       INNER JOIN LATERAL (
         SELECT idx, y
         FROM   JSON_TABLE(
                  t.Y,
                  '$[*]'
                  COLUMNS (
                    idx FOR ORDINALITY,
                    y   NUMBER PATH '$'
                  )
                )
       ) y
       ON (x.idx = y.idx)

db<>fiddle here

CodePudding user response:

this code works for test2:

WITH
    test2 (ITEM_ID,
           cat1,
           cat2,
           X,
           Y)
    AS
        (SELECT 'item1',
                'A',
                1,
                json_array (1, 2, 3),
                json_array (1, 2, 3)
           FROM DUAL),
    step2
    AS
        (SELECT test2.item_id, t1.name X, ROWNUM num
           FROM test2
                CROSS APPLY
                JSON_TABLE (
                    test2.X,
                    '$'
                    COLUMNS (NESTED PATH '$[*]' COLUMNS (name PATH '$'))) t1),
    step3
    AS
        (SELECT test2.item_id, t1.name Y, ROWNUM num
           FROM test2
                CROSS APPLY
                JSON_TABLE (
                    test2.X,
                    '$'
                    COLUMNS (NESTED PATH '$[*]' COLUMNS (name PATH '$'))) t1)
SELECT step3.item_id, step3.Y, step2.X
  FROM step3 JOIN step2 ON step2.num = step3.num

this code works for test1

WITH
    test1 (ITEM_ID,
           cat1,
           cat2,
           pos_val_json)
    AS
        (SELECT 'item1',
                'A',
                1,
                json_object ('X' VALUE json_array (1, 2, 3),
                             'Y' VALUE json_array (1, 2, 3))
           FROM DUAL),
    step2
    AS
        (SELECT test1.item_id, t1.*,rownum num
           FROM test1
                CROSS APPLY
                JSON_TABLE (
                    test1.pos_val_json,
                    '$'
                    COLUMNS (NESTED PATH '$.X[*]' COLUMNS (X PATH '$'))) t1
                    
                    
) ,step3 as (SELECT test1.item_id, t2.*,rownum num
           FROM test1
           CROSS APPLY
                JSON_TABLE (
                    test1.pos_val_json,
                    '$'
                    COLUMNS (NESTED PATH '$.Y[*]' COLUMNS (Y PATH '$'))) t2)
SELECT step3.item_id,step3.Y,step2.X
  FROM step3 join step2 on step2.num=step3.num
X Y ITEM_ID
1 1 ITEM1
2 2 ITEM1
3 3 ITEM1

this code works for test1 only if the array has 3 values

WITH
    test1 (ITEM_ID,
           cat1,
           cat2,
           pos_val_json)
    AS
        (SELECT 'item1',
                'A',
                1,
                json_object ('X' VALUE json_array (1, 2, 3),
                             'Y' VALUE json_array (1, 2, 3))
           FROM DUAL),
    test2 (ITEM_ID,
           cat1,
           cat2,
           X,
           Y)
    AS
        (SELECT 'item1',
                'A',
                1,
                json_array (1, 2, 3),
                json_array (1, 2, 3)
           FROM DUAL),
    step2
    AS
        (SELECT test1.item_id,
                t.*
           FROM test1
                CROSS APPLY
                JSON_TABLE (
                    test1.pos_val_json,
                    '$'
                    COLUMNS ("X0" PATH '$.X[0]',
                             "X1" PATH '$.X[1]',
                             "X2" PATH '$.X[2]',
                             "Y0" PATH '$.Y[0]',
                             "Y1" PATH '$.Y[1]',
                             "Y2" PATH '$.Y[2]'
                             )) t),
step3 as( SELECT *
  FROM step2
   unpivot(
                (x_value,y_value)
                for xy_name
                in ((x0,y0) as 'xy_0',
                (x1,y1) as 'xy_1',
                (x2,y2) as 'xy_2')
             )
             )
             select item_id,X_value as x, y_value as y from step3

this code works for test2 only if the array has 3 values

WITH
    test2 (ITEM_ID,
           cat1,
           cat2,
           X,
           Y)
    AS
        (SELECT 'item1',
                'A',
                1,
                json_array (1, 2, 3),
                json_array (1, 2, 3)
           FROM DUAL),
    step2
    AS
        (
      SELECT test2.item_id,
                t1.*,t2.*
           FROM test2
                CROSS APPLY
                JSON_TABLE (
                    test2.X,
                    '$'
                    COLUMNS ("X0" PATH '$[0]',
                             "X1" PATH '$[1]',
                             "X2" PATH '$[2]'
                             )) t1
                             
                CROSS APPLY
                JSON_TABLE (
                    test2.Y,
                    '$'
                    COLUMNS ("Y0" PATH '$[0]',
                             "Y1" PATH '$[1]',
                             "Y2" PATH '$[2]'
                             )) t2) , --select * from step2
step3 as( SELECT *
  FROM step2
   unpivot(
                (x_value,y_value)
                for xy_name
                in ((x0,y0) as 'xy_0',
                (x1,y1) as 'xy_1',
                (x2,y2) as 'xy_2')
             )
             )
             select item_id,X_value as x, y_value as y from step3

code

  • Related