MySql中各种功能用sql语句实现总结

目录

1.排序和分页

2.聚合统计与分组

3.数据增删改(DML)

4.判断表是否存在指定字段

5.向数据库中的每个表都增加或删除一个字段

6.字符串合并(拼接)

[6.1.单行拼接(同一条数据内,多字段 / 文本合并)](#6.1.单行拼接(同一条数据内,多字段 / 文本合并))

6.2.多行合并(多条记录,按分组拼接成一行)

7.字符串查找

7.1.精确匹配(FIND_IN_SET)

7.2.模糊匹配

后续待加...


1.排序和分页

1.排序(ORDER BY)

cpp 复制代码
-- 升序(ASC,默认)、降序(DESC)
SELECT * FROM user ORDER BY age ASC;
SELECT * FROM user ORDER BY create_time DESC;

-- 多字段排序(先按年龄降序,年龄相同按创建时间升序)
SELECT * FROM user ORDER BY age DESC, create_time ASC;

2.分页(LIMIT)

cpp 复制代码
-- LIMIT 起始索引, 每页条数(起始索引从0开始)
-- 第1页,10条数据
SELECT * FROM user LIMIT 0,10;

-- 第2页,10条数据
SELECT * FROM user LIMIT 10,10;

2.聚合统计与分组

1.常用聚合函数

cpp 复制代码
-- 统计数量
SELECT COUNT(*) FROM user;        -- 统计总行数
SELECT COUNT(email) FROM user;    -- 统计非空email数量

-- 求和/平均值/最大/最小值
SELECT SUM(age) FROM user;
SELECT AVG(age) FROM user;
SELECT MAX(age) FROM user;
SELECT MIN(age) FROM user;

2.分组统计(GROUP BY)

核心GROUP BY 后只能跟分组字段 + 聚合函数

cpp 复制代码
-- 按性别统计人数
SELECT gender, COUNT(*) AS 人数 FROM user GROUP BY gender;

-- 按城市统计平均年龄
SELECT city, AVG(age) AS 平均年龄 FROM user GROUP BY city;

3.分组后筛选(HAVING)

区别WHERE 筛选原始数据HAVING 筛选分组后结果

cpp 复制代码
-- 统计人数大于5的城市
SELECT city, COUNT(*) AS 人数 
FROM user 
GROUP BY city 
HAVING COUNT(*) > 5;

3.数据增删改(DML)

1.插入数据(INSERT)

cpp 复制代码
-- 单条插入
INSERT INTO user(name, age, gender) VALUES ('张三', 20, '男');

-- 批量插入(性能更高)(高效推荐)
INSERT INTO user(name, age, gender) 
VALUES ('李四',21,'女'),('王五',22,'男');

2.更新数据(UPDATE)

必须加 WHERE 条件,否则全表更新!

cpp 复制代码
-- 条件更新
UPDATE user SET age = 21, email = 'xxx@163.com' WHERE id = 1;

3.删除数据(DELETE/TRUNCATE)

cpp 复制代码
-- 条件删除
DELETE FROM user WHERE id = 1;

-- 清空全表(不可回滚,速度远快于DELETE)
TRUNCATE TABLE user;

4.插入或更新数据

INSERT ... SET + ON DUPLICATE KEY UPDATE 标准写法

MySQL 支持 INSERT INTO 表 SET 字段=值 语法,可直接拼接 ON DUPLICATE KEY UPDATE依赖主键 / 唯一索引冲突触发更新

cpp 复制代码
INSERT INTO `table_name`
SET
    id = 1,
    username = 'test',
    age = 20
ON DUPLICATE KEY UPDATE
    username = 'test',
    age = 20;

5.查询结果插入(INSERT ... SELECT)

将一个查询结果集批量插入目标表,适合数据迁移 / 复制:

cpp 复制代码
-- 替换:库名、表名、字段名
SELECT COUNT(*)
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = '数据库名'
  AND TABLE_NAME = '表名'
  AND COLUMN_NAME = '字段名';

如:

cpp 复制代码
-- 复制部门10的员工到新表
INSERT INTO new_employees(id, name, dept)
SELECT id, name, 20 FROM employees 
WHERE dept = 10;

支持复杂子查询、JOIN 与聚合函数。

4.判断表是否存在指定字段

查询 information_schema(通用,推荐)

cpp 复制代码
-- 替换:库名、表名、字段名
SELECT COUNT(*)
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = '数据库名'
  AND TABLE_NAME = '表名'
  AND COLUMN_NAME = '字段名';

返回>0:字段存在;=0:不存在

示例:

cpp 复制代码
SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'testdb'
AND TABLE_NAME = 'user'
AND COLUMN_NAME = 'phone';

5.向数据库中的每个表都增加或删除一个字段

1.增加字段

先判断表中是否有这个字段,没有则增加,有则跳过,sql语句如下:

cpp 复制代码
-- 如果存储过程存在则删除
DROP PROCEDURE IF EXISTS add_username_all_table;

DELIMITER $$ /*修改语句结束符为$$,类似sql server中的go语句*/

--db_name :数据库名称
--col_name :字段名
CREATE PROCEDURE add_username_all_table(IN db_name VARCHAR(64), IN col_name VARCHAR(64))
BEGIN
    DECLARE done INT DEFAULT 0;
    DECLARE tb_name VARCHAR(64);
    -- 游标:查询指定库下所有数据表
    DECLARE cur_tb CURSOR FOR
        SELECT TABLE_NAME FROM information_schema.TABLES
        WHERE TABLE_SCHEMA = db_name AND TABLE_TYPE='BASE TABLE';
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=1;

    OPEN cur_tb;
    tb_loop:LOOP
        FETCH cur_tb INTO tb_name;
        IF done=1 THEN LEAVE tb_loop; END IF;

        -- 判断字段是否存在
        SET @is_exist = (SELECT COUNT(*) FROM information_schema.COLUMNS
            WHERE TABLE_SCHEMA=db_name AND TABLE_NAME=tb_name AND TABLE_NAME<>'usertable' AND COLUMN_NAME=col_name);

        -- 不存在则添加字段,varchar(50)可自行修改类型
        SET @sql = IF(@is_exist=0,
            CONCAT('ALTER TABLE `',db_name,'`.`',tb_name,'` ADD COLUMN `',col_name,'` VARCHAR(255) NOT NULL COMMENT \'*unVisible\';'),
            'SELECT 1;');
        PREPARE stmt FROM @sql;
        EXECUTE stmt;
        DEALLOCATE PREPARE stmt;
    END LOOP tb_loop;
    CLOSE cur_tb;
END$$

DELIMITER ; /*改回默认分号结束符*/

--调用此过程
CALL add_username_all_table('xxxxxx', 'userName');

2.删除字段

cpp 复制代码
DROP PROCEDURE IF EXISTS drop_column_all_tables;

DELIMITER $$ /*修改语句结束符为$$,类似sql server中的go语句*/

--db_name :数据库名称
--col_name :字段名
CREATE PROCEDURE drop_column_all_tables(IN db_name VARCHAR(64), IN col_name VARCHAR(64))
BEGIN
    DECLARE done INT DEFAULT 0;
    DECLARE tb_name VARCHAR(64);

    DECLARE cur_tb CURSOR FOR
        SELECT TABLE_NAME FROM information_schema.`TABLES`
        WHERE TABLE_SCHEMA = db_name AND TABLE_TYPE='BASE TABLE';

    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=1;

    OPEN cur_tb;
    tb_loop:LOOP
        FETCH cur_tb INTO tb_name;
        IF done=1 THEN LEAVE tb_loop; END IF;

        -- 判断字段是否存在
        SET @is_exist = (SELECT COUNT(*) FROM information_schema.COLUMNS
            WHERE TABLE_SCHEMA=db_name AND TABLE_NAME=tb_name AND TABLE_NAME<>'usertable' AND COLUMN_NAME=col_name);

        -- 存在则删除字段
        SET @sql = IF(@is_exist>0,
            CONCAT('ALTER TABLE `',db_name,'`.`',tb_name,'` DROP COLUMN `',col_name,'`;'),
            'SELECT 1;');
        PREPARE stmt FROM @sql;
        EXECUTE stmt;
        DEALLOCATE PREPARE stmt;
    END LOOP tb_loop;
    CLOSE cur_tb;
END$$

DELIMITER ; /*改回默认分号结束符*/

-- 调用示例:删除 xxxxx 库中所有表的 userName 字段
CALL drop_column_all_tables('xxxxxx', 'userName');

6.字符串合并(拼接)

MySQL 字符串拼接分单行多字段拼接多行数据合并为一行 两大场景,常用函数:CONCATCONCAT_WSGROUP_CONCAT,MySQL 8.0+ 还支持标准函数 STRING_AGG

先准备测试表 + 测试数据,后续所有示例共用:

cpp 复制代码
-- 创建测试表
CREATE TABLE `user` (
  id INT,
  name VARCHAR(20),
  dept VARCHAR(20),
  city VARCHAR(20),
  phone VARCHAR(20)
);

-- 插入测试数据(包含 NULL 场景)
INSERT INTO `user` VALUES
(1,'张三','技术部','北京','13800138000'),
(2,'李四','技术部','上海',NULL),
(3,'王五','市场部','广州','13900139000'),
(4,'赵六','市场部','广州','13900139000'),
(5,'钱七','人事部',NULL,'13700137000');

6.1.单行拼接(同一条数据内,多字段 / 文本合并)

适用于:一条记录里,把多个字段、固定文字拼接成一个字符串。

1.CONCAT(str1,str2,...) 基础拼接

cpp 复制代码
CONCAT(字符串1, 字符串2, 字符串3 ...)
  • 支持多个参数拼接;
  • 只要任意一个参数为 NULL,整体结果直接返回 NULL(最大坑点)。
cpp 复制代码
-- 拼接:姓名 + 固定符号 + 城市
SELECT CONCAT(name, ' / ', city) AS user_info FROM `user`;

-- 包含 NULL 字段演示(李四的phone为NULL,整条结果为NULL)
SELECT name, CONCAT(name, phone) AS name_phone FROM `user`;

2.CONCAT_WS(分隔符, str1, str2,...) 带分隔符拼接

WS = With Separator,生产环境首选 ,完美规避 NULL 问题。

cpp 复制代码
CONCAT_WS(分隔符, 字段1, 字段2, 字段3 ...)
  • 第一个参数固定为分隔符
  • 自动跳过值为 NULL 的字段 ,不会因为 NULL 导致整体为空;
  • 不会产生多余的分隔符。
cpp 复制代码
-- 用 | 拼接 姓名、城市、手机号(李四手机号为NULL,自动忽略)
SELECT 
  name,
  CONCAT_WS(' | ', name, city, phone) AS full_info 
FROM `user`;

-- 拼接固定文本 + 字段
SELECT CONCAT_WS(':', '姓名', name) AS name_label FROM `user`;

6.2.多行合并(多条记录,按分组拼接成一行)

适用于:分组后,把一组内多条行数据的字段合并为单个字符串(行转列)。

1.GROUP_CONCAT() 全版本通用(MySQL 所有版本支持)

cpp 复制代码
GROUP_CONCAT( [DISTINCT] 字段 
              [ORDER BY 排序字段] 
              [SEPARATOR '自定义分隔符'] )
  • DISTINCT:去重;
  • ORDER BY:拼接前对内容排序;
  • SEPARATOR:指定分隔符,默认逗号 ,

示例:基础用法:按部门合并员工姓名(默认逗号分隔)

cpp 复制代码
SELECT 
  dept,
  GROUP_CONCAT(name) AS emp_names 
FROM `user` 
GROUP BY dept;

自定义分隔符(改用分号 ;

cpp 复制代码
SELECT 
  dept,
  GROUP_CONCAT(name SEPARATOR ';') AS emp_names 
FROM `user` 
GROUP BY dept;

拼接前排序:

cpp 复制代码
-- 按姓名升序后再拼接
SELECT 
  dept,
  GROUP_CONCAT(name ORDER BY name SEPARATOR ',') AS emp_names 
FROM `user` 
GROUP BY dept;

拼接时去重:

cpp 复制代码
-- 合并同部门的手机号,并去重
SELECT 
  dept,
  GROUP_CONCAT(DISTINCT phone SEPARATOR ',') AS phone_list 
FROM `user` 
GROUP BY dept;

2.STRING_AGG(字段, 分隔符)(MySQL 8.0+ 新函数)

SQL 标准拼接函数,语法更简洁,无默认长度限制,推荐 8.0 及以上版本使用。

cpp 复制代码
STRING_AGG(字段, '分隔符' [ORDER BY 排序字段])
cpp 复制代码
-- 按部门合并姓名,逗号分隔
SELECT 
  dept,
  STRING_AGG(name, ',') AS emp_names 
FROM `user` 
GROUP BY dept;

-- 带排序
SELECT 
  dept,
  STRING_AGG(name, ',' ORDER BY name DESC) AS emp_names 
FROM `user` 
GROUP BY dept;

7.字符串查找

判断表中某一列的单个值,是否存在于另一列 / 指定的逗号分隔字符串中 ,分精确匹配(逗号分隔独立项,业务主流)模糊匹配(纯文本包含) 两大类。

先统一准备测试表和数据,所有示例共用:

cpp 复制代码
-- 表1:存储单个值(待匹配列)
CREATE TABLE `user` (
  id INT,
  name VARCHAR(20)
);
INSERT INTO `user` VALUES
(1,'张三'),
(2,'李四'),
(3,'王五'),
(4,'赵六'),
(5,'张三三'); -- 用于测试模糊匹配坑点

-- 表2:存储逗号分隔字符串(目标字符串列)
CREATE TABLE `article` (
  aid INT,
  title VARCHAR(50),
  tag_list VARCHAR(100) -- 逗号分隔字符串
);
INSERT INTO `article` VALUES
(1,'文章1','张三,李四,王五'),
(2,'文章2','李四,赵六'),
(3,'文章3',',王五,钱七,'), -- 首尾带逗号
(4,'文章4',''),            -- 空字符串
(5,'文章5',NULL);          -- NULL 值

7.1.精确匹配(FIND_IN_SET)

列值是逗号字符串里的完整独立项 (比如标签、多选 ID、人员名单),这是逗号分隔串最常用场景。 MySQL 专用函数:FIND_IN_SET()专门适配逗号分隔列表,全版本兼容,无子串误匹配问题。

cpp 复制代码
FIND_IN_SET( 待查找的值, 逗号分隔字符串 )

返回规则:

  • 匹配到独立项:返回所在位置(1、2、3...)
  • 未匹配到:返回 0
  • 任意一个参数为 NULL:返回 NULL

判断条件:FIND_IN_SET(...) > 0 代表找到。

示例如下:查询 user 表中 name 存在于固定字符串 '张三,李四,王五' 的数据:

cpp 复制代码
SELECT * FROM `user`
WHERE FIND_IN_SET(name, '张三,李四,王五') > 0;

同表内,A 列值 匹配 本表 B 列逗号串,查询 article 表中,固定值 王五 存在于 tag_list 的行:

cpp 复制代码
SELECT * FROM `article`
WHERE FIND_IN_SET('王五', tag_list) > 0;

两表联查,关联 userarticle,找出 user.name 存在于 article.tag_list 的关联数据:

cpp 复制代码
SELECT u.*, a.title, a.tag_list
FROM `user` u
JOIN `article` a 
  ON FIND_IN_SET(u.name, a.tag_list) > 0;

边界问题处理:

1.字段值带空格

如果数据存在前后空格(如 ' 张三 '),先用 TRIM() 去空格:

cpp 复制代码
SELECT * FROM `user`
WHERE FIND_IN_SET(TRIM(name), '张三,李四,王五') > 0;

2.空字符串 / NULL

  • tag_list = ''(空串):FIND_IN_SET 返回 0,自动过滤;
  • tag_list = NULLFIND_IN_SET 返回 NULL,WHERE 条件不成立,自动过滤; 无需额外判断。

3.分隔符不是逗号

FIND_IN_SET 仅支持逗号,如果是分号、竖线、空格等分隔符,先替换成逗号再使用:

cpp 复制代码
-- 原分隔符为 ; ,先替换为 ,
SELECT * FROM `article`
WHERE FIND_IN_SET('王五', REPLACE(tag_list, ';', ',')) > 0;

7.2.模糊匹配

不要求是独立项,只要字符串中包含该列的字符 (纯文本检索,和分隔符无关)。 适用函数:LIKEINSTRLOCATE

1.LIKE 写法(最直观)

使用 % 通配符表示模糊匹配:

cpp 复制代码
-- 匹配:name 出现在 tag_list 任意位置
SELECT u.*, a.tag_list
FROM `user` u
JOIN `article` a
WHERE a.tag_list LIKE CONCAT('%', u.name, '%');

重大坑点 :会出现子串误匹配 例如 name='张三三',也会匹配到 tag_list='张三,李四',因为文本包含「张三」。

只要是逗号分隔的选项列表,坚决不要用模糊匹配。

2.INSTR / LOCATE 写法(等价 LIKE,性能略优)

INSTR (原字符串,查找内容)

返回字符所在位置,0 = 未找到:

cpp 复制代码
SELECT * FROM `article`
WHERE INSTR(tag_list, '张三') > 0;

LOCATE (查找内容,原字符串)

参数顺序和 INSTR 相反,功能一致:

cpp 复制代码
SELECT * FROM `article`
WHERE LOCATE('张三', tag_list) > 0;

后续待加...

相关推荐
数据库小学妹1 小时前
AI时代数据库怎么选?多模融合、数据统一存储与选型实战指南
数据库·人工智能·经验分享·ai
Albert Edison1 小时前
【Redis】Centos7.9 安装 Redis 5 教程
数据库·redis·缓存
云计算磊哥@2 小时前
运维开发宝典026-MySQL02数据库表操作
运维·数据库·运维开发
小二·2 小时前
Redis 内存溢出(OOM)排查与恢复实战
数据库·redis·bootstrap
pqk6V6Vep2 小时前
Redis 分布式锁进阶第一篇讲解
数据库·redis·分布式
giaz14n9X2 小时前
Redis 分布式锁进阶第六十一篇
数据库·redis·分布式
是一个Bug2 小时前
MongoDB:像搭积木一样存数据
数据库·mongodb
ULIi096kr3 小时前
MySQL解决Too many connections报错:连接数爆满排查、优化与永久解决方案
数据库·mysql·adb
SL-staff3 小时前
(一)数据源配置 —— JVS-Rules规则引擎 V2.5 操作说明介绍
数据库·jar·规则引擎·数据源·jvs-rules·api 接口·jvs低代码