MySQL中操作json的函数!

一、📥 创建 JSON 的函数

1. JSON_ARRAY() --- 创建 JSON 数组

sql 复制代码
-- 基础用法
SELECT JSON_ARRAY(1, 'hello', NULL, TRUE);
-- 结果: [1, "hello", null, true]

-- 嵌套数组
SELECT JSON_ARRAY(1, JSON_ARRAY(2, 3), 4);
-- 结果: [1, [2, 3], 4]

-- 从表中查询构建数组
SELECT JSON_ARRAY(id, name) FROM t_org WHERE id = 1;
-- 结果: [1, "测试组织"]

2. JSON_OBJECT() --- 创建 JSON 对象

sql 复制代码
-- 基础用法
SELECT JSON_OBJECT('name', '张三', 'age', 25, 'active', TRUE);
-- 结果: {"name":"张三","age":25,"active":true}

-- 嵌套对象
SELECT JSON_OBJECT(
    'user', JSON_OBJECT('id', 1, 'name', '张三'),
    'status', 'active'
);
-- 结果: {"user":{"id":1,"name":"张三"},"status":"active"}

-- NULL 值会被保留
SELECT JSON_OBJECT('name', '李四', 'phone', NULL);
-- 结果: {"name":"李四","phone":null}

3. JSON_QUOTE() --- 转义为 JSON 字符串

sql 复制代码
-- 给普通字符串加双引号
SELECT JSON_QUOTE('hello');
-- 结果: "hello"

-- 特殊字符会被转义
SELECT JSON_QUOTE('a/b/c');
-- 结果: "a\/b\/c"

-- 已有引号的字符串
SELECT JSON_QUOTE('He said "Hi"');
-- 结果: "He said \"Hi\""

-- 配合 JSON_CONTAINS 使用(如你之前那个SQL)
SELECT JSON_CONTAINS('["a.jpg","b.jpg"]', JSON_QUOTE('a.jpg'), '$');
-- 结果: 1

4. CAST(expr AS JSON) --- 强制转换为 JSON 类型

sql 复制代码
-- 字符串转 JSON
SELECT CAST('{"name":"张三","age":25}' AS JSON);
-- 结果: {"name":"张三","age":25}

-- 无效的 JSON 会报错
SELECT CAST('not a json' AS JSON);  -- ERROR: Invalid JSON text

-- 也可以用来创建简单的 JSON 值
SELECT CAST('100' AS JSON);
-- 结果: 100  (JSON 数字类型)

二、🔍 查询 JSON 的函数

5. JSON_EXTRACT() --- 提取指定路径的值

sql 复制代码
-- 从对象中提取
SELECT JSON_EXTRACT('{"name":"张三","age":25,"address":{"city":"深圳"}}', '$.name');
-- 结果: "张三"

-- 提取嵌套路径
SELECT JSON_EXTRACT('{"name":"张三","address":{"city":"深圳"}}', '$.address.city');
-- 结果: "深圳"

-- 从数组中提取(下标从0开始)
SELECT JSON_EXTRACT('["a","b","c"]', '$[1]');
-- 结果: "b"

-- 提取多个路径(返回数组)
SELECT JSON_EXTRACT('{"a":1,"b":2,"c":3}', '$.a', '$.c');
-- 结果: [1, 3]

-- 通配符:提取数组所有元素
SELECT JSON_EXTRACT('[{"id":1},{"id":2}]', '$[*].id');
-- 结果: [1, 2]

6. column->>column-> --- JSON_EXTRACT 的简写

sql 复制代码
-- 测试表
CREATE TABLE test_json (id INT, info JSON);
INSERT INTO test_json VALUES (1, '{"name":"张三","age":25}');

-- -> 保留类型(数字还是数字,字符串带引号)
SELECT info->'$.name' FROM test_json;   -- 结果: "张三"  (带引号)
SELECT info->'$.age' FROM test_json;    -- 结果: 25      (数字,不带引号)

-- ->> 去掉引号(总是返回字符串)
SELECT info->>'$.name' FROM test_json;  -- 结果: 张三     (不带引号)
SELECT info->>'$.age' FROM test_json;   -- 结果: 25      (字符串)

-- 用于 WHERE 条件
SELECT * FROM test_json WHERE info->>'$.name' = '张三';

7. JSON_SEARCH() --- 搜索值所在的路径

sql 复制代码
-- 在对象中搜索
SELECT JSON_SEARCH('{"a":1,"b":2,"c":2}', 'one', 2);
-- 结果: "$.b"  (返回第一个匹配的路径)

-- 返回所有匹配('all')
SELECT JSON_SEARCH('{"a":1,"b":2,"c":2}', 'all', 2);
-- 结果: ["$.b", "$.c"]

-- 在数组中搜索
SELECT JSON_SEARCH('["apple","banana","apple"]', 'all', 'apple');
-- 结果: ["$[0]", "$[2]"]

-- 找不到返回 NULL
SELECT JSON_SEARCH('{"a":1}', 'one', 999);
-- 结果: NULL

-- ⚠️ 重要:JSON_SEARCH 无法搜索数组根元素的值(需要指定路径范围)
-- 如果失败,检查 JSON 结构是否匹配

8. JSON_CONTAINS() --- 判断是否包含指定值

sql 复制代码
-- 对象中查找某个值(精确匹配)
SELECT JSON_CONTAINS('{"a":1,"b":2}', '1', '$.a');
-- 结果: 1

-- 查找数组是否包含某个元素
SELECT JSON_CONTAINS('["a","b","c"]', '"b"', '$');
-- 结果: 1

-- JSON_QUOTE 可以帮你加引号
SELECT JSON_CONTAINS('["a","b","c"]', JSON_QUOTE('b'), '$');
-- 结果: 1

-- 查找对象是否包含某个 key-value 对
SELECT JSON_CONTAINS('{"user":{"name":"张三","age":25}}', '{"name":"张三"}', '$.user');
-- 结果: 1

-- 查找数组包含整个子对象
SELECT JSON_CONTAINS('[{"id":1},{"id":2}]', '{"id":2}', '$');
-- 结果: 1

9. JSON_CONTAINS_PATH() --- 判断路径是否存在

sql 复制代码
-- 检查某个 key 是否存在
SELECT JSON_CONTAINS_PATH('{"a":1,"b":2}', 'one', '$.a');
-- 结果: 1  (存在)

SELECT JSON_CONTAINS_PATH('{"a":1,"b":2}', 'one', '$.c');
-- 结果: 0  (不存在)

-- 检查多个路径是否都存在('all')
SELECT JSON_CONTAINS_PATH('{"a":1,"b":2}', 'all', '$.a', '$.b');
-- 结果: 1  (两个都存在)

-- 检查多个路径是否存在一个('one')
SELECT JSON_CONTAINS_PATH('{"a":1,"b":2}', 'one', '$.c', '$.d', '$.b');
-- 结果: 1  (至少有一个存在)

-- 检查嵌套路径
SELECT JSON_CONTAINS_PATH('{"user":{"name":"张三"}}', 'one', '$.user.name');
-- 结果: 1

10. JSON_KEYS() --- 获取所有 key

sql 复制代码
-- 获取对象的所有 key
SELECT JSON_KEYS('{"a":1,"b":2,"c":3}');
-- 结果: ["a", "b", "c"]

-- 获取嵌套对象的 key
SELECT JSON_KEYS('{"user":{"name":"张三","age":25}}', '$.user');
-- 结果: ["name", "age"]

-- 空对象返回空数组
SELECT JSON_KEYS('{}');
-- 结果: []

11. JSON_OVERLAPS() --- 判断两个 JSON 是否有交集(MySQL 8.0+)

sql 复制代码
-- 两个数组是否有公共元素
SELECT JSON_OVERLAPS('[1,2,3]', '[3,4,5]');
-- 结果: 1  (有交集,都有 3)

SELECT JSON_OVERLAPS('[1,2,3]', '[4,5,6]');
-- 结果: 0  (无交集)

-- 对象之间的比较(比较 key-value 对)
SELECT JSON_OVERLAPS('{"a":1,"b":2}', '{"b":2,"c":3}');
-- 结果: 1  (都有 b:2)

-- 数组和单个值比较
SELECT JSON_OVERLAPS('[1,2,3]', '2');
-- 结果: 1

三、✏️ 修改 JSON 的函数(返回新 JSON)

12. JSON_SET() --- 设置值(存在覆盖,不存在添加)

sql 复制代码
-- 添加新字段
SELECT JSON_SET('{"a":1}', '$.b', 2);
-- 结果: {"a":1,"b":2}

-- 覆盖已有字段
SELECT JSON_SET('{"a":1}', '$.a', 99);
-- 结果: {"a":99}

-- 添加嵌套字段
SELECT JSON_SET('{"user":{"name":"张三"}}', '$.user.age', 25);
-- 结果: {"user":{"name":"张三","age":25}}

-- 同时设置多个路径
SELECT JSON_SET('{"a":1}', '$.b', 2, '$.c', 3);
-- 结果: {"a":1,"b":2,"c":3}

-- 数组操作
SELECT JSON_SET('["a","b"]', '$[2]', 'c');
-- 结果: ["a","b","c"]  (数组长度自动扩展)

13. JSON_INSERT() --- 仅当路径不存在时才插入

sql 复制代码
-- 路径不存在 → 添加
SELECT JSON_INSERT('{"a":1}', '$.b', 2);
-- 结果: {"a":1,"b":2}

-- 路径已存在 → 不覆盖(和 JSON_SET 的区别就在这里)
SELECT JSON_INSERT('{"a":1}', '$.a', 99);
-- 结果: {"a":1}  (不变!)

-- 混合:已存在的不变,不存在的添加
SELECT JSON_INSERT('{"a":1,"b":2}', '$.b', 999, '$.c', 3);
-- 结果: {"a":1,"b":2,"c":3}  (b 不变,c 新增)

14. JSON_REPLACE() --- 仅当路径存在时才替换

sql 复制代码
-- 路径存在 → 替换
SELECT JSON_REPLACE('{"a":1}', '$.a', 99);
-- 结果: {"a":99}

-- 路径不存在 → 不添加(和 JSON_SET 的区别就在这里)
SELECT JSON_REPLACE('{"a":1}', '$.b', 2);
-- 结果: {"a":1}  (不变!)

-- 混合:存在的替换,不存在的不变
SELECT JSON_REPLACE('{"a":1,"b":2}', '$.a', 99, '$.c', 3);
-- 结果: {"a":99,"b":2}  (c 没有添加)

15. JSON_REMOVE() --- 删除指定路径

sql 复制代码
-- 删除单个字段
SELECT JSON_REMOVE('{"a":1,"b":2,"c":3}', '$.b');
-- 结果: {"a":1,"c":3}

-- 删除多个字段
SELECT JSON_REMOVE('{"a":1,"b":2,"c":3}', '$.a', '$.c');
-- 结果: {"b":2}

-- 删除数组元素
SELECT JSON_REMOVE('["a","b","c"]', '$[1]');
-- 结果: ["a","c"]

-- 删除嵌套路径
SELECT JSON_REMOVE('{"user":{"name":"张三","age":25}}', '$.user.age');
-- 结果: {"user":{"name":"张三"}}

-- 删除不存在的路径 → 无变化
SELECT JSON_REMOVE('{"a":1}', '$.b');
-- 结果: {"a":1}

16. JSON_ARRAY_APPEND() --- 数组末尾追加

sql 复制代码
-- 数组追加元素
SELECT JSON_ARRAY_APPEND('[1,2,3]', '$', 4);
-- 结果: [1,2,3,4]

-- 追加字符串(需要引号)
SELECT JSON_ARRAY_APPEND('["a","b"]', '$', 'c');
-- 结果: ["a","b","c"]

-- 追加到嵌套数组
SELECT JSON_ARRAY_APPEND('{"arr":[1,2]}', '$.arr', 3);
-- 结果: {"arr":[1,2,3]}

-- 追加到多个路径
SELECT JSON_ARRAY_APPEND('[1,2]', '$', 3, '$', 4);
-- 结果: [1,2,3,4]

-- 如果目标不是数组,会自动转成数组再追加
SELECT JSON_ARRAY_APPEND('{"a":1}', '$.a', 2);
-- 结果: {"a":[1,2]}  (1 被转成了数组)

17. JSON_ARRAY_INSERT() --- 数组指定位置插入

sql 复制代码
-- 在下标 1 的位置插入(下标从 0 开始)
SELECT JSON_ARRAY_INSERT('[1,2,3]', '$[1]', 99);
-- 结果: [1,99,2,3]

-- 在开头插入
SELECT JSON_ARRAY_INSERT('["a","b"]', '$[0]', 'start');
-- 结果: ["start","a","b"]

-- 在末尾插入(下标等于长度)
SELECT JSON_ARRAY_INSERT('["a","b"]', '$[2]', 'c');
-- 结果: ["a","b","c"]

-- 插入到嵌套数组
SELECT JSON_ARRAY_INSERT('{"arr":[1,3]}', '$.arr[1]', 2);
-- 结果: {"arr":[1,2,3]}

18. JSON_MERGE_PATCH() --- 合并 JSON(覆盖同名 key)

sql 复制代码
-- 合并两个对象(同名 key 被覆盖)
SELECT JSON_MERGE_PATCH('{"a":1,"b":2}', '{"b":99,"c":3}');
-- 结果: {"a":1,"b":99,"c":3}

-- 合并数组(后者替换前者,不是拼接!)
SELECT JSON_MERGE_PATCH('[1,2]', '[3,4]');
-- 结果: [3,4]

-- NULL 表示删除
SELECT JSON_MERGE_PATCH('{"a":1,"b":2}', '{"b":null}');
-- 结果: {"a":1}

-- 嵌套合并
SELECT JSON_MERGE_PATCH('{"user":{"name":"张三","age":25}}', '{"user":{"age":26}}');
-- 结果: {"user":{"name":"张三","age":26}}

19. JSON_MERGE_PRESERVE() --- 合并 JSON(保留同名 key 为数组)

sql 复制代码
-- 同名 key 合并成数组
SELECT JSON_MERGE_PRESERVE('{"a":1,"b":2}', '{"b":99,"c":3}');
-- 结果: {"a":1,"b":[2,99],"c":3}

-- 数组拼接(和 PATCH 不同)
SELECT JSON_MERGE_PRESERVE('[1,2]', '[3,4]');
-- 结果: [1,2,3,4]

-- 嵌套合并
SELECT JSON_MERGE_PRESERVE('{"user":{"name":"张三"}}', '{"user":{"age":25}}');
-- 结果: {"user":{"name":"张三","age":25}}

四、📊 JSON 信息/元数据函数

20. JSON_TYPE() --- 返回数据类型

sql 复制代码
SELECT JSON_TYPE('{"a":1}');        -- 结果: OBJECT
SELECT JSON_TYPE('[1,2,3]');        -- 结果: ARRAY
SELECT JSON_TYPE('"hello"');        -- 结果: STRING
SELECT JSON_TYPE('123');            -- 结果: INTEGER
SELECT JSON_TYPE('123.45');         -- 结果: DECIMAL
SELECT JSON_TYPE('true');           -- 结果: BOOLEAN
SELECT JSON_TYPE('null');           -- 结果: NULL

21. JSON_LENGTH() --- 返回长度

sql 复制代码
-- 对象的长度 = key 数量
SELECT JSON_LENGTH('{"a":1,"b":2,"c":3}');
-- 结果: 3

-- 数组的长度 = 元素数量
SELECT JSON_LENGTH('["a","b","c","d"]');
-- 结果: 4

-- 嵌套路径的长度
SELECT JSON_LENGTH('{"arr":[1,2,3,4,5]}', '$.arr');
-- 结果: 5

-- 空数组/空对象长度为 0
SELECT JSON_LENGTH('[]');   -- 0
SELECT JSON_LENGTH('{}');   -- 0

22. JSON_DEPTH() --- 返回最大深度

sql 复制代码
-- 标量深度为 1
SELECT JSON_DEPTH('"hello"');        -- 结果: 1
SELECT JSON_DEPTH('123');            -- 结果: 1

-- 空数组/空对象深度为 2
SELECT JSON_DEPTH('[]');             -- 结果: 2
SELECT JSON_DEPTH('{}');             -- 结果: 2

-- 简单对象深度为 2
SELECT JSON_DEPTH('{"a":1}');        -- 结果: 2

-- 嵌套对象深度为 3
SELECT JSON_DEPTH('{"a":{"b":2}}');  -- 结果: 3

-- 嵌套数组
SELECT JSON_DEPTH('[1,[2,[3]]]');    -- 结果: 4

23. JSON_VALID() --- 判断是否合法 JSON

sql 复制代码
SELECT JSON_VALID('{"name":"张三"}');    -- 结果: 1
SELECT JSON_VALID('["a","b"]');          -- 结果: 1
SELECT JSON_VALID('not a json');         -- 结果: 0
SELECT JSON_VALID('{name:"张三"}');       -- 结果: 0 (key 没有引号)

-- 数据清洗时用
SELECT * FROM t_org WHERE JSON_VALID(info) = 0;  -- 找出不合法的数据

24. JSON_SCHEMA_VALID() --- Schema 校验(MySQL 8.0+)

sql 复制代码
-- 定义 Schema(要求 name 是字符串,age 是整数)
SET @schema = '{
    "type": "object",
    "properties": {
        "name": {"type": "string"},
        "age": {"type": "integer"}
    },
    "required": ["name"]
}';

-- 校验
SELECT JSON_SCHEMA_VALID(@schema, '{"name":"张三","age":25}');
-- 结果: 1

SELECT JSON_SCHEMA_VALID(@schema, '{"name":"张三"}');
-- 结果: 1  (age 不是必须的)

SELECT JSON_SCHEMA_VALID(@schema, '{"name":123,"age":25}');
-- 结果: 0  (name 应该是字符串)

SELECT JSON_SCHEMA_VALID(@schema, '{"age":25}');
-- 结果: 0  (缺少必须的 name)

25. JSON_STORAGE_SIZE() --- 存储字节数

sql 复制代码
-- 查看 JSON 占用的存储空间
SELECT JSON_STORAGE_SIZE('{"a":1,"b":2,"c":3}');
-- 结果: 31  (字节)

-- 对比不同数据的大小
SELECT 
    JSON_STORAGE_SIZE('{"a":1}') AS small,
    JSON_STORAGE_SIZE('{"aaaaaaaaaa":1}') AS large;

26. JSON_TABLE() --- JSON 转关系型表(MySQL 8.0+)

sql 复制代码
-- 假设有张表存储了用户的多个电话
CREATE TABLE user_phones (id INT, phones JSON);
INSERT INTO user_phones VALUES (1, '["13800138000","13800138001"]');

-- 将数组展开成多行
SELECT *
FROM user_phones,
JSON_TABLE(
    phones,
    '$[*]' COLUMNS(
        row_id FOR ORDINALITY,           -- 自动编号
        phone_number VARCHAR(20) PATH '$'  -- 每个元素的值
    )
) AS jt;

-- 结果:
-- id | row_id | phone_number
-- 1  | 1      | 13800138000
-- 1  | 2      | 13800138001

-- 复杂示例:展开对象数组
CREATE TABLE orders (id INT, items JSON);
INSERT INTO orders VALUES (1, '[
    {"product":"手机","price":5999,"qty":1},
    {"product":"耳机","price":299,"qty":2}
]');

SELECT *
FROM orders,
JSON_TABLE(
    items,
    '$[*]' COLUMNS(
        product VARCHAR(50) PATH '$.product',
        price DECIMAL(10,2) PATH '$.price',
        qty INT PATH '$.qty'
    )
) AS jt;

-- 结果:
-- id | product | price  | qty
-- 1  | 手机    | 5999.00 | 1
-- 1  | 耳机    | 299.00  | 2
相关推荐
来者皆善1 小时前
了解Mysql优化吗?如何优化索引?
数据库·mysql
赤壁小虾3 小时前
【渲染流水线】[逐片元阶段]-[透明度测试]以UnityURP为例
java·前端·数据库
MC皮蛋侠客4 小时前
SQLAlchemy 系列(七):高级建模与高效写入——批量 DML、方言与扩展
数据库·python
奈斯先生Vector5 小时前
把 Midjourney 二次编辑做成生产系统:customId 能力令牌、Action Graph 与 WebUI 精修工作台
数据库·人工智能·架构·aigc·音视频·midjourney
Lethehong5 小时前
双擎并驱·全链路并行:KFS让TB级异构增量同步秒级到达
数据库
MC皮蛋侠客5 小时前
SQLAlchemy 系列(八):AsyncIO、并发与 Web 生命周期——让每个并发任务持有自己的 Session
数据库·python
一水6 小时前
Redis实战:一个AI工作流系统里的五个应用场景,从传参到限流的完整链路
数据库·redis·wpf
Ai拆代码的曹操6 小时前
MySQL GROUP BY 性能优化:执行计划分析 + 索引重构实战
mysql·性能优化·重构
枫叶v.7 小时前
Prompt Injection 防不住怎么办?从 Source-Sink 模型设计 Agent 安全边界
数据库·安全·prompt