JSON 系列之1:将 JSON 数据存储在 Oracle 数据库中

本文为Oracle数据库JSON学习系列的第一篇,讲述如何将JSON文档存储到数据库中,包括了版本为19c和23ai的情形。

19c中的JSON

先来看一下数据库版本为19c时的情形。

创建表colortab,其中color列的长度设为4000。若color的长度需要设为32767,则init.ora 参数 MAX_STRING_SIZE 必须设置为 EXTENDED。

sql 复制代码
DROP TABLE colortab PURGE;

CREATE TABLE colortab (
    id    NUMBER,
    color VARCHAR2(4000)
);

插入4条数据:

sql 复制代码
INSERT INTO colortab VALUES ( 1,
                              '
 {
  "color": "black",
  "rgb": [0,0,0],
  "hex": "#000000"
 }
' );

INSERT INTO colortab VALUES ( 2,
                              '
 {
  "color": "orange red",
  "rgb": [255,69,0],
  "hex": "#FF4500"
 }
' );

INSERT INTO colortab VALUES ( 3,
                              '
 {
  color: "gold",
  "rgb": [255,215,0],
  "hex": "#FFD700 "
 }
' );

INSERT INTO colortab VALUES ( 4,
                              'I am not valid JSON' );

COMMIT;

查看这些记录,会发现记录3的color字段并没有用双引号括起,于严格的JSON定义不符,但松散的JSON定义是允许的:

这可以通过如下来证明:

sql 复制代码
SQL> set echo on
SQL> SELECT id FROM colorTab WHERE color IS NOT JSON;

        ID
----------
         4

SQL> 
SQL> SELECT id FROM colorTab WHERE color IS NOT JSON STRICT;

        ID
----------
         3
         4

在Oracle 23ai JSON Developer's Guide中,松散的语法称为Lax JSON Syntax,是默认的。严格的则称为Strict JSON Syntax。

插入一条新纪录,此记录符合Strict JSON Syntax,但具有重复的key:"color"。

sql 复制代码
INSERT INTO colortab VALUES ( 5,
                              '
 {
  "color": "black",
  "rgb": [0,0,0],
  "hex": "#000000",
  "color": "white"
 }
' );

COMMIT;

子句可以排除具有重复key的JSON。不过检查重复键是有代价的,所以一般是不做的:

sql 复制代码
SQL> SELECT id FROM colorTab WHERE color IS JSON STRICT;

        ID
----------
         1
         2
         5


SQL> SELECT id FROM colorTab WHERE color IS JSON STRICT WITH UNIQUE KEYS;

        ID
----------
         1
         2

如果只想让列存合法的JSON,在19c版本可以通过IS JSON约束。

sql 复制代码
TRUNCATE TABLE colorTab;

ALTER TABLE colorTab ADD CONSTRAINT ensure_json CHECK (color IS JSON);

此时,插入记录4时报错:

sql 复制代码
错误报告 -
ORA-02290: 违反检查约束条件 (SSB.ENSURE_JSON)

https://docs.oracle.com/error-help/db/ora-02290/

如果约束是CHECK (color IS JSON STRICT),则插入记录4时报错同上。

JSON的信息可以从字典视图中查看:

sql 复制代码
col table_name for a10
col column_name for a16
SELECT * FROM USER_JSON_COLUMNS WHERE table_name = 'COLORTAB';

TABLE_NAME OBJEC COLUMN_NAME      FORMAT    DATA_TYPE    
---------- ----- ---------------- --------- -------------
COLORTAB   TABLE COLOR            TEXT      VARCHAR2   

最后再说一点,上例中的JSON是用VARCHAR2来存的,此外还可以用CLOB和BLOB。通常会建议BLOB,因为BLOB占用空间更小,从而引发的I/O更少。

Internally, CLOB encodes characters as UCS2 (similar to UTF16) which means every character takes up two bytes. BLOB does not perform such re-encoding but instead stores the Unicode (UTF8) bytes unmodified - thus requiring half the storage size for ASCII characters, and half the IO to load it.

23ai中的JSON

23ai支持原生JSON,因此表的定义变为:

sql 复制代码
drop table colortab purge;
CREATE TABLE colortab (
    id    NUMBER,
    color JSON
);

JSON 数据类型的实例使用 OSON 格式存储。OSON 是 Oracle 针对 Oracle 数据库服务器和 Oracle 数据库客户端中的查询和更新而优化的二进制 JSON 格式。

根据Oracle Database JSON Capabilities Specification,单个JSON实例的存储限制为32MB。

此时插入之前的5条数据。

插入记录4时,报错如下:

sql 复制代码
错误报告 -
ORA-40441: JSON 语法错误
JZN-00078: Invalid JSON keyword 'I' (line 1, position 1)

https://docs.oracle.com/error-help/db/ora-40441/

More Details :
https://docs.oracle.com/error-help/db/ora-40441/
https://docs.oracle.com/error-help/db/jzn-00078/

插入记录5时,报错如下:

sql 复制代码
错误报告 -
SQL 错误: ORA-40473: JSON 对象中存在重复的键名 'color'
JZN-00007: Object member key 'color' is not unique

https://docs.oracle.com/error-help/db/ora-40473/40473. 00000 -  "duplicate key names '%s' in JSON object"
*Cause:    The provided JavaScript Object Notation (JSON) data had duplicate
           key names in one object.
*Action:   Provide JSON data with unique key names in each JSON object.

More Details :
https://docs.oracle.com/error-help/db/ora-40473/
https://docs.oracle.com/error-help/db/jzn-00007/

这说明23ai JSON默认语法是Lax JSON Syntax,并且不允许重复键。文档 也是这么说的:

JSON 标准建议 JSON 对象不要有重复的字段名称。Oracle 数据库通过引发错误来强制 JSON 类型数据遵循此要求。

查看字典视图,数据类型为JSON,存储格式为OSON:

sql 复制代码
SQL> col table_name for a10
SQL> col column_name for a16
SQL> SELECT * FROM USER_JSON_COLUMNS WHERE table_name = 'COLORTAB';

TABLE_NAME OBJEC COLUMN_NAME      FORMAT    DATA_TYPE    
---------- ----- ---------------- --------- -------------
COLORTAB   TABLE COLOR            OSON      JSON         

Oracle称所有非OSON存储的JSON为文本JSON(Textual JSON)。

JSON数据类型无法指定Strict JSON Syntax,按照文档5.3 Specifying Strict or Lax JSON Syntax 的说法:

Oracle 数据库的默认 JSON 语法是宽松的。严格或宽松语法仅对 SQL/JSON 条件 is json 和 is not json 有意义。所有其他 SQL/JSON 函数和条件都使用宽松语法来解释输入,并在返回输出时使用严格语法。
如果您需要确保特定文本 JSON 数据具有严格正确的语法,请先使用 is json 或 is not json 进行检查。

参考

相关推荐
白皎32 分钟前
立志成为一名优秀测试开发工程师(第十一天)—Postman动态参数/变量、文件上传、断言策略、批量执行及CSV/JSON数据驱动测试
json·postman
GUIQU.2 小时前
【Oracle】DCL语言
数据库·oracle
在代码的海洋中寻找亚特兰蒂斯3 小时前
AJAX对于XML和JSON的处理
xml·ajax·json
wtsolutions12 小时前
Excel to JSON 插件 2.4.0 版本更新
json·excel
not coder15 小时前
Pytest Fixture 是什么?
数据库·oracle·pytest
珹洺19 小时前
数据库系统概论(十六)数据库安全性(安全标准,控制,视图机制,审计与数据加密)
数据库·安全·oracle
线条11 天前
Flume 自定义拦截器开发实战:添加时间戳与 JSON 处理
大数据·json·flume
DoWeixin61 天前
【请关注】各类数据库优化,抓大重点整改,快速优化空间mysql,Oracle,Neo4j等
数据库·mysql·oracle·neo4j
消失在人海中1 天前
Oracle的Hint
数据库·oracle
雷神乐乐1 天前
Oracle正则表达式学习
数据库·sql·oracle·正则表达式