首先要说明的是,本文的主要以案例为主,具体函数的说明可以查看oracle官方文档,虽然是19c,但是这里参考了oracle 21c的说明
主要为两个模块
-
环境准备
数据库:oracle 19c
创建一张表
CREATE TABLE "MY_JSON_TABLE" (
"ID" NUMBER VISIBLE NOT NULL,
"CODE" VARCHAR2(255 BYTE) VISIBLE,
"NAME" VARCHAR2(255 BYTE) VISIBLE,
"JDATA" CLOB VISIBLE
) ;
初始化数据,这里插入了10W
BEGIN
FOR i IN 1..100000 LOOP
INSERT INTO "MY_JSON_TABLE"(ID, CODE, NAME, JDATA) VALUES (i, 'MJ-CD-'||i, '测试'||1, '{
"name":"龙傲天",
"age":18,
"phone":[ "15088888888", "13966666666","0571-88888888"],
"id":"333333199911114567",
"eamil":"113@126.com",
"work":[
{
"company":"快乐无限",
"post":"销售经理",
"address":"杭州一号大街"
},
{
"company":"高兴上班",
"post":"售前总监",
"address":"浙江杭州滨江"
},
{
"company":"没班上",
"post":"务农",
"address":"浙江杭州富阳"
}
]
}');
END LOOP;
COMMIT;
END;
/
-
函数
JSON路径表达式通配符
在查询开始之前,我们先来看下通配符的说明,后续查询条件及各种操作时,都会用到JSON PATH
通配符 | 说明 |
$ | 表示根元素 |
. | 表示当前元素 |
[*] | 表示匹配数组中的所有元素 |
[] | 表示过滤数组中符合条件的元素 |
@ | 表示当前元素的属性 |
-
-
JSON_OBJECT
-
JSON_OBJECT接受一系列键-值对或一个对象类型实例作为输入,返回一个JSON类型的对象。集合类型不能传递给JSON_OBJECT。
将MY_JSON_TABLE表中的CODE,NAME字段组合成一个JSON字符串
SELECT
JSON_OBJECT(CODE,NAME)
FROM MY_JSON_TABLE
WHERE id = 1;
查询结果字段都转成json格式
select JSON_OBJECT(*) from "flyway_schema_history";
可以更换字段名称,key关键字可以省略
SELECT
JSON_OBJECT(
key 'CODE1' VALUE CODE,
key 'NAME1' VALUE NAME
)
FROM MY_JSON_TABLE
WHERE id = 1;
可以和JSON_ARRAY一起使用,将多行结果转成一个json数组,JSON_ARRAY后面章节中有讲到
SELECT
JSON_ARRAYAGG(
JSON_OBJECT(
key 'CODE1' VALUE CODE,
key 'NAME1' VALUE NAME
)
)
FROM MY_JSON_TABLE
WHERE rownum < 5;
NULL ON NULL和ABSENT ON NULL,可以选择保留或者忽略nul值。缺省是 NULL ON NULL
SELECT
JSON_ARRAYAGG(
JSON_OBJECT(
key 'CODE1' VALUE CODE,
key 'NAME1' VALUE null NULL ON NULL
)
)
FROM MY_JSON_TABLE
WHERE rownum < 5;
SELECT
JSON_ARRAYAGG(
JSON_OBJECT(
key 'CODE1' VALUE CODE,
key 'NAME1' VALUE null ABSENT ON NULL
)
)
FROM MY_JSON_TABLE
WHERE rownum < 5;
STRICT关键字,严格校验json,不符合会报错
SELECT JSON_OBJECT ('name' value 'Foo' FORMAT JSON ) FROM DUAL;
SELECT JSON_OBJECT ('name' value 'Foo' FORMAT JSON STRICT ) FROM DUAL;
还可以把两个字段组合在一起,一个作为key,一个作为value
SELECT JSON_OBJECT(
key CODE value NAME
)
FROM MY_JSON_TABLE
WHERE rownum < 10
ORDER BY id;
-
-
JSON_OBJECTAGG
-
JSON_OBJECTAGG是一个聚合函数。它将属性键-值对作为其输入。通常,属性键、属性值或两者都是SQL表达式的列。该函数为每个键-值对构造一个对象成员,并返回一个包含这些对象成员的JSON对象。
SELECT JSON_OBJECTAGG(
KEY CODE VALUE NAME
)
FROM MY_JSON_TABLE
WHERE rownum < 10 ;
-
-
IS JSON
-
判断字段内容是否是JSON格式
select JDATA from MY_JSON_TABLE where JDATA IS JSON and rownum < 10;
后面可以跟关键字 STRICT 和 LAX,缺省使用LAX,STRICT会严格校验JSON
select JDATA from MY_JSON_TABLE where JDATA IS JSON STRICT and rownum < 10;
也可以判断不是JSON的,且可以两者一起使用。如:是JSON,但不是严格的JSON
{ "Grade Values" : { A : 4.0, B : 3.0, C : 2.0 } }
select JDATA from MY_JSON_TABLE where JDATA IS NOT JSON STRICT and JDATA IS JSON LAX AND rownum < 10;
还可以使用WITH UNIQUE KEYS 过滤JSON中有重复字段的数据, 缺省其实是WITHOUT UNIQUE KEYS 。当然如果后面有STRICT关键字也是一样的,重复字段也是不允许的
{a:100, a:200, b:300}
select count(1) from MY_JSON_TABLE where JDATA IS JSON WITH UNIQUE KEYS ;
-
-
JSON_EXISTS
-
判断符合条件的JSON
判断JSON中是否存在字段
SELECT count(1) FROM MY_JSON_TABLE WHERE JSON_EXISTS(JDATA, '$.name');
如果是JSON ARRAY,则可以加 [0] -取第一个对象,[*]-任意对象
SELECT JDATA FROM MY_JSON_TABLE WHERE JSON_EXISTS(JDATA, '$[0].first');
如果需要把不是JSON的一起查询出来,则需要加关键字 TRUE ON ERROR
SELECT JDATA FROM MY_JSON_TABLE WHERE JSON_EXISTS(JDATA, '$[*].first' TRUE ON ERROR );
上述只是判断字段是否存在,并不能判断具体值,下面开始说明值查询
相等
SELECT * FROM MY_JSON_TABLE WHERE JSON_EXISTS(JDATA, '$?(@.name == "龙傲天")');
SELECT * FROM MY_JSON_TABLE WHERE JSON_EXISTS(JDATA, '$[*]?(@.name == "龙傲天")');
全等还有另外一种写法,可以把参数提取出来,var1就是提取出来的字段名,但是如果条件多的情况下就不是很好处理
SELECT * FROM MY_JSON_TABLE WHERE JSON_EXISTS(JDATA, '$[*]?(@.name == $var1)' PASSING '龙傲天' as "var1");
不相等
SELECT * FROM MY_JSON_TABLE WHERE JSON_EXISTS(JDATA, '$?(@.age <> 18)' );
SELECT * FROM MY_JSON_TABLE WHERE JSON_EXISTS(JDATA, '$?(@.age != 18)' );
模糊查询
模糊查询我们要用到like,这与普通模糊查询是一样。
SELECT * FROM MY_JSON_TABLE WHERE JSON_EXISTS(JDATA, '$[*]?(@.name like "龙%")');
与全等一样,参数也可以提取出来,后面就不再举例
SELECT * FROM MY_JSON_TABLE WHERE JSON_EXISTS(JDATA, '$[*]?(@.name like $var2)' PASSING '龙%' as "var2");
not like就有区别了,不支持直接加not,我们这里要用到exists和 !exists
SELECT JSON_QUERY(JDATA, '$') FROM MY_JSON_TABLE WHERE JSON_EXISTS(JDATA, '$[*]?(!exists (@.name? (@ like "龙%")))');
在列表中-in与not in
通过前面几个案例,后的我们都可以举一反三了
SELECT * FROM MY_JSON_TABLE WHERE JSON_EXISTS(JDATA, '$[*]?(@.age in (18,19))');
not in 也一样,不支持直接加not ,这里利用 !exists
SELECT JSON_QUERY(JDATA, '$') FROM MY_JSON_TABLE WHERE JSON_EXISTS(JDATA, '$[*]?(!exists (@.age?(@ in ("10","18","20"))))');
空字符串
SELECT * FROM MY_JSON_TABLE WHERE JSON_EXISTS(JDATA, '$[*]?(@.middle == "")' );
null与not null
这里的查询条件更像是java代码中的判断,与以往的 is null 不同
SELECT * FROM MY_JSON_TABLE WHERE JSON_EXISTS(JDATA, '$?(@.age == null)' );
SELECT * FROM MY_JSON_TABLE WHERE JSON_EXISTS(JDATA, '$?(@.age != null)' );
范围比较
大于
SELECT * FROM MY_JSON_TABLE WHERE JSON_EXISTS(JDATA, '$?(@.age >18)' );
小于
SELECT * FROM MY_JSON_TABLE WHERE JSON_EXISTS(JDATA, '$?(@.age < 18)' );
条件组合,需要用到&& 和 ||,这里与java中的符号一样,与通用sql区别。另外,BETWEEN...AND这里用不了(或者说我没找对方法)
SELECT * FROM MY_JSON_TABLE WHERE JSON_EXISTS(JDATA, '$?(@.age < 30 && @.age > 18 )' ) ;
组合查询
用&& 或 ||连接,&&与逻辑,||表示或逻辑。
SELECT * FROM MY_JSON_TABLE WHERE JSON_EXISTS(JDATA, '$[*]?(@.age in (10, 15,20,28) && @.name like "%傲_")') ;
复杂查询
准备模拟数据
{
"name":"龙傲天",
"age":10,
"phone":[ "15088888888", "13966666666","0571-88888888"],
"id":"333333199911114567",
"eamil":"113@126.com",
"work":[
{
"company":"快乐无限",
"post":"销售经理",
"address":"杭州一号大街"
},
{
"company":"高兴上班",
"post":"售前总监",
"address":"上海"
},
{
"company":"没班上",
"post":"务农",
"address":"浙江杭州富阳"
}
]
}
sql说明:查询work数组中,第二个元素对象address包含上海的数据。[1]表示取第二个数据,下标从0开始。如果不区分下标可以是[*]
SELECT * FROM MY_JSON_TABLE WHERE JSON_EXISTS(JDATA, '$[*]?(@.age in (10, 15,20,28) && @.name like "%傲_" && @.work[1].address like "%上海%")') ;
如果不区分数组的元素,以下两个sql同等效果
SELECT * FROM MY_JSON_TABLE WHERE JSON_EXISTS(JDATA, '$[*]?(@.age in (10, 15,20,28) && @.name like "%傲_" && @.work[*].address like "%上海%")') ;
SELECT * FROM MY_JSON_TABLE WHERE JSON_EXISTS(JDATA, '$[*]?(@.age in (10, 15,20,28) && @.name like "%傲_" && @.work.address like "%上海%")') ;
我们还可以用exists关键字,注意这里exists不能大写,否则会报错
SELECT JDATA FROM MY_JSON_TABLE where JSON_EXISTS(JDATA, '$?(@.age == 10 && exists (@.work[*]?(@.address == "上海")) )') ;
当然如果只是单纯的查询work第2个元素中address包含上海的,还可以这样
SELECT * FROM MY_JSON_TABLE WHERE JSON_EXISTS(JDATA, '$.work[1]?(@.address like "%上海%")') ;
-
-
JSON_TEXTCONTAINS
-
使用JSON_TEXTCONTAINS需要先创建索引
CREATE INDEX ix_json_data
ON MY_JSON_TABLE(JDATA)
INDEXTYPE IS CTXSYS.CONTEXT
PARAMETERS ('SECTION GROUP CTXSYS.JSON_SECTION_GROUP SYNC (ON COMMIT)');
也可以用于查询
SELECT JSON_QUERY(JDATA ,'$') FROM MY_JSON_TABLE WHERE JSON_TEXTCONTAINS(JDATA, '$.name', '龙傲天') AND ROWNUM < 10;
能查询数组对象里面的字段
SELECT JSON_QUERY(JDATA ,'$') FROM MY_JSON_TABLE WHERE JSON_TEXTCONTAINS(JDATA, '$.work', '杭州一号大街') AND ROWNUM < 10;
能查询按空格分割的数据
SELECT JSON_QUERY(JDATA ,'$') FROM MY_JSON_TABLE WHERE JSON_TEXTCONTAINS(JDATA, '$.work', '杭州一号') AND ROWNUM < 10;
-
-
JSON_TABLE
-
JSON_TABLE可以将json中的字段转换成普通数据库字段,然后作为条件查询
这里只做演示,详细讲解可以参考其他章节
演示1
查询age=10的数据
SELECT JDATA FROM MY_JSON_TABLE, JSON_TABLE(JDATA, '$' COLUMNS ("MY_AGE" NUMBER PATH '$.age')) AS t WHERE t.MY_AGE = 10;
演示2
查询存在age字段的数据,
SELECT HAS_AGE
FROM MY_JSON_TABLE,
JSON_TABLE(JDATA, '$'
COLUMNS ("HAS_AGE" NUMBER EXISTS PATH '$.age')) AS jt
WHERE jt.HAS_AGE = 1;
演示3
查询age=10,name='龙傲天'的数据
SELECT JDATA
FROM MY_JSON_TABLE, JSON_TABLE(JDATA, '$'
COLUMNS (
"MY_AGE" NUMBER PATH '$.age',
"NAME" VARCHAR2 PATH '$.name'
)) AS t WHERE t.MY_AGE = 10 and t.NAME = '龙傲天';
也允许单独使用,但是实际意义不大。我们可以看下
SELECT *
FROM JSON_TABLE(
'{"id": 100, "name": "John", "age": 25, "email": "john@example.com"}',
'$'
COLUMNS (
id NUMBER PATH '$.id',
name VARCHAR2(50) PATH '$.name',
age NUMBER PATH '$.age',
email VARCHAR2(100) PATH '$.email'
)
);
复杂结构,可以使用NESTED PATH嵌套
select ID,t.* from MY_JSON_TABLE
, JSON_TABLE(
JDATA, '$'
COLUMNS (
"NAME" VARCHAR2 PATH '$.name',
"AGE" NUMBER PATH '$.age',
NESTED PATH '$.work[*]'
COLUMNS (
"COMPANY" VARCHAR2(32) PATH '$.company',
"ADDRESS" VARCHAR2(20) PATH '$.address'
)
)
) AS t WHERE t.AGE = 18 AND t.NAME = '龙傲天' AND rownum < 10;
-
-
JSON_ARRAY
-
以下示例从JSON对象、JSON数组、数字文字、文本文字和null构造JSON数组:
VARCHAR2 指定大小为字节数或字符数。 默认是字节。如果省略了这个子句,或者在没有指定 size 值的情况下指定了这个子句,那么 JSON_ARRAY 将返回一个 VARCHAR2(4000) 类型的字符串。
CLOB 返回一个包含单字节或多字节字符的字符大对象。
BLOB 返回一个二进制大对象的 AL32UTF8 字符集。
SELECT JSON_ARRAY (
JSON_OBJECT('percentage' VALUE .50),
JSON_ARRAY(1,2,3),
100,
'California',
null
NULL ON NULL
) "JSON Array Example"
FROM DUAL;
可以添加STRICT关键字
SELECT JSON_ARRAY (
JSON_OBJECT('percentage' VALUE .50),
JSON_ARRAY(1,2,3),
100,
'California',
null
NULL ON NULL
STRICT ) "JSON Array Example"
FROM DUAL;
关键ABSENT ON NULL(忽略null) 或者 NULL ON NULL (保留null),前面已经保留了null,我们再来看下忽略的情况
SELECT JSON_ARRAY (
JSON_OBJECT('percentage' VALUE .50),
JSON_ARRAY(1,2,3),
100,
'California',
null ABSENT ON NULL
) "JSON Array Example"
FROM DUAL;
-
-
JSON_ARRAYAGG
-
SELECT
JSON_ARRAYAGG ( ID ORDER BY ID RETURNING VARCHAR2(100) ) ID
FROM
MY_JSON_TABLE
WHERE
ROWNUM < 10;
添加STRICT关键字,验证 JSON 生成函数的输出是正确的 JSON 。如果检查失败,将引发语法错误。
SELECT
JSON_ARRAYAGG ( ID ORDER BY ID RETURNING VARCHAR2(100) STRICT) ID
FROM
MY_JSON_TABLE
WHERE
ROWNUM < 10;
-
-
JSON_DATAGUIDE
-
聚合函数JSON_DATAGUIDE接受JSON数据的表列作为输入,并将数据指南作为CLOB返回。列中的每一行都被称为一个JSON文档。对于列中的每个JSON文档,该函数返回一个CLOB值,其中包含该JSON文档的平面数据指南。
意思就是返回一个JSON文档的说明,包括json path, 类型,长度。
SELECT
id, JSON_DATAGUIDE(JDATA) DATAGUIDE
FROM MY_JSON_TABLE where rownum < 2 group by id
-
-
JSON_QUERY
-
从JSON数据中选择并返回一个或多个值,然后返回这些值。可以使用JSON_QUERY检索JSON文档的片段。
这个函数有一个神奇的用处,如果存储JSON字符串的的字段是CLOB或者BLOB类型,查询往往比较耗时。此时如果使用JSON_QUERY,可以减少消耗。
SELECT JSON_QUERY(JDATA, '$') FROM MY_JSON_TABLE where ROWNUM < 100;
只返回100条,都已经不是一个量级的了
WRAPPER关键字,可以将结果包裹成数组,不管本身结果是不是数组都会包裹。
SELECT JSON_QUERY('{a:100, b:200, c:300}', '$.a' WITH WRAPPER) AS value FROM DUAL;
结果包裹成数组
SELECT JSON_QUERY('{a:100, b:200, c:300}', '$.*' WITH WRAPPER) AS value FROM DUAL;
获取数组中的全部元素,并包裹成数组,下面两个语句是等价的
SELECT JSON_QUERY('[0,1,2,3,4]', '$' ) AS value FROM DUAL;
SELECT JSON_QUERY('[0,1,2,3,4]', '$[*]' WITH WRAPPER) AS value FROM DUAL;
可以取数组中,几个元素
SELECT JSON_QUERY('[0,1,2,3,4,5,6,7,8]', '$[0, 3 to 5, 7]' WITH WRAPPER) AS value FROM DUAL;
CONDITIONAL关键字,可以返回一个严格的JSON格式,我们可以看到字段被加上了双引号
SELECT JSON_QUERY('[{a:100},{b:200},{c:300}]', '$[*]' WITH CONDITIONAL WRAPPER) AS value FROM DUAL;
RETURNING VARCHAR2(100),可以限制返回的JSON串长度,如果超过了长度会返回null
SELECT JSON_QUERY('[{"a":100},{"b":200},{"c":300}]', '$[*]' RETURNING VARCHAR2(100) WITH CONDITIONAL WRAPPER) AS value FROM DUAL;
其他关键字
ON ERROR
- NULL ON ERROR - 默认缺省.如果异常则返回null
- ERROR ON ERROR - 如果异常就提示异常
- EMPTY ON ERROR - 如果异常就返回一个空数组,与 EMPTY ARRAY ON ERROR相同.
- EMPTY ARRAY ON ERROR - 如果异常就返回一个空数组
- EMPTY OBJECT ON ERROR - 如果异常就返回一个空对象
ON EMPTY
- NULL ON EMPTY - 匹配不到就返回null
- ERROR ON EMPTY - 匹配不到就提示异常
- EMPTY ON EMPTY - 匹配不到就返回空数组,参考 EMPTY ARRAY ON EMPTY.
- EMPTY ARRAY ON EMPTY - 匹配不到就返回空数组
- EMPTY OBJECT ON EMPTY - 匹配不到就返回一个空对象
可以组合使用
SELECT JSON_QUERY('[{"a":100},{"b":200},{"c":300}]', '$[3]' EMPTY ON ERROR NULL ON EMPTY) AS value FROM DUAL;
-
-
JSON_MERGEPATCH
-
JSON_MERGEPATCH可以用于更新json字符串,也可以增加字段,删除字段,这样引申出可以修改字段名称。
如果A字段存在则修改值为对应值,如果不存在则添加A字段,可以多个字段一起修改,如果A字段设置的值为null,则会把A字段删除
修改数据
UPDATE MY_JSON_TABLE set JDATA = JSON_MERGEPATCH(JDATA, '{"name":"聂风"}') where ID = 14;
select JSON_QUERY(JDATA, '$') from MY_JSON_TABLE where ID = 14;
可以多个字段一起修改
UPDATE MY_JSON_TABLE set JDATA = JSON_MERGEPATCH(JDATA, '{"name":"聂风","age":55}') where ID = 14;
select JSON_QUERY(JDATA, '$') from MY_JSON_TABLE where ID = 14;
新增字段
只要字段不存在就自动加上了,如ID
UPDATE MY_JSON_TABLE set JDATA = JSON_MERGEPATCH(JDATA, '{"id":"1","age":55}') where ID = 14;
select JSON_QUERY(JDATA, '$') from MY_JSON_TABLE where ID = 14;
删除字段
UPDATE MY_JSON_TABLE set JDATA = JSON_MERGEPATCH(JDATA, '{"id":null}') where ID = 14;
select JSON_QUERY(JDATA, '$') from MY_JSON_TABLE where ID = 14;
这里需要讲到一个妙用,如果返回的结果中不需要某些字段,则可以使用此方法
SELECT id, JSON_MERGEPATCH(JDATA, '{"name":null}' ) A from MY_JSON_TABLE where ROWNUM < 100;
修改字段
需要注意的是,这里只是利用了删除和新增的方式。并不适合大量修改,因为值需要额外输入。后面会讲JSON_TRANSFORM
UPDATE MY_JSON_TABLE set JDATA = JSON_MERGEPATCH(JDATA, '{"id":null,"newId":"124"}') where ID = 14;
select JSON_QUERY(JDATA, '$') from MY_JSON_TABLE where ID = 14;
-
-
JSON_SERIALIZE
-
可以序列化json串,如果是用blob类型存储的,还能将二进制数据转换成字符显示出来。
先看下blob类型的数据
插入模拟数据
INSERT INTO "MY_JSON" ("id", "JDATA") VALUES ('1', UTL_RAW.CAST_TO_RAW('{"code":"11","name":"测试"}'));
select JSON_SERIALIZE(JDATA) from MY_JSON;
可以更很多关键字,
RETURNING VARCHAR2(100)限制返回的字符串长度
PRETTY 可以格式化sql
TRUNCATE 可以截取,默认缺省,配合RETURNING使用
ERROR ON ERROR json非法时提示错误,缺省默认,且不支持EMPTY ON ERROR
select JSON_SERIALIZE(JDATA RETURNING VARCHAR2(100) PRETTY TRUNCATE ERROR ON ERROR) from MY_JSON;
-
-
JSON_TRANSFORM
-
操作 | 说明 |
REMOVE | 删除字段及值 |
INSERT | 添加字段及值 |
REPLACE | 替换字段及值 |
APPEND | 数组中追加数据 |
SET | 设置字段值 |
RENAME | 重命名字段名 |
KEEP | 保留字段,没有被保留的字段及值会被清掉。(21C好像可以跟其他关键字) |
REMOVE
UPDATE MY_JSON_TABLE SET JDATA = JSON_TRANSFORM(JDATA, REMOVE '$.name' ) where ID = 88;
IGNORE ON MISSING (default), ERROR ON MISSING
默认字段不存在不会报错,如果需要提示错误则需要加ERROR ON MISSING
UPDATE MY_JSON_TABLE SET JDATA = JSON_TRANSFORM(JDATA, REMOVE '$.name' ERROR ON MISSING ) where ID = 88;
remove还可以移除数组中的数据,配合条件使用
UPDATE MY_JSON_TABLE SET JDATA = JSON_TRANSFORM(JDATA, REMOVE '$.work[0]' ) where ID = 88;
UPDATE MY_JSON_TABLE SET JDATA = JSON_TRANSFORM(JDATA, REMOVE '$.work[*]?(@.address like "%浙江%")' ) where ID = 88;
INSERT
UPDATE MY_JSON_TABLE SET JDATA = JSON_TRANSFORM(JDATA, INSERT '$.age' = 30 ) where ID = 88;
如果字段存在了,就会提示错误,可以加上IGNORE ON EXISTING
UPDATE MY_JSON_TABLE SET JDATA = JSON_TRANSFORM(JDATA, INSERT '$.age' = 30 IGNORE ON EXISTING) where ID = 88;
支持以下操作
ERROR ON NULL会提示错误
IGNORE ON NULL 会忽略本次插入,不会动原数据
REMOVE ON NULL会把字段删掉
UPDATE MY_JSON_TABLE SET JDATA = JSON_TRANSFORM(JDATA, INSERT '$.age' = null REPLACE ON EXISTING REMOVE ON NULL) where ID = 88;
往数组中添加一个数据,与APPEND功能相同
UPDATE MY_JSON_TABLE SET JDATA = JSON_TRANSFORM(JDATA, INSERT '$.work[last+1]' = '{"company":"快乐无限","post":"销售经理","address":"浙江杭州一号大街"}' FORMAT JSON ) where ID = 88;
那么其实也可以往第一个元素插入
UPDATE MY_JSON_TABLE SET JDATA = JSON_TRANSFORM(JDATA, INSERT '$.work[0]' = '{"company":"快乐无限","post":"销售经理","address":"测试地址"}' FORMAT JSON ) where ID = 88;
REPLACE
目前测试的基本和SET一致,详细的可以看SET
下述中FORMAT JSON关键字把前面的json串当JSON对象处理,否则会当成字符串
UPDATE MY_JSON_TABLE SET JDATA = JSON_TRANSFORM(JDATA, REPLACE '$.address' = '{"street":"8 Timbly Rd.", "city":"Penobsky", "state":"UT"}' FORMAT JSON ) where ID = 88;
插入结果为
{
"phone" :
[
"15088888888",
"13966666666",
"0571-88888888"
],
"id" : "333333199911114567",
"eamil" : "113@126.com",
"work" :
[
],
"name" : "风云",
"address" :
{
"street" : "8 Timbly Rd.",
"city" : "Penobsky",
"state" : "UT"
}
}
APPEND
UPDATE MY_JSON_TABLE SET JDATA = JSON_TRANSFORM(JDATA, APPEND '$.work' = '{"company":"新公司","post":"新职位","address":"杭州"}' FORMAT JSON) where ID = 100;
{
"name" : "龙傲天",
"age" : 18,
"phone" :
[
"15088888888",
"13966666666",
"0571-88888888"
],
"id" : "333333199911114567",
"eamil" : "113@126.com",
"work" :
[
{
"company" : "快乐无限",
"post" : "销售经理",
"address" : "杭州一号大街"
},
{
"company" : "高兴上班",
"post" : "售前总监",
"address" : "浙江杭州滨江"
},
{
"company" : "没班上",
"post" : "务农",
"address" : "浙江杭州富阳"
},
{
"company" : "新公司",
"post" : "新职位",
"address" : "杭州"
}
]
}
SET
修改字段值
UPDATE MY_JSON_TABLE SET JDATA = JSON_TRANSFORM(JDATA, SET '$.age' = 6 REPLACE ON EXISTING REMOVE ON NULL) where ID = 88;
如果值是一个JSON对象,则需要添加FORMAT JSON
UPDATE MY_JSON_TABLE SET JDATA = JSON_TRANSFORM(JDATA, SET '$.address' = '{"street":"8 Timbly Rd.", "city":"Penobsky", "state":"UT"}' FORMAT JSON) where ID = 88;
SET与REPLACE的区别在于特殊情况的处理
来点高级的,可以用筛选,主要还是针对数组
UPDATE MY_JSON_TABLE SET JDATA = JSON_TRANSFORM(JDATA, SET '$.work[*]?(@.address == "杭州一号大街")' = '{"company":"快乐无限","post":"销售经理","address":"浙江杭州一号大街"}' FORMAT JSON ) where ID = 100;
原条件如果是数组,则只需要@表示
UPDATE MY_JSON_TABLE SET JDATA = JSON_TRANSFORM(JDATA, SET '$.work[*]?(@ == "浙江杭州一号大街")' = '{"company":"快乐无限","post":"销售经理","address":"浙江杭州一号大街"}' FORMAT JSON ) where ID = 88;
RENAME
UPDATE MY_JSON_TABLE set JDATA = JSON_TRANSFORM(JDATA, RENAME '$.name' ='NAME') where id = 100;
修改字段名且,保留原来的数据。如果被修改的字段名不存在,缺省情况下不会报错,可以加关键字。
再来点复杂的,把符合条件的company字段改成COMPANY字段
UPDATE MY_JSON_TABLE set JDATA = JSON_TRANSFORM(JDATA, RENAME '$.work[*]?(@.address == "测试地址").company' ='COMPANY') where id = 88;
KEEP
只保留符合条件的字段,其他字段都清除
UPDATE MY_JSON_TABLE set JDATA = JSON_TRANSFORM(JDATA, KEEP '$.work[*].company' ) where id = 188;
UPDATE MY_JSON_TABLE set JDATA = JSON_TRANSFORM(JDATA, KEEP '$.work[*]?(@.company == "快乐无限")' ) where id = 188;
-
-
JSON_VALUE
-
select JSON_SERIALIZE(JSON_QUERY(JDATA, '$') PRETTY) from MY_JSON_TABLE where id <100 and JSON_VALUE(JDATA, '$.name') like '%龙%';
对查询结果处理
select JSON_VALUE(JDATA, '$.name') as NAME, JSON_VALUE(JDATA, '$.age') as AGE from MY_JSON_TABLE where id <100 and JSON_VALUE(JDATA, '$.name') like '%龙%';
取数组第一个元素的字段
select JSON_VALUE(JDATA, '$.name') as NAME, JSON_VALUE(JDATA, '$.age') as AGE, JSON_VALUE(JDATA, '$.work[0].company') as COMPANY from MY_JSON_TABLE where id <100 and JSON_VALUE(JDATA, '$.work[0].company') like '%无限%';
再来几个官方的例子
SELECT JSON_VALUE('{a:100}', '$.a' RETURNING NUMBER) AS value FROM DUAL;
SELECT JSON_VALUE('{a:{b:100}}', '$.a.b') AS value FROM DUAL;
SELECT JSON_VALUE('{a:{b:100}, c:{d:200}, e:{f:300}}', '$.*.d') AS value FROM DUAL;
SELECT JSON_VALUE('[0, 1, 2, 3]', '$[0]') AS value FROM DUAL;
SELECT JSON_VALUE('{a:[5, 10, 15, 20]}', '$.a[2]') AS value FROM DUAL;
SELECT JSON_VALUE('[{a:100}, {a:200}, {a:300}]', '$[1].a') AS value FROM DUAL;
SELECT JSON_VALUE('{firstname:"John"}', '$.lastname' DEFAULT 'No last name found' ON ERROR) AS "Last Name" FROM DUAL;
SELECT JSON_VALUE('{firstname:"John","lastname":""}', '$.lastname'
DEFAULT ' Last name is empty' ON EMPTY
DEFAULT 'No last name found' ON ERROR) AS "Last Name"
FROM DUAL;