无法在DB2 v11.5上使用JSON_TABLE从JSON中提取数组。

huangapple go评论54阅读模式
英文:

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

{
	&quot;string&quot;:&quot;string&quot;,
	&quot;array&quot;:[{
		&quot;type&quot;:&quot;main&quot;,
		&quot;name&quot;:&quot;name&quot;
	},{
		&quot;type&quot;:&quot;othertype&quot;,
		&quot;name&quot;:&quot;othername&quot;
	}],
	&quot;object&quot;:{
		&quot;type&quot;:&quot;objecttype&quot;,
		&quot;name&quot;:&quot;objectname&quot;
	}
}

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(&#39;{&quot;string&quot;:&quot;string&quot;,&quot;array&quot;:[{&quot;type&quot;:&quot;main&quot;,&quot;name&quot;:&quot;name&quot;},{&quot;type&quot;:&quot;othertype&quot;,&quot;name&quot;:&quot;othername&quot;}],&quot;object&quot;:{&quot;type&quot;:&quot;objecttype&quot;,&quot;name&quot;:&quot;objectname&quot;}}&#39; FORMAT JSON, 
    &#39;strict $&#39; columns (
        string varchar(20) path &#39;strict $.string&#39;,
        type varchar(20) path &#39;strict $.object.type&#39;,
        name varchar(20) path &#39;strict $.object.name&#39;,
        nested path &#39;strict $.array[*]&#39; columns(
            type2 varchar(20) path &#39;strict $.type&#39;,
            name2 varchar(20) path &#39;strict $.name&#39;
        )
    ) error on error
) as t where true;

The error I'm obtaining is:

SQL0104N An unexpected token &quot;path &#39;strict $.array[*]&#39; columns(type2&quot; was found following &quot;object.name&#39;, nested&quot;. Expected tokens may include:&quot;&lt;space&gt;&quot;. 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(&#39;{&quot;string&quot;:&quot;string&quot;,&quot;array&quot;:[{&quot;type&quot;:&quot;main&quot;,&quot;name&quot;:&quot;name&quot;},{&quot;type&quot;:&quot;othertype&quot;,&quot;name&quot;:&quot;othername&quot;}],&quot;object&quot;:{&quot;type&quot;:&quot;objecttype&quot;,&quot;name&quot;:&quot;objectname&quot;}}&#39; FORMAT JSON, 
    &#39;strict $&#39; columns (
        string varchar(20) path &#39;strict $.string&#39;,
        type varchar(20) path &#39;strict $.object.type&#39;,
        name varchar(20) path &#39;strict $.object.name&#39;,
        nested path &#39;strict $.array[1]&#39; columns(
            type2 varchar(20) path &#39;strict $.type&#39;,
            name2 varchar(20) path &#39;strict $.name&#39;
        )
    ) 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(&#39;{&quot;string&quot;:&quot;string&quot;,&quot;array&quot;:[{&quot;type&quot;:&quot;main&quot;,&quot;name&quot;:&quot;name&quot;},{&quot;type&quot;:&quot;othertype&quot;,&quot;name&quot;:&quot;othername&quot;}],&quot;object&quot;:{&quot;type&quot;:&quot;objecttype&quot;,&quot;name&quot;:&quot;objectname&quot;}}&#39; FORMAT JSON, 
    &#39;strict $&#39; columns (
        string varchar(20) path &#39;strict $.string&#39;,
        type varchar(20) path &#39;strict $.object.type&#39;,
        name varchar(20) path &#39;strict $.object.name&#39;
    ) 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
(
&#39;{
    &quot;string&quot;:&quot;string&quot;,
    &quot;array&quot;:[{
        &quot;type&quot;:&quot;main&quot;,
        &quot;name&quot;:&quot;name&quot;
    },{
        &quot;type&quot;:&quot;othertype&quot;,
        &quot;name&quot;:&quot;othername&quot;
    }],
    &quot;object&quot;:{
        &quot;type&quot;:&quot;objecttype&quot;,
        &quot;name&quot;:&quot;objectname&quot;
    }
}&#39;
)
)
SELECT D.*, IT.* 
FROM 
  TAB T
, TABLE (UNNEST_JSON (T.DOC, &#39;$.array&#39;)) A
-- array element to row
, JSON_TABLE
  (
    A.ITEM, &#39;strict $&#39; COLUMNS
    (
        TYPE2 VARCHAR(20) PATH &#39;$.type&#39;
      , NAME2 VARCHAR(20) PATH &#39;$.name&#39; 
    ) ERROR ON ERROR
  ) IT
-- other elements of original JSON to row
, JSON_TABLE
  (
    T.DOC, &#39;strict $&#39; COLUMNS
    (
        STRING VARCHAR (20) PATH &#39;$.string&#39;
      , TYPE   VARCHAR (20) PATH &#39;$.object.type&#39;
      , NAME   VARCHAR (20) PATH &#39;$.object.name&#39;
    ) ERROR ON ERROR
  ) D

The result is:

STRING TYPE NAME TYPE2 NAME2
string objecttype objectname main name
string objecttype objectname othertype othername

huangapple
  • 本文由 发表于 2023年6月15日 16:57:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/76480819.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定