json 如何从存储在Oracle数据库一个单元格中的KeyValuePair数据中获取基于键的值

ix0qys7i  于 2023-10-21  发布在  Oracle
关注(0)|答案(3)|浏览(217)

假设我有一张这样的table

id name             address                     Doc
1  {1:mark,2:john}  {1:Home,2:Work,3:Club}      {NI:299,Pass:A159}
2  {1:Max,2:Mo}     {1:Home}                    {NI:300011}

我想要的是写一个qurey来选择一个值从单元格的基础上的关键例如

i want the value which has key = 2 in column named(Name) where id=1

所以它应该返回

john

所以我怎么能做这样的事情,而不使用子字符串?

5cg8jx4n

5cg8jx4n1#

假设你有一个有效的json值:

CREATE TABLE mytable (
  id int,
  name  VARCHAR2 (200) ,          
  address VARCHAR2 (200),                    
  Doc VARCHAR2 (200),
  CONSTRAINT ensure_json CHECK (name IS JSON)
);

insert into mytable 
select 1,  '{"1":"mark","2":"john"}', '{"1":"Home","2":"Work","3":"Club"}', '{"NI":299,"Pass":"A159"}' from dual union all
select 2,  '{"1":"Max","2":"Mo"}', '{"1":"Home"}', '{"NI":300011}' from dual

查询可以是:

select t.name."2"
from mytable t
where id = 1

Demo here
如果在一个无效的JSON中只有键值,那么:

with cte as (
  select REGEXP_REPLACE(name,
                 '([a-zA-Z0-9-]+):([a-zA-Z0-9-]+)',
                 '"\1":"\2"') as name
  from mytable t
  where id = 1
)
select json_value(name, '$."2"')
from cte

Demo here

vqlkdk9b

vqlkdk9b2#

您的name列不是有效的JSON,因此无法使用JSON函数。
你可以使用正则表达式,但它们比简单的字符串函数慢。所以,即使你说你不想使用SUBSTR,你应该使用SUBSTR

SELECT id,
       CASE
       WHEN spos > 0 AND epos > 0
       THEN SUBSTR(name, spos + 3, epos - spos - 3)
       END AS name2
FROM   (
  SELECT id,
         name,
         INSTR(TRANSLATE(name, '{}', ',,'), ',2:', 1) AS spos,
         INSTR(
           TRANSLATE(name, '{}', ',,'),
           ',',
           INSTR(TRANSLATE(name, '{}', ',,'), ',2:', 1, 1) + 3
         ) AS epos
  FROM   table_name
)

其中,对于样本数据:

CREATE TABLE table_name (id, name) AS
SELECT 1, '{1:mark,2:john}' FROM DUAL UNION ALL
SELECT 2, '{1:Max,2:Mo}'    FROM DUAL;

输出:
| ID| NAME2|
| --|--|
| 1 |约翰|
| 2 |莫|
如果你只想当id = 1然后添加该过滤器,如果你想使索引匹配一个更动态的参数,那么:

SELECT CASE
       WHEN spos > 0 AND epos > 0
       THEN SUBSTR(name, spos + 3, epos - spos - 3)
       END AS name
FROM   (
  SELECT id,
         name,
         INSTR(TRANSLATE(name, '{}', ',,'), ','||index_to_match||':', 1) AS spos,
         INSTR(
           TRANSLATE(name, '{}', ',,'),
           ',',
           INSTR(TRANSLATE(name, '{}', ',,'), ','||index_to_match||':', 1, 1) + 3
         ) AS epos
  FROM   table_name
         CROSS JOIN (SELECT 2 AS index_to_match FROM DUAL)
  WHERE  id = 1
)

或者使用参数化查询和绑定参数(而不是子查询)。
fiddle

fnatzsnv

fnatzsnv3#

如果你的数据如图所示,而不是JSON(或引号),并且性能不是主要问题(如果是,那么回到substr(),如@MT0所示),那么你可以使用regexp_substr()来查找匹配,并使用一个嵌入你想要的键值的模式:

select regexp_substr(name, '({|,)' || 2 || ':(.*?)(,|})', 1, 1, null, 2) as result
from your_table
where id = 1

| 结果|
| --|
| 约翰|
您的脚本需要在第一行提供第一个2,在第三行提供1;所以更一般地使用绑定变量:

select regexp_substr(name, '({|,)' || :p_key || ':(.*?)(,|})', 1, 1, null, 2) as result
from your_table
where id = :p_id

该模式将查找{,,后跟您的键值,后跟冒号:;并将所有内容捕获到另一个,}。其他参数告诉它返回第二个捕获组(该行中的第二个2)。第一个组是({|,)的“或”,而第二个组(.*?)是该对的值。
通过改变键值,你会得到不同的结果;使用相同的列和1

select regexp_substr(name, '({|,)' || 1 || ':(.*?)(,|})', 1, 1, null, 2) as result
from your_table
where id = 1

| 结果|
| --|
| 马克|
您可以对其他键/值列使用相同的方法。
fiddle
当然,最好是以关系的方式存储数据,而不是将数据存储为字符串列中的键/值对。

相关问题