英文:
Can't extract an array from JSON using JSON_TABLE on DB2 v11.5
问题
I have a table where I allocated a JSON document as a string inside a CLOB field. Inside that JSON, there is an array that I need to expose as a table to join in a SQL sentence.
Example JSON
{
"string":"string",
"array":[{
"type":"main",
"name":"name"
},{
"type":"othertype",
"name":"othername"
}],
"object":{
"type":"objecttype",
"name":"objectname"
}
}
I read the official documentation and found that I can do that with JSON_TABLE function. The documentation has 2 different JSON_TABLE, one on built-in functions, SYSIBM package and the other one on SYSTOOLS package that seems to will be deprecated in the future.
With SYSIBM.JSON_TABLE function, I can extract from the JSON field properties such as string or string inside objects, but I can't extract the array as table rows (my main goal).
Here is the SQL sentence I'm trying to do (I put the JSON as a parameter to check, but the final destination is on a table.field):
select t.*
from json_table('{ "string":"string", "array":[{"type":"main","name":"name"},{"type":"othertype","name":"othername"}],"object":{"type":"objecttype","name":"objectname"}}' FORMAT JSON,
'strict $' columns (
string varchar(20) path 'strict $.string',
type varchar(20) path 'strict $.object.type',
name varchar(20) path 'strict $.object.name',
nested path 'strict $.array[*]' columns(
type2 varchar(20) path 'strict $.type',
name2 varchar(20) path 'strict $.name'
)
) error on error
) as t where true;
The error I'm obtaining is:
SQL0104N An unexpected token "path 'strict $.array[*]' columns(type2" was found following "object.name', nested". Expected tokens may include: "<space>". SQLSTATE=42601
The result expected:
string | type | name | type2 | name2 |
---|---|---|---|---|
string | objecttype | objectname | main | name |
string | objecttype | objectname | othertype | othername |
If I change [*] clause for a specific index, ie. [0] works but only receive the first element in the array and throw an error if there are no elements:
select t.*
from json_table('{ "string":"string", "array":[{"type":"main","name":"name"},{"type":"othertype","name":"othername"}],"object":{"type":"objecttype","name":"objectname"}}' FORMAT JSON,
'strict $' columns (
string varchar(20) path 'strict $.string',
type varchar(20) path 'strict $.object.type',
name varchar(20) path 'strict $.object.name',
nested path 'strict $.array[1]' columns(
type2 varchar(20) path 'strict $.type',
name2 varchar(20) path 'strict $.name'
)
) error on error
) as t where true;
string | type | name | type2 | name2 |
---|---|---|---|---|
string | objecttype | objectname | main | name |
Also, if I remove the array specification from the SQL sentence, it doesn't throw any error but obviously, I don't have the data I need:
select t.*
from json_table('{ "string":"string", "array":[{"type":"main","name":"name"},{"type":"othertype","name":"othername"}],"object":{"type":"objecttype","name":"objectname"}}' FORMAT JSON,
'strict $' columns (
string varchar(20) path 'strict $.string',
type varchar(20) path 'strict $.object.type',
name varchar(20) path 'strict $.object.name'
) error on error
) as t where true;
Result obtained:
string | type | name |
---|---|---|
string | objecttype | objectname |
NOTE: I also checked with SYSTOOLS.JSON_TABLE but it doesn't work as I wanted, and also need a BSON as the main source instead of a string, and I don't want to make conversions each time I need to look inside.
NOTE2: Also, when I tried to put "null on error" instead of "error on error" (to return null values instead of errors) I received an error. The same happens when I change "strict" clause with "lax".
英文:
I have a table where I allocated a JSON document as string inside a CLOB field. Inside that JSON, there is an array that I need to expose as a table to can join in a SQL sentence.
Let me explain with an example: in the JSON below, I need to convert the array on a table of two cols (type and main) and two rows (same length of array) to can join with another table.field.
Example JSON
{
"string":"string",
"array":[{
"type":"main",
"name":"name"
},{
"type":"othertype",
"name":"othername"
}],
"object":{
"type":"objecttype",
"name":"objectname"
}
}
I read the official documentation and found that I can do that with JSON_TABLE function. The documentation have 2 different JSON_TABLE, one on built-in functions, SYSIBM package and the other one on SYSTOOLS package that seems to will be deprecated in future.
With SYSIBM.JSON_TABLE function I can extract from the JSON field properties such as string or string inside objects, but I can't extract the array as table rows (my main goal).
Here is the SQL sentence I'm trying to do (I put the json as parameter to check but the final destination is on a table.field):
select t.*
from json_table('{"string":"string","array":[{"type":"main","name":"name"},{"type":"othertype","name":"othername"}],"object":{"type":"objecttype","name":"objectname"}}' FORMAT JSON,
'strict $' columns (
string varchar(20) path 'strict $.string',
type varchar(20) path 'strict $.object.type',
name varchar(20) path 'strict $.object.name',
nested path 'strict $.array[*]' columns(
type2 varchar(20) path 'strict $.type',
name2 varchar(20) path 'strict $.name'
)
) error on error
) as t where true;
The error I'm obtaining is:
SQL0104N An unexpected token "path 'strict $.array[*]' columns(type2" was found following "object.name', nested". Expected tokens may include:"<space>". SQLSTATE=42601
The result expected:
string | type | name | type2 | name2 |
---|---|---|---|---|
string | objecttype | objectname | main | name |
string | objecttype | objectname | othertype | othername |
If I change [*] clause for a specific index, ie. [0] works but only receive the first element in the array and throw an error if there is no elements:
select t.*
from json_table('{"string":"string","array":[{"type":"main","name":"name"},{"type":"othertype","name":"othername"}],"object":{"type":"objecttype","name":"objectname"}}' FORMAT JSON,
'strict $' columns (
string varchar(20) path 'strict $.string',
type varchar(20) path 'strict $.object.type',
name varchar(20) path 'strict $.object.name',
nested path 'strict $.array[1]' columns(
type2 varchar(20) path 'strict $.type',
name2 varchar(20) path 'strict $.name'
)
) error on error
) as t where true;
string | type | name | type2 | name2 |
---|---|---|---|---|
string | objecttype | objectname | main | name |
Also, if I remove the array specification from the SQL sentence it doesn't throw any error but obviously, I don't have the data I need:
select t.*
from json_table('{"string":"string","array":[{"type":"main","name":"name"},{"type":"othertype","name":"othername"}],"object":{"type":"objecttype","name":"objectname"}}' FORMAT JSON,
'strict $' columns (
string varchar(20) path 'strict $.string',
type varchar(20) path 'strict $.object.type',
name varchar(20) path 'strict $.object.name'
) error on error
) as t where true;
Result obtained:
string | type | name |
---|---|---|
string | objecttype | objectname |
NOTE: I also checked with SYSTOOLS.JSON_TABLE but it doesn't work as I wanted, and also need a BSON as main source instead of string and I don't want to make conversions each time I need to look inside.
NOTE2: Also, when I tried to put null on error instead of error on error (to return null values instead of errors) I received an error. The same happens when I change strict clause with lax.
答案1
得分: 0
Db2 for LUW(包括当前版本11.5.8.0)不支持nested path
表达式。可以查看通用函数的解决方案,在这里描述。在你的情况下:
WITH TAB (DOC) AS
(
VALUES
(
'{
"string":"string",
"array":[{
"type":"main",
"name":"name"
},{
"type":"othertype",
"name":"othername"
}],
"object":{
"type":"objecttype",
"name":"objectname"
}
}'
)
)
SELECT D.*, IT.*
FROM
TAB T
, TABLE (UNNEST_JSON (T.DOC, '$.array')) A
-- array element to row
, JSON_TABLE
(
A.ITEM, 'strict $' COLUMNS
(
TYPE2 VARCHAR(20) PATH '$.type'
, NAME2 VARCHAR(20) PATH '$.name'
) ERROR ON ERROR
) IT
-- other elements of original JSON to row
, JSON_TABLE
(
T.DOC, 'strict $' COLUMNS
(
STRING VARCHAR (20) PATH '$.string'
, TYPE VARCHAR (20) PATH '$.object.type'
, NAME VARCHAR (20) PATH '$.object.name'
) ERROR ON ERROR
) D
结果为:
STRING | TYPE | NAME | TYPE2 | NAME2 |
---|---|---|---|---|
string | objecttype | objectname | main | name |
string | objecttype | objectname | othertype | othername |
英文:
Db2 for LUW (including current v11.5.8.0) doesn't support the nested path
expression.
Look at the solution with a generic function described here.
In your case:
WITH TAB (DOC) AS
(
VALUES
(
'{
"string":"string",
"array":[{
"type":"main",
"name":"name"
},{
"type":"othertype",
"name":"othername"
}],
"object":{
"type":"objecttype",
"name":"objectname"
}
}'
)
)
SELECT D.*, IT.*
FROM
TAB T
, TABLE (UNNEST_JSON (T.DOC, '$.array')) A
-- array element to row
, JSON_TABLE
(
A.ITEM, 'strict $' COLUMNS
(
TYPE2 VARCHAR(20) PATH '$.type'
, NAME2 VARCHAR(20) PATH '$.name'
) ERROR ON ERROR
) IT
-- other elements of original JSON to row
, JSON_TABLE
(
T.DOC, 'strict $' COLUMNS
(
STRING VARCHAR (20) PATH '$.string'
, TYPE VARCHAR (20) PATH '$.object.type'
, NAME VARCHAR (20) PATH '$.object.name'
) ERROR ON ERROR
) D
The result is:
STRING | TYPE | NAME | TYPE2 | NAME2 |
---|---|---|---|---|
string | objecttype | objectname | main | name |
string | objecttype | objectname | othertype | othername |
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论