Json 数据类型与函数

Json 类型与使用

MySQL 从5.7开始就支持JavaScript 对象表示 (Java Script Object Mptatopm JSON) 仅将数据库类型修改成 JSON 即可,

JSON 类型的表

  1. CREATE TABLE `test` (
  2. `id` int NOT NULL COMMENT 'ID',
  3. `json` json NOT NULL COMMENT 'json',
  4. PRIMARY KEY (`id`)
  5. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

通过JSON进行过滤和查询

-- 显示JSON某个字段
SELECT json->'$.data' FROM test;

-- 通过JSON过滤数据
SELECT json->'$.data' FROM test WHERE json->'$.data' = 1;

Json 函数

JSON_PRETTY()

以优雅的格式显示JSON args0: json 字段

SELECT JSON_PRETTY(json)  FROM test;

JSON_CONTAINS_PATH()

判断Json是否存在此字段 args0: json 字段 args1: ‘one’ 表示至少存在一个 ‘all’表示全部存在 args2: json结构字符 args2: json结构字符 (N ..)

SELECT JSON_CONTAINS_PATH(json, 'one', '$.data') FROM test;

JSON_SET()

替换JSON中的某个值 args0: json 字段 args1: 表示key 结构字符 args2: 表示value 对象 [args1, args2, .. N]

UPDATE test SET json = JSON_SET(json, '$.name', '李大双', '$.age', 18) WHERE id = 1;

JSON_INSERT()

插入新值但不替换现有的值

UPDATE test SET json = JSON_INSERT(json, '$.alias', '狗子', '$.age', 18) WHERE id = 1;

JSON_REPLACE()

仅替换现有的值

UPDATE test SET json = JSON_REPLACE(json, '$.alias', '狗子', '$.age', 18) WHERE id = 1;

CTE 的使用

MySQL8 支持公用表达式 (CTE),支持递归和非递归二种。 公共表达式允许使用命名的临时结果集,这是通过允许在SELECT 语句和某些其他语句签名使用WITH子句来实现的。

CTE 非递归

公共表达式(CTE)与派生表达类似,但它的声明会放在查询块之前,而不是FROM子句中。 CTE语法:WITH [CTE名称] AS (子查询) 读到这里是不是感觉很懵逼,它到底有什么用? 看下面例子

-- 场景查询工资较上一年比例; 下面第3行第5行重复子查询
SELECT 100 * ((a.sum - b.sum) / a.number) AS "rate" FROM
    (SELECT SUM(salary) AS "sum", SUM(year) AS "year" GROUP BY year) a
LEFT JOIN
    (SELECT SUM(salary) AS "sum", SUM(year) AS "year" GROUP BY year) b
WHERE a.year = b.year - 1;

使用CTE 之后

-- 创建CTE
WITH SALARY_TABLE AS (SELECT SUM(salary) AS "sum", SUM(year) AS "year" GROUP BY year)

-- 在查询中使用
SELECT 100 * ((a.sum - b.sum) / a.number) AS "rate" FROM SALARY_TABLE AS a
LEFT JOIN SALARY_TABLE AS b
WHERE a.year = b.year - 1;

CTE 递归

递归CTE子查询包括两部分: seed 查询和 recursive查询, 由UNION ALL 或者 UNION DISTINCT 分隔。 CTE语法:WITH RECURSIVE [CTE名称] AS (子查询) ; 子查询必须包含UNION ALL 或 UNION DISTINCT 直到连接下面的查询没有数据返回为止,**务必避免死循环** !!

-- 递归的CTE
WITH RECURSIVE cte_name AS (
    SELECT * FROM USER WHERE id = 2 
  UNION ALL
    SELECT a.* FROM USER a INNER JOIN cte_name b ON a.pid = b.id 
) 
SELECT * FROM cte_name;

窗口函数特性

对于查询中的每一行,都可以使用窗口函数,利用与该行相关的行执行计算;这就是窗口函数。

CUME_DIST()

累积分布值

SELECT CUME_DIST() OVER w AS 'Rank', FIRST_VALUE(salary) OVER w AS 'F', u.* FROM USER u
WINDOW w AS (ORDER BY salary DESC)

DENSE_RANK()

分区内当前行的等级 (无间隔)

SELECT DENSE_RANK() OVER w AS 'Rank', FIRST_VALUE(salary) OVER w AS 'F', u.* FROM USER u
WINDOW w AS (ORDER BY salary DESC)

FIRST_VALUE()

窗口帧中第一行的参数值

SELECT CUME_DIST() OVER w AS 'Rank', LAST_VALUE(salary) OVER w AS 'F', u.* FROM USER u
WINDOW w AS (ORDER BY salary DESC)

LAG()

落后于分区内当前行的那一行的参数值

SELECT CUME_DIST() OVER w AS 'Rank', LAST_VALUE(salary) OVER w AS 'F', u.* FROM USER u
WINDOW w AS (ORDER BY salary DESC)

LAST_VALUE()

窗口帧中最末行的参数值

SELECT RANK() OVER w AS 'Rank', FIRST_VALUE(salary) OVER w AS 'F', u.* FROM USER u
WINDOW w AS (ORDER BY salary DESC)

LEAD()

领先于分区内当前行的那一行的参数值

SELECT CUME_DIST() OVER w AS 'Rank', LEAD(salary,0) OVER w AS 'F', u.* FROM USER u
WINDOW w AS (ORDER BY salary DESC)

NTH_VALUE()

窗口帧中的第N行的参数值

SELECT CUME_DIST() OVER w AS 'Rank', NTH_VALUE(salary,1) OVER w AS 'F', u.* FROM USER u
WINDOW w AS (ORDER BY salary DESC)

NTILE()

分区内当前行的桶编号

SELECT NTILE(3) OVER w AS 'Rank', u.* FROM USER u
WINDOW w AS (ORDER BY salary DESC)

PERCENT_RANK()

百分比排名值

SELECT PERCENT_RANK() OVER w AS 'Rank', FIRST_VALUE(salary) OVER w AS 'F', u.* FROM USER u
WINDOW w AS (ORDER BY salary DESC)

RANK()

分区中当前行的等级(有间隔)

-- 根据字段计算出排行第几
SELECT RANK() OVER(  ORDER BY salary DESC), u.* FROM USER u

ROW_NUMBER()

分区内当前行的编号

-- 通过OVER内的排序规则给数据排序并生成顺序ID
SELECT ROW_NUMBER() OVER(ORDER BY salary DESC), u.* FROM USER u

多次窗口函数

在SELECT 中定义函数, 在FROM 后面进行使用

SELECT RANK() OVER w AS 'Rank', FIRST_VALUE(salary) OVER w AS 'F', u.* FROM USER u
WINDOW w AS (ORDER BY salary DESC)

分割结果

窗口函数还可以对结果进行分区计算

-- 根据分区查找数据
SELECT ROW_NUMBER() OVER(PARTITON BY pid ORDER BY salary DESC), u.* FROM USER u

Generated Column (生成列)

生成列(Generated Column)的值是根据列定义中包含的表达式计算得出的。生产列包含二种类型: Virtual 生成列:当从表中读取记录时,将计算该列。 Stored 生成列: 当想表中写入新记录时,将计算该列并将其作为常规列存储在表中。

Virtual 虚拟列

虚拟列; 通过多个物理列动态计算出来结果, 虚拟列不占用任何存储空间

-- 创建表
CREATE TABLE `test` (
  `id` int NOT NULL COMMENT 'ID',
  `json` json NOT NULL COMMENT 'json',
  `f_name` varchar(50) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
  `s_name` varchar(50) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
  `full_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci GENERATED ALWAYS AS (concat(`f_name`,_utf8mb4'_',`s_name`)) VIRTUAL NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

-- 插入数据
INSERT INTO `test`(`id`, `json`, `f_name`, `s_name`) VALUES (1, '{}', '1', '2');

-- 查询
SELECT * FROM test;

Stored 存储列

存储列; 类似触发器监听每次插入数据或修改数据时更新列,是实际存储到磁盘的 每次插入或者修改数据的时候不需要修改此字段,此字段会自动更新

CREATE TABLE `test` (
  `id` int NOT NULL COMMENT 'ID',
  `json` json NOT NULL COMMENT 'json',
  `f_name` varchar(50) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
  `s_name` varchar(50) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
  `full_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci GENERATED ALWAYS AS (concat(`f_name`,_utf8mb4'_',`s_name`)) VIRTUAL NOT NULL,
  `stored_name` varchar(100) COLLATE utf8mb4_general_ci GENERATED ALWAYS AS (concat(`f_name`,_utf8mb4'_',`s_name`)) STORED,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;