沉梦听雨的编程指南 沉梦听雨的编程指南
首页
  • 基础篇
  • 集合篇
  • 并发篇
  • JVM
  • 新特性
  • 计算机网络
  • 操作系统
  • 数据结构与算法
  • 基础篇
  • MySql
  • Redis
  • 达梦数据库
  • Spring
  • SpringBoot
  • Mybatis
  • Shiro
  • 设计须知
  • UML画图
  • 权限校验
  • 设计模式
  • API网关
  • RPC
  • 消息队列
  • SpringCloud
  • 分布式事务
  • 云存储
  • 搜索引擎
  • 多媒体框架
  • 虚拟机
  • 开发工具篇
  • 工具库篇
  • 开发技巧篇
  • 工具类系列
  • 随笔
  • 前端环境搭建
  • HTML与CSS
  • JS学习
  • Vue3入门
  • Vue3进阶
  • 黑马Vue3
  • 脚手架搭建
  • 瑞吉外卖
  • 黑马点评
  • vue-blog
  • 沉梦接口开放平台
  • 用户中心
  • 聚合搜索平台
  • 仿12306项目
  • 壁纸小程序项目
  • RuoYi-Vue
  • 博客搭建
  • 网站收藏箱
  • 断墨寻径摘录
  • 费曼学习法
Github (opens new window)

沉梦听雨

时间是最好的浸渍剂,而沉淀是最好的提纯器🚀
首页
  • 基础篇
  • 集合篇
  • 并发篇
  • JVM
  • 新特性
  • 计算机网络
  • 操作系统
  • 数据结构与算法
  • 基础篇
  • MySql
  • Redis
  • 达梦数据库
  • Spring
  • SpringBoot
  • Mybatis
  • Shiro
  • 设计须知
  • UML画图
  • 权限校验
  • 设计模式
  • API网关
  • RPC
  • 消息队列
  • SpringCloud
  • 分布式事务
  • 云存储
  • 搜索引擎
  • 多媒体框架
  • 虚拟机
  • 开发工具篇
  • 工具库篇
  • 开发技巧篇
  • 工具类系列
  • 随笔
  • 前端环境搭建
  • HTML与CSS
  • JS学习
  • Vue3入门
  • Vue3进阶
  • 黑马Vue3
  • 脚手架搭建
  • 瑞吉外卖
  • 黑马点评
  • vue-blog
  • 沉梦接口开放平台
  • 用户中心
  • 聚合搜索平台
  • 仿12306项目
  • 壁纸小程序项目
  • RuoYi-Vue
  • 博客搭建
  • 网站收藏箱
  • 断墨寻径摘录
  • 费曼学习法
Github (opens new window)
  • 基础

  • Mysql

    • MySQL基础小结
    • 索引篇
    • 讲讲回表查询
    • 讲讲索引失效问题
    • 思维导图
    • 数据库优化
    • 临时表
    • 实战篇

      • 日常小记
        • 编写 Mysql 触发器
        • 联表查询问题
        • count(*) 和 count(1) 的区别
        • 获取行号
        • DISTINCT 子句
        • 替换字段值
        • 截取字段值
        • 分页查询的 sql 编写
        • SQL 的执行顺序⭐️
        • 正则表达式查询
        • select 1
        • 学习参考
      • JOIN 解析
      • 执行计划解析
      • 内置函数小记
      • JSON字段处理
      • 时间字段的处理
      • 一文教你如何删除重复记录
      • exists语法解析
      • SQL语句优化
    • 读高性能MySQL笔记

  • Redis

  • 达梦数据库

  • 数据库
  • Mysql
  • 实战篇
沉梦听雨
2023-10-24
目录

日常小记

# 实战篇

# 编写 Mysql 触发器

1、第一条,可执行

DELIMITER $$

create trigger update_ai_alarm_status
after update on t_ai_alarm_stat for each row
begin
	if new.status <> old.status then

        UPDATE t_ai_alarm_20231011
        SET status = NEW.status
        WHERE org_id = NEW.org_id
        AND dev_id = NEW.dev_id
        AND channel_id = NEW.channel_id
        AND alg_type = NEW.alg_type
        AND alert_type = NEW.alert_type
				AND NEW.alert_date = CONVERT(alarm_time, DATE);

        UPDATE t_ai_alarm_20231012
        SET status = NEW.status
        WHERE org_id = NEW.org_id
        AND dev_id = NEW.dev_id
        AND channel_id = NEW.channel_id
        AND alg_type = NEW.alg_type
        AND alert_type = NEW.alert_type
				AND NEW.alert_date = CONVERT(alarm_time, DATE);
        
    END IF;
END$$

DELIMITER ;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

有个弊端,不灵活,需要写很多表进去

2、触发器中使用动态 sql,不可用,会报错

DELIMITER $$

CREATE TRIGGER update_ai_alarm_status 
AFTER UPDATE ON t_ai_alarm_stat FOR EACH ROW
BEGIN
  IF NEW.status <> OLD.status THEN
    SET @today = DATE_FORMAT(NEW.alert_date, '%Y%m%d');
    SET @update_status_sql = CONCAT('UPDATE t_ai_alarm_', @today, '
        SET status = NEW.status
        WHERE alarm_time = NEW.alert_date
        AND org_id = NEW.org_id
        AND dev_id = NEW.dev_id
        AND channel_id = NEW.channel_id
        AND alg_type = NEW.alg_type
        AND alert_type = NEW.alert_type');
    PREPARE create_stmt FROM @update_status_sql;
    EXECUTE create_stmt;
    DEALLOCATE PREPARE create_stmt;
  END IF;
END$$

DELIMITER ;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

报错:

1336 - Dynamic SQL is not allowed in stored function or trigger
MySQL不允许在存储函数或触发器中使用动态SQL
1
2

参考:

  • 【精选】【MySQL触发器】触发器的使用、创建、修改及删除_创建一个insert触发器_霸道小明的博客-CSDN博客 (opens new window)

  • MySQL 触发器使用教程 - 六种触发器案例详解 - 知乎 (zhihu.com) (opens new window)

  • 触发器(三、条件触发)_触发器条件判断-CSDN博客 (opens new window)

  • Mysql 预准备语句详解(prepare、execute、deallocate)_mysql prepare execute-CSDN博客 (opens new window)

# 联表查询问题

# 基础查询(49条记录)
			 SELECT 
        		 *
        FROM
            t_maintenance_enterprise ent
        WHERE
            ent.is_deleted = 0;
# 反例(18)
        SELECT
						*
        FROM
            t_maintenance_enterprise ent
                LEFT JOIN
            t_maintenance_maintainer main
            ON ent.id = main.enterprise_id
        WHERE ent.is_deleted = 0
						and main.is_deleted = 0;
# 正例(53)
        SELECT
						*
        FROM
            t_maintenance_enterprise ent
                LEFT JOIN
            t_maintenance_maintainer main
            ON ent.id = main.enterprise_id and main.is_deleted = 0
        WHERE ent.is_deleted = 0;
          
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# count(*) 和 count(1) 的区别

COUNT(*) 和 COUNT(1) 都是用于统计行数的聚合函数,但它们在实现方式上有一些区别。

  1. COUNT(*):COUNT(*) 用于计算表中的所有行数,无论行中的数据是否为 NULL。它会对表的每一行进行计数,包括 NULL 值行。
    • 因此,COUNT(*) 返回的结果是表的总行数。
  2. COUNT(1):COUNT(1) 也用于计算表中的行数,但它不关心行中的实际数据或 NULL 值。它会将一个常量值 1 应用于每一行,并对每一行进行计数。因为它只是对每一行应用一个固定值,而不需要访问实际的数据内容。
    • 所以在某些数据库系统中,COUNT(1) 的性能可能会比 COUNT(*) 稍微好一些。

两者的区别可以总结如下:

  • COUNT(*) 对表的每一行进行计数,包括 NULL 值行。
  • COUNT(1) 将一个常量值 1 应用于每一行进行计数,不考虑行中的实际数据或 NULL 值。

在实际使用中,通常使用 COUNT(*) 来统计行数,因为它更符合直觉和语义。而 COUNT(1) 则可以作为一种性能优化手段,在某些情况下可能会稍微提高查询的执行速度。

# 获取行号

利用 ROW_NUMBER() 函数。

SELECT
  ROW_NUMBER() over(order by town, market) rowNumber,
	town,
	market,
	count(*) 
FROM
	tbl_ent 
WHERE
	is_deleted = 0 
	AND create_time BETWEEN '2023-08-27 15:01:09' 
	AND '2023-08-29 15:01:09' 
GROUP BY
	town,
	market;
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# DISTINCT 子句

  • 用于返回唯一不同的值,通常与 SELECT 子句一起使用,消除结果集中的重复行。

# 替换字段值

用 replace 方法:

UPDATE your_table_name
SET your_column_name = REPLACE(your_column_name, '替换前字符串', '替换后字符串')
1
2

用途:比如可以用来替换路径前缀

# 截取字段值

用 substring + LENGTH 方法:

UPDATE t_file 
SET no_prefix_path = SUBSTRING( file_path, LENGTH( 'http://172.16.27.40:9001' ) + 1 );

# file_path = http://127.0.0.1:8080/xxxx

-- 赋值之后
# no_prefix_path = /xxxx

1
2
3
4
5
6
7
8

# 分页查询的 sql 编写

分页查询的 SQL 语句通常包括以下部分:

  1. SELECT 语句:选择需要查询的字段。
  2. FROM 语句:指定要查询的表。
  3. WHERE 语句(可选):添加筛选条件。
  4. ORDER BY 语句(可选):对结果进行排序。
  5. LIMIT 和 OFFSET 语句:实现分页功能。

以下是一个分页查询的 SQL 示例:

SELECT * FROM 表名
WHERE 条件
ORDER BY 排序字段
LIMIT 每页数量 OFFSET (当前页数 - 1) * 每页数量;
1
2
3
4

注意:

实际使用中需要将 "表名"、"条件"、"排序字段"、"每页数量" 和 "当前页数" 替换为实际的值。

两种写法:

SELECT * FROM table LIMIT [offset,] rows | rows OFFSET offset
1

⚠️LIMIT 子句可以被用于指定 SELECT 语句返回的记录数。

需注意以下几点:

  • 第一个参数指定第一个返回记录行的偏移量,注意从 0 开始
  • 第二个参数指定返回记录行的最大数目
  • 如果只给定一个参数:它表示返回最大的记录行数目
  • 第二个参数为 -1 表示检索从某一个偏移量到记录集的结束所有的记录行(目前 MySQL 已经不支持这种语法了)
  • 初始记录行的偏移量是 0 (而不是 1)

# SQL 的执行顺序⭐️

  1. FROM 子句:
    • 查询首先从 FROM 子句开始,确定要检索数据的表。
    • 确定要检索数据的表或多个表的组合。
  2. JOIN 子句:
    • 在选择的表中,根据 JOIN 子句中的条件,将相关联的行连接在一起。JOIN 的执行顺序可能受到优化器的干预,选择最优的连接方式。
  3. ON 子句:
    • (如果使用了 JOIN)用于指定连接表时的条件,决定了哪些行应该被包含在结果集中。
  4. WHERE 子句:
    • 接着,在 FROM 和 JOIN 的基础上,根据 WHERE 子句中的条件对表进行筛选,只保留符合条件的行。
  5. GROUP BY 子句:
    • 根据指定的 GROUP BY 列对数据进行分组。
  6. HAVING 子句:
    • 类似于 WHERE,但作用于 GROUP BY 的结果,用于过滤组。
    • 对【分组后的结果集】进行进一步的过滤,条件通常与聚合函数(如 COUNT, SUM 等)一起使用。
  7. SELECT 子句:
    • 根据 SELECT 子句中的列,选择要返回的结果列。
    • 确定要返回的列或计算结果,包括聚合函数和表达式。
  8. DISTINCT 子句:
    • 用于去除 SELECT 语句结果集中的重复行。
  9. ORDER BY 子句:
    • 如果有 ORDER BY 子句,则对结果集进行排序。
  10. LIMIT 子句:
  • 用于限制返回结果集的行数(仅在某些数据库系统中,如 MySQL)。
  1. OFFSET 子句:
    • 与 LIMIT 子句一起使用,用于指定返回结果集的起始行(仅在某些数据库系统中)。
    • 常用于分页(传统分页,游标分页)
  2. UNION/UNION ALL 子句:
    • 将多个 SELECT 语句的结果集合并在一起,去除重复的行(UNION)或包含所有行(UNION ALL)。

# 正则表达式查询

参考:MySQL 正则表达式 | 菜鸟教程 (runoob.com) (opens new window)

# select 1

SELECT 1:用于快速检查记录是否存在,而不需要读取和返回实际的数据行。

  • 用途:主要用于检查记录的存在性、性能优化、锁定行、测试连接等。
  • 优点:减少数据传输量,提高查询性能,简化逻辑判断。

示例:

-- 判断是否存在符合条件的数据
-- 结合 LIMIT 1 使用时,一旦找到一条匹配的记录,查询就会立即停止,从而进一步提高性能。
SELECT 1
FROM large_table
WHERE some_column = 'some_value';
LIMIT 1;

-- 测试连接
SELECT 1;
1
2
3
4
5
6
7
8
9

# 学习参考

  • 面试官:数据量很大,分页查询很慢,有什么优化方案? - 知乎 (zhihu.com) (opens new window)
  • SQL进阶技巧——CASE表达式全解! - 知乎 (zhihu.com) (opens new window)
  • SQL中的cast()函数_cast sql-CSDN博客 (opens new window)
上次更新: 2025/1/6 17:59:10
临时表
JOIN 解析

← 临时表 JOIN 解析→

Theme by Vdoing | Copyright © 2023-2025 沉梦听雨 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式