0

On the Teradata database (ver.17), I would like to shred a JSON object as below:

{
  "products": [{"category":"car", "name":"toyota"},
               {"category":"aircraft", "name":"boeing"},
               {"category":"fruit","name":"pear"}],
  "prices": [500, 100000, 1]
}

Here, products and prices arrays are paired; toyota's price is 500, boeing is 100000, and pear is 1. My goal is to parse this into the following form:

id  category    name   price
----------------------------
 1       car  toyota     500
 1  aircraft  boeing  100000
 1     fruit    pear       1 

My approach is to use JSON_TABLE to parse products and prices arrays separately and join afterwards.

I could shred the products part using JSON_TABLE function, but I got stuck for the prices part.

What I have so far is below:

/* create temp table for demo */
CREATE MULTISET VOLATILE TABLE test AS (
SELECT 1 AS id, NEW JSON('{
  "products":[{"category":"car","name":"toyota"},
              {"category":"aircraft","name":"boeing"},
              {"category":"fruit","name":"pear"}],
  "prices":[500,100000,1]}') AS doc
)
WITH DATA
ON COMMIT PRESERVE ROWS
;

/* working shredding for products part */
SELECT * FROM JSON_Table (
  ON (SELECT id, doc FROM test)
  USING rowexpr('$.products[*]')
        colexpr('[ {"jsonpath" : "$.category", "type" : "CHAR(20)"},
                   {"jsonpath" : "$.name", "type" : "VARCHAR(20)"},
                   {"ordinal" : true} ]')
) AS JT(id, category, name, ord)
;

/* failing for prices parts, just get NULLs */
SELECT * FROM JSON_Table (
  ON (SELECT id, doc FROM test)
  USING rowexpr('$.prices[*]')
        colexpr('[ {"jsonpath" : "$", "type" : "INTEGER"},
                   {"ordinal" : true} ]')
) AS JT(id, price, ord)
;

The results are below. The output from prices part is not something intended.

+----+------------------------------------------+--------+-----+
| id |                 category                 |  name  | ord |
+----+------------------------------------------+--------+-----+
| 1  | car                                      | toyota |  0  |
| 1  | aircraft                                 | boeing |  1  |
| 1  | fruit                                    |  pear  |  2  |
+----+------------------------------------------+--------+-----+


+----+-------+-----+
| id | price | ord |
+----+-------+-----+
| 1  |  None |  1  |
| 1  |  None |  1  |
| 1  |  None |  1  |
+----+-------+-----+

Can someone advise me on how I can shred the prices part of the JSON, preferably using JSON_TABLE?

Other approaches to achieve the same goal will also be appreciated.

I suppose UNPIVOT syntax could work, but I think it is not efficient because in reality I have much longer sequences and UNPIVOT requires I make a very wide table first (I could be wrong). But if UNPIVOT is actually a good solution for my problem, please let me know that as well.

Kota Mori
  • 6,510
  • 1
  • 21
  • 25

1 Answers1

1

I don't know if JSON_Table can be used to split a value array, but the result looks fishy: ord is always 1 instead of 0,1,2.

JSON_Shread works as expected:

SELECT * 
FROM TD_JSONSHRED(
ON
 (
   SELECT id, doc
   FROM test
 )
USING
   ROWEXPR('prices')
   COLEXPR('')
   RETURNTYPES('INTEGER')
) dt
;

But there's no ordinal returned.

This returns the expected result:

WITH cte AS 
 (
   SELECT id
     ,doc.prices[*] AS prices
   FROM test
 )
SELECT id, ord, trycast(token AS INTEGER) 
FROM TABLE
 ( STRTOK_SPLIT_TO_TABLE (cte.id, cte.prices, '[],')
   RETURNS (id integer, ord integer, token varchar(20)) 
 ) AS d
;
dnoeth
  • 59,503
  • 4
  • 39
  • 56
  • How is `STRTOK_SPLIT_TO_TABLE (cte.id, cte.prices, '[],')` working here? Does it treat any of the characters in the third argument (`[],`) as a delimiter? – Andrew Sep 17 '21 at 15:07
  • @Andrew: Exactly, any number of those characters. If there's a multi-character delimiter or if you want to treat two consecutive delimiters as empty/null switch to REGEXP_SPLIT_TO_TABLE. – dnoeth Sep 17 '21 at 18:39