解析 PL/SQL 中的 JSON 字段的最有效方法是什么?
What is the most efficient way to parse JSON fields in PL/SQL?
想象一下 table my_table
的行数:
COLUMN_1
COLUMN_2
COLUMN_3
"test_1212"
{date: 1646240118, name: "John", age: null}
"test_2311"
"test_998"
null
"test_26351"
"test_56551"
{age: 20}
"test_3323"
此处COLUMN_2
为JSON
或null
。 JSON 字段可以有值,可以是 null
,也可以不存在。
我正在编写一个查询来解压 JSON 字段 如果它存在并且有一个值 。下面是我所拥有的,我很好奇是否有多个 case 语句会影响性能,是否有更好的方法来做到这一点?
请注意,以上只是一个示例,实际 JSON 最多可以有 10 个字段。如果可以提高性能,我可以选择在代码端解压 JSON 而不是 SQL。
SELECT COLUMN_1,
CASE WHEN json_value(COLUMN_2, '$.date') IS NOT NULL THEN json_value(COLUMN_2, '$.date')
END AS date,
CASE WHEN json_value(COLUMN_2, '$.name') IS NOT NULL THEN json_value(COLUMN_2, '$.name')
END AS name,
CASE WHEN json_value(COLUMN_2, '$.age') IS NOT NULL THEN json_value(COLUMN_2, '$.age')
END AS age,
COLUMN_3
FROM my_table
我正在使用 Oracle 版本 12.2.0.1.0 (12c)。
可以使用JSON_TABLE解析字段值-
SQL> with data_cte (col1, col2, col3) as
2 (
3 select 'COLUMN_1',json_object('date' value 1646240118, 'name' value 'John', 'age' value null), 'COLUMN_3' from dual union all
4 select 'COLUMN_1', null, 'COLUMN_3' from dual union all
5 select 'COLUMN_1', json_object('date' value null, 'name' value 'Tom', 'age' value 20), 'COLUMN_3' from dual
6 )select col1, t.*, col3 from data_cte, json_table(col2,'$'
7 columns (
8 date_1 varchar2(10) path '$.date',
9 name varchar2(21) path '$.name',
10 age varchar2(10) path '$.age')
11 ) t;
COL1 DATE_1 NAME AGE COL3
-------- ------------ ---------- ---------- --------
COLUMN_1 1646240118 John COLUMN_3
COLUMN_1 Tom 20 COLUMN_3
您可以将 JSON_TABLE
与 OUTER APPLY
一起使用:
SELECT column_1,
column_3,
j.*
FROM my_table m
OUTER APPLY JSON_TABLE(
m.column_2,
'$'
COLUMNS (
dt NUMBER PATH '$.date',
name VARCHAR2(50) PATH '$.name',
age NUMBER PATH '$.age'
)
) j;
或者,如果您更喜欢使用 ANSI 标准 LATERAL
连接而不是专有的 OUTER APPLY
那么:
SELECT column_1,
column_3,
j.*
FROM my_table m
LEFT OUTER JOIN LATERAL (
SELECT *
FROM JSON_TABLE(
m.column_2,
'$'
COLUMNS (
dt NUMBER PATH '$.date',
name VARCHAR2(50) PATH '$.name',
age NUMBER PATH '$.age'
)
)
) j
ON (1 = 1);
其中,对于示例数据:
CREATE TABLE my_table (COLUMN_1, COLUMN_2, COLUMN_3) AS
SELECT 'test_1212', '{date: 1646240118, name: "John", age: null}', 'test_2311' FROM DUAL UNION ALL
SELECT 'test_998', null, 'test_26351' FROM DUAL UNION ALL
SELECT 'test_56551', '{age: 20}', 'test_3323' FROM DUAL;
双输出:
COLUMN_1
COLUMN_3
DT
NAME
AGE
test_1212
test_2311
1646240118
John
null
test_998
test_26351
null
null
null
test_56551
test_3323
null
null
20
db<>fiddle here
想象一下 table my_table
的行数:
COLUMN_1 | COLUMN_2 | COLUMN_3 |
---|---|---|
"test_1212" | {date: 1646240118, name: "John", age: null} | "test_2311" |
"test_998" | null | "test_26351" |
"test_56551" | {age: 20} | "test_3323" |
此处COLUMN_2
为JSON
或null
。 JSON 字段可以有值,可以是 null
,也可以不存在。
我正在编写一个查询来解压 JSON 字段 如果它存在并且有一个值 。下面是我所拥有的,我很好奇是否有多个 case 语句会影响性能,是否有更好的方法来做到这一点?
请注意,以上只是一个示例,实际 JSON 最多可以有 10 个字段。如果可以提高性能,我可以选择在代码端解压 JSON 而不是 SQL。
SELECT COLUMN_1,
CASE WHEN json_value(COLUMN_2, '$.date') IS NOT NULL THEN json_value(COLUMN_2, '$.date')
END AS date,
CASE WHEN json_value(COLUMN_2, '$.name') IS NOT NULL THEN json_value(COLUMN_2, '$.name')
END AS name,
CASE WHEN json_value(COLUMN_2, '$.age') IS NOT NULL THEN json_value(COLUMN_2, '$.age')
END AS age,
COLUMN_3
FROM my_table
我正在使用 Oracle 版本 12.2.0.1.0 (12c)。
可以使用JSON_TABLE解析字段值-
SQL> with data_cte (col1, col2, col3) as
2 (
3 select 'COLUMN_1',json_object('date' value 1646240118, 'name' value 'John', 'age' value null), 'COLUMN_3' from dual union all
4 select 'COLUMN_1', null, 'COLUMN_3' from dual union all
5 select 'COLUMN_1', json_object('date' value null, 'name' value 'Tom', 'age' value 20), 'COLUMN_3' from dual
6 )select col1, t.*, col3 from data_cte, json_table(col2,'$'
7 columns (
8 date_1 varchar2(10) path '$.date',
9 name varchar2(21) path '$.name',
10 age varchar2(10) path '$.age')
11 ) t;
COL1 DATE_1 NAME AGE COL3
-------- ------------ ---------- ---------- --------
COLUMN_1 1646240118 John COLUMN_3
COLUMN_1 Tom 20 COLUMN_3
您可以将 JSON_TABLE
与 OUTER APPLY
一起使用:
SELECT column_1,
column_3,
j.*
FROM my_table m
OUTER APPLY JSON_TABLE(
m.column_2,
'$'
COLUMNS (
dt NUMBER PATH '$.date',
name VARCHAR2(50) PATH '$.name',
age NUMBER PATH '$.age'
)
) j;
或者,如果您更喜欢使用 ANSI 标准 LATERAL
连接而不是专有的 OUTER APPLY
那么:
SELECT column_1,
column_3,
j.*
FROM my_table m
LEFT OUTER JOIN LATERAL (
SELECT *
FROM JSON_TABLE(
m.column_2,
'$'
COLUMNS (
dt NUMBER PATH '$.date',
name VARCHAR2(50) PATH '$.name',
age NUMBER PATH '$.age'
)
)
) j
ON (1 = 1);
其中,对于示例数据:
CREATE TABLE my_table (COLUMN_1, COLUMN_2, COLUMN_3) AS
SELECT 'test_1212', '{date: 1646240118, name: "John", age: null}', 'test_2311' FROM DUAL UNION ALL
SELECT 'test_998', null, 'test_26351' FROM DUAL UNION ALL
SELECT 'test_56551', '{age: 20}', 'test_3323' FROM DUAL;
双输出:
COLUMN_1 COLUMN_3 DT NAME AGE test_1212 test_2311 1646240118 John null test_998 test_26351 null null null test_56551 test_3323 null null 20
db<>fiddle here