MySQL【sql之DML】

本文详细介绍了SQL语言的四大组成部分:DDL(数据定义语言)、DML(数据操纵语言)、DQL(数据查询语言)和DCL(数据控制语言)之一的DML(数据操纵语言)。

数据库使用时,大多数情况下,开发者只会操作数据,核心是就增删改查(CRUD), 增删改查四条语句,最重要的是查询(DQL)

增加语句

增加语言,就是给某张表进行数据插入。

语法:

sql 复制代码
insert INTO table_name[(field1 [, field2 ......]) values(value1 [, vaule2 ......])  [,()]];

案例演示:

sql 复制代码
insert into t_user(name, password) values("zxy", "hehhehe");
Query OK, 1 row affected (0.01 sec)


mysql> INSERT INTO t_user value(null, "xixi", 16, "123456");
Query OK, 1 row affected (0.01 sec)

mysql> insert into t_user(password, name) values("abcd", "haha");
Query OK, 1 row affected (0.01 sec)

--插入多表数据
mysql> insert into t_user(name, password) value("yuyu1", "afaf"), ("ouou", "hfvha");
Query OK, 2 rows affected (0.01 sec)
Records: 2  Duplicates: 0  Warnings: 0

删除语句和TRUNCATE

删除语言,请注意删除的条件!!!如果不带条件,则删除全表。

语法结构:

sql 复制代码
delete from table_name [where 条件];
truncate table table_name;

区别

  1. 性能TRUNCATE TABLEDELETE FROM 快,因为 DELETE FROM 是逐行删除,并在事务日志中记录每行的删除,而 TRUNCATE TABLE 只记录页的释放。

  2. 事务处理DELETE FROM 可以回滚(ROLLBACK),而 TRUNCATE TABLE 不能回滚。

  3. 触发器TRUNCATE TABLE 不会触发 DELETE 触发器,而 DELETE FROM 会触发。

  4. 外键约束 :对于由外键约束引用的表,不能使用 TRUNCATE TABLE ,而应使用不带 WHERE 子句的 DELETE FROM

  5. 标识列TRUNCATE TABLE 会重置标识列的计数值,而 DELETE FROM 不会。

案例演示:

sql 复制代码
delete from t_user where id=4;

-- 如果没有条件,则清空全表数据【慎重!!】
delete from user;


-- truncate清空全表[注意:truncate删除数据是不经过数据字典]
truncate table students;

更新语句

更新就是修改表中的数据。

语法结构:

sql 复制代码
update table_name set 字段1=新值 [, 字段2=新值, 字段3=字段3 + 1]   [where 条件];

案例演示:

sql 复制代码
update t_user set age = 30 where id = 7;

update t_user set age = 20, password="root" where id = 28;

update t_user set age = age + 1 ;

replace语句

该语句是集更新和插入为一体的一个语句。

如果表中没有这条数据,则执行插入,否则执行更新。

注意:replace的更新,本质是先删除,再插入。

sql 复制代码
replace into t_user(id, name, password) values(100, "test", "test");
replace into t_user(id, name, password) values(100, "testtest", "testtest");

select查询语句

在开发中,查询语句是使用最多,也是CRUD中,复杂度最高的sql语句。

查询的语法结构

select *|字段1 [, 字段2 ......] from 表名称 [, 表名称2......] [where 条件] [group by 字段 [having 分组后的筛选]] [order by 字段 [desc|asc] [字段2 [desc|asc] ......]] [limit 分页]

简单的sql查询,案例演示:

sql 复制代码
-- 查询所有数据
select * from t_user;

-- 查询需要的字段信息
select id, name, password from t_user;

-- 查询一个字段,一个等值条件
select name from t_user where id = 1;

select 字段列表 from 表名称 where 条件


/*
 等值查询
*/
select password from t_user where name="zxy";
select * from t_user where age = 19;
alter table t_user add birthday datetime default now();
select * from t_user where birthday='2025-03-13 20:52:12';

由于案列表里没有birthday字段,我们在这里添加一个dirthday字段,并更新一些数据
sql 复制代码
-- 修改表结构,添加字段名为birthday的列
mysql> alter table t_user add birthday datetime default now();
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0
sql 复制代码
 -- 更新表数据
UPDATE t_user SET birthday = '1990-01-01' WHERE id = 7;

select语句中的特殊情况:

sql 复制代码
对数值型数据列、变量、常量可以使用算数操作符创建表达式(+ - * /)
对日期型数据列、变量、常量可以使用部分算数操作符创建表达式(+ -)
运算符不仅可以在列和常量之间进行运算,也可以在多列之间进行运算。
	SELECT last_name, salary, salary*12
	FROM employees;
	
补充:+ 说明
-- MySQL的+默认只有一个功能:运算符
SELECT 100+80; # 结果为180
SELECT '123'+80; # 只要其中一个为数值,则试图将字符型转换成数值,转换成功做预算,结果为203
SELECT 'abc'+80; # 转换不成功,则字符型数值为0,结果为80
SELECT 'This'+'is'; # 转换不成功,结果为0
SELECT 'This'+'30is'; # ?猜测下这个结果是多少?
SELECT NULL+80; # 只要其中一个为NULL,则结果为NULL

等值判断

  • = 判断两次的值是否相等

  • is 判断空null

  • is not null来判断不为空

  • <=> 可以判断null或者普通值

不等判断

  • != 不等于

  • <>也是不等于

逻辑运算符

逻辑运算符是多条件关联的一种方式。

与或非

  • and

  • or

  • not

注意:在sql中,如果要提升条件的运行顺序,或者提高条件的优先级别 ,则需要使用括号来提升

查询时的别名使用(用as指定别名)

查询时,将结果的显示字段,使用一个其他名称来代替,就是别名。

常见的条件查询

sql 复制代码
使用IN运算符获得匹配列表值的记录
    SELECTemployee_id, last_name, salary, manager_id
    FROM employees
    WHERE manager_id IN (7902, 7566, 7788);
    
使用LIKE运算符
  使用LIKE运算符执行模糊查询
  查询条件可包含文字字符或数字
  (%) 可表示零或多个字符
  ( _ ) 可表示一个字符
    SELECT last_name
    FROM employees
    WHERE last_name LIKE '_A%';
    
使用IS NULL运算符
  查询包含空值的记录
      SELECT last_name, manager_id
      FROM employees
      WHERE manager_id IS NULL;
  
  
  逻辑运算符
  使用AND运算符
    AND需要所有条件都是满足T.
    
    SELECT employee_id, last_name, job_id, salary
    FROM employees
    WHERE salary>=1100--4 AND job_id='CLERK';
  使用OR运算符
    OR只要两个条件满足一个就可以
  
    SELECT employee_id, last_name, job_id, salary
    FROM employees
    WHERE salary>=1100 OR job_id='CLERK';
  使用NOT运算符
    NOT是取反的意思
    	SELECT last_name, job_id
        FROM employees
        WHERE job_id NOT IN ('CLERK','MANAGER','ANALYST');
        
        
  使用正则表达式:REGEXP
  	<列名> regexp '正则表达式'
  	select * from product where product_name regexp '^2018';

分组

sql中,分组是一种统计概念。查询的数据,进行数据分析时,可能需要将相同的数据分成一组。

条件后面,当然是存在条件时,不过不存在,则是表名称后面

注意:分组查询时,查询字段必须是分组的字段,或者是聚合函数

group by 字段

案例演示:

sql 复制代码
mysql> select gender from t_hero group by gender;
+--------+
| gender |
+--------+
| 男     |
| 女     |
+--------+
2 rows in set (0.00 sec)

mysql> select gender,count(gender) from t_hero group by gender;
+--------+---------------+
| gender | count(gender) |
+--------+---------------+
| 男     |            14 |
| 女     |             2 |
+--------+---------------+
2 rows in set (0.00 sec)

分组后的筛选

发现,如果直接在分组后的结果集上进行条件判断,将条件写在where中,会报错,因为:结果集是分组后才能做的判断,而where实在查询前的条件判断。

所以不能使用where,必须使用having。

再次强调,having必须写在group by之后!!!没有分组,就不能写having,但是分组可以没有having。

案例演示:

sql 复制代码
mysql> select gender ,count(gender) from t_hero group by gender having count(gender) > 5;
+--------+---------------+
| gender | count(gender) |
+--------+---------------+
| 男     |            14 |
+--------+---------------+
1 row in set (0.00 sec)

结果排序

将查询结果,以特定的顺序展示(升序或者降序

语法结构:

sql 复制代码
order by 字段 
order by 字段 asc|desc;
order by 字段 asc|desc, 字段2 ;

案例演示:

sql 复制代码
-- 升序排序
select * from t_user order by age asc;

-- 降序排序
select * from t_user order by age desc;

分页查询

select语句,查询数据时,可能结果会非常多,此时就不能直接展示,分页展示。

总数量(all_data):查询 select count(*)

每页展示的数量(page_size):程序员定

当前页(cur_page):默认第一页,用户自己点击选择

总页数(all_page):总数量 % 每页的数量 == 0 整除后的商 : 商 + 1

sql 复制代码
limit num  # 查询多少条

limit num1, num2; # num1: 偏移量, num2 : 每页的数量  

limit cur_page * (page_size - 1), page_size;

分表查询

数据直接都存储在一张表中:

  • 如果数据很大,性能会出现问题

  • 将不同的数据,如果放在同一个表中,可能数据冗余

  • 数据冗余,会导致数据可能出错

将不同的类型,采用不同的数据表进行存储,如果两张表或者多张表之间存在关联关系,则可以采用外键来描述这种关联关系。

外键作为主表的一个字段,这个外键一般是从表的主键,因为从表的主键一般不会轻易更改

案例:

sql 复制代码
--主表
create table grade(
	id int auto_increment,
    name varchar(50) unique,
    primary key(id)  -- 主键
)
insert into grade(name) value("Java精品班"), ("python数据分析班"), ("网络安全班"), ("云原生高级班");

--从表
create table student(
     id int primary key auto_increment,
     name varchar(50) unique,
     gender enum("F", "M"),
     age int default 18,
     adddress varchar(255),
     class_id int   -- 外键
    );
Query OK, 0 rows affected (0.06 sec)

mysql> desc student;
+----------+---------------+------+-----+---------+----------------+
| Field    | Type          | Null | Key | Default | Extra          |
+----------+---------------+------+-----+---------+----------------+
| id       | int           | NO   | PRI | NULL    | auto_increment |
| name     | varchar(50)   | YES  | UNI | NULL    |                |
| gender   | enum('F','M') | YES  |     | NULL    |                |
| age      | int           | YES  |     | 18      |                |
| adddress | varchar(255)  | YES  |     | NULL    |                |
| class_id | int           | YES  |     | NULL    |                |
+----------+---------------+------+-----+---------+----------------+
6 rows in set (0.00 sec)

insert into student(name, class_id) values("张三", 1);
insert into student(name, class_id) values("张三2", 2);
insert into student(name, class_id) values("张三3", 1);
insert into student(name, class_id) values("张三4", 3);
insert into student(name, class_id) values("张三5", 1);
insert into student(name, class_id) values("张三6", 4);


-- 此时,插入了一条错误数据,该数据描述的外键不存在,是一条错误数据!!!
insert into student(name, class_id) values("张三666", 44);

# 如果要避免出现这种情况,必须加入外键约束!!

外键和多表关联

外键:指的是两张或者多张表之间关联关系的字段。

外键约束:是表的约束,是约束表在插入外键数据时能够正确的插入。

如何添加约束:

在创建表的同时,将外键约束添加上去

首先保证班级表创建成功

插入正确的数据

create table grade(

id int auto_increment,

name varchar(50) unique,

primary key(id)

)

insert into grade(name) value("Java精品班"), ("python数据分析班"), ("网络安全班"), ("云原生高级班");

外键约束

外键是构建于一个表的两个字段或者两个表的两个字段之间的关系

外键确保了相关的两个字段的两个关系:

子(从)表外键列的值必须在主表参照列值的范围内,或者为空(也可以加非空约束,强制不允许为空)。

当主表的记录被子表参照时,主表记录不允许被删除。

外键参照的只能是主表主键或者唯一键,保证子表记录可以准确定位到被参照的记录。

外键约束创建的两种方式

方法一:通过在已经创建好的表中修改的方式来添加外键约束

ALTER TABLE 表名 ADD CONSTRAINT 外键名 FOREIGN KEY(外键字段名)

方法二:在创建表的同时创建外键约束

FOREIGN KEY (外键列名)REFERENCES 主表(参照列)

sql 复制代码
create table student(
     id int primary key auto_increment,
     name varchar(50) unique,
     gender enum("F", "M"),
     age int default 18,
     adddress varchar(255),
     class_id int,  
     foreign key(class_id) references grade(id)       --外键约束 
     );

案例:这里想插入class_id=44,因为外键约束关联了grade表,而grade表主键最大为4,所有这里报错了

ON DELETE {RESTRICT \| CASCADE \| SET NULL \| NO ACTION \| SET DEFAULT}

该子句用于定义当父表中的记录被删除时,子表中相关记录的处理方式

ON UPDATE {RESTRICT \| CASCADE \| SET NULL \| NO ACTION \| SET DEFAULT}

该子句用于定义当父表中的记录被更新时,子表中相关记录的处理方式

子表中相关记录的处理方式,有以下几种选项:

1. RESTRICT

当父表中的记录的主键值被更新时,如果子表中存在与之关联的记录,数据库会拒绝更新操作,并抛出一个错误。

2. CASCADE

当父表中的记录的主键值被更新时,数据库会自动更新子表中所有与之关联的记录的外键值。

3. SET NULL

当父表中的记录的主键值被更新时,子表中与之关联的记录的外键列会被设置为 NULL。前提是外键列允许为 NULL

4. NO ACTION
在 SQL 标准中,NO ACTIONRESTRICT 类似。在大多数数据库系统中,当执行更新操作时,数据库会检查子表中的关联记录,但不会立即采取行动。如果在事务结束时仍然存在关联记录,更新操作将被拒绝。
5. SET DEFAULT

当父表中的记录的主键值被更新时,子表中与之关联的记录的外键列会被设置为其默认值。前提是外键列有默认值。

表与表之间的关联关系

当表与表之间存在了外键,这就意味着,这两张表之间存在某种关联关系。

一旦表存在了关联关系,则会进行外键设计,如果设计外键,将外键设计在哪张表中?

  • 一对一 :外键可以设计在任意一张表中

  • 一对多 :外键必须设计在多方

  • 多对多 :创建第三张表,来专门描述两张表的关联关系

多表关联查询

当两张或者多张表之间存在了关联关系,往往多表查询,如果查询。

  • 交叉连接

  • 内连接

  • 外链接

    • 左外连接

    • 右外连接

  • 自连接

  • 全连接

  • 自然连接 【不建议使用,直到就行】数据库自动使用相同字段名称完成外键关联

sql 复制代码
-- 交叉连接(cross join),
-- 在查询多表时,不指定表的关联关系,数据只能全部匹配,引发笛卡尔积现象
 select * from student, grade;
 -- sql98的标准写法
 select * from student cross join grade;
 
 # 内连接(一般情况下使用)
 select * from student, grade where student.class_id  = grade.id;
 select * from student, grade where student.class_id  = grade.id and student.name = '张三';

# 注意:sql98的内连接方式时,如果不指定关联条件,不管怎么写,都是交叉连接
select * from student inner join grade;
select * from student join grade;

# 正确写法,必须写清楚关联条件
select * from student inner join grade on (student.class_id=grade.id);
select * from student join grade on (student.class_id=grade.id) where student.name = "张三3";
# 内连接,只能查询出,存在关联关系的数据,如果不存在关联关系,如目前没有班级的学生,目前没有学生的班级
select * from student cross join grade on (student.class_id=grade.id) where student.name = "张三3";

# 如果要将这些没关联关系的数据查询出来,则需要使用外连接
select * from student left join grade on (student.class_id=grade.id);
select * from student right join grade on (student.class_id=grade.id);

# 注意:mysql不支持全连接查询  full  join

# 但是SQL存在联合查询  union 、union all
# 注意:联合查询,必须保证查询的多条SQL返回的结果 结构必须一致,所以联合查询常见于查询一张表
(select * from student where class_id = "1") union (select id, name from student where id > 3);
(select * from student where class_id = "1") union all (select * from student where id > 3);

# 自连接查询

# 表的外键指向自身
create table board (
	id int primary key auto_increment,
	name varchar(50) unique not null,
	intro text,
	parent_id int,
	foreign key(parent_id) references board(id)
);
insert into board(name, parent_id) values("前端板块", null);
insert into board(name, parent_id) values("后端板块", null);
insert into board(name, parent_id) values("硬件板块", null);
insert into board(name, parent_id) values("html", 1);
insert into board(name, parent_id) values("css", 1);
insert into board(name, parent_id) values("java", 2);
insert into board(name, parent_id) values("python", 2);
insert into board(name, parent_id) values("嵌入式", 3);
insert into board(name, parent_id) values("python基础", 7);
insert into board(name, parent_id) values("django", 7);
insert into board(name, parent_id) values("python GUI开发", 7);
insert into board(name, parent_id) values("css2", 5);
insert into board(name, parent_id) values("css3", 5);


select name from board where parent_id is null;

select name from board where parent_id = (select id from board where name = "前端板块");
select * from board as b, (select id from board where name = "前端板块") as t where b.parent_id = t.id;
select name from (select * from board where parent_id is not null) as t where t.parent_id in (1, 2, 3);
 

笛卡尔积现象:当进行多张表联合查询的时候,在没有任何条件进行限制情况下,最终查询结果条数是多张表记录条数的乘积

例如:

select *|字段 [,......] from 表名称 [,表名称] ......

SQL中函数

聚合函数

聚合函数对一组值进行运算,并返回单个值。也叫组合函数。

COUNT(*|列名) 统计行数

AVG(数值类型列名) 平均值

SUM (数值类型列名) 求和

MAX(列名) 最大值

MIN(列名) 最小值

除了COUNT()以外,聚合函数都会忽略NULL值。

函数名称 作用
MAX 查询指定列的最大值
MIN 查询指定列的最小值
COUNT 统计查询结果的行数
SUM 求和,返回指定列的总和
AVG 求平均值,返回指定列数据的平均值
count(*) 和 count(1)和count(列名)区别
  1. count(1) and count(*)

    当表的数据量大些时,对表作分析之后,使用count(1)还要比使用count()用时多了! 从执行计划来看,count(1)和count()的效果是一样的。 但是在表做过分析之后,count(1)会比count(*)的用时少些(1w以内数据量),不过差不了多少。

    如果count(1)是聚索引,id,那肯定是count(1)快。但是差的很小的。 因为count(),自动会优化指定到那一个字段。所以没必要去count(1),用count(),sql会帮你完成优化的 因此:count(1)和count(*)基本没有差别!

  2. count(1) and count(字段) 两者的主要区别是 (1) count(1) 会统计表中的所有的记录数,包含字段为null 的记录。 (2) count(字段) 会统计该字段在表中出现的次数,忽略字段为null 的情况。即不统计字段为null 的记录。

  3. count(*) 和 count(1)和count(列名)区别

    执行效果上: count(*)包括了所有的列,相当于行数,在统计结果的时候,不会忽略列值为NULL count(1)包括了忽略所有列,用1代表代码行,在统计结果的时候,不会忽略列值为NULL count(列名)只包括列名那一列,在统计结果的时候,会忽略列值为空(这里的空不是只空字符串或者0,而是表示null)的计数,即某个字段值为NULL时,不统计。

    执行效率上: 列名为主键,count(列名)会比count(1)快 列名不为主键,count(1)会比count(列名)快 如果表多个列并且没有主键,则 count(1) 的执行效率优于 count(*) 如果有主键,则 select count(主键)的执行效率是最优的 如果表只有一个字段,则 select count(*)最优。

数值型函数

函数名称 作用
ABS 求绝对值
SQRT 求平方根
POW 和 POWER 两个函数的功能相同,返回参数的幂次方
MOD 求余数
CEIL 和 CEILING 两个函数功能相同,都是返回不小于参数的最小整数,即向上取整
FLOOR 向下取整,返回值转化为一个BIGINT
RAND 生成一个0~1之间的随机数,传入整数参数是,用来产生重复序列
ROUND 对所传参数进行四舍五入
SIGN 返回参数的符号

字符型函数

函数名称 作用
LENGTH 计算字符串长度函数,返回字符串的字节长度
CHAR_LENGTH 计算字符串长度函数,返回字符串的字节长度,注意两者的区别
CONCAT 合并字符串函数,返回结果为连接参数产生的字符串,参数可以使一个或多个
INSERT(str,pos,len,newstr) 替换字符串函数
LOWER 将字符串中的字母转换为小写
UPPER 将字符串中的字母转换为大写
LEFT(str,len) 从左侧字截取符串,返回字符串左边的若干个字符
RIGHT 从右侧字截取符串,返回字符串右边的若干个字符
TRIM 删除字符串左右两侧的空格
REPLACE(s,s1,s2) 字符串替换函数,返回替换后的新字符串
SUBSTRING(s,n,len) 截取字符串,返回从指定位置开始的指定长度的字符换
REVERSE 字符串反转(逆序)函数,返回与原始字符串顺序相反的字符串
STRCMP(expr1,expr2) 比较两个表达式的顺序。若expr1 小于 expr2 ,则返回 -1,0相等,1则相反
LOCATE(substr,str [,pos]) 返回第一次出现子串的位置
INSTR(str,substr) 返回第一次出现子串的位置

日期和时间函数

函数名称 作用
CURDATE() CURRENT_DATE() CURRENT_DATE 两个函数作用相同,返回当前系统的日期值
CURTIME() CURRENT_TIME() CURRENT_TIME 两个函数作用相同,返回当前系统的时间值
NOW 返回当前系统的日期和时间值
SYSDATE 返回当前系统的日期和时间值
DATE 获取指定日期时间的日期部分
TIME 获取指定日期时间的时间部分
MONTH 获取指定日期中的月份
MONTHNAME 获取指定曰期对应的月份的英文名称
DAYNAME 获取指定曰期对应的星期几的英文名称
YEAR 获取年份,返回值范围是 1970〜2069
DAYOFWEEK 获取指定日期对应的一周的索引位置值,也就是星期数,注意周日是开始日,为1
WEEK 获取指定日期是一年中的第几周,返回值的范围是否为 0〜52 或 1 〜53
DAYOFYEAR 获取指定曰期是一年中的第几天,返回值范围是1~366
DAYOFMONTH 和 DAY 两个函数作用相同,获取指定日期是一个月中是第几天,返回值范围是1~31
DATEDIFF(expr1,expr2) 返回两个日期之间的相差天数,如 SELECT DATEDIFF('2007-12-31 23:59:59','2007-12-30');
SEC_TO_TIME 将秒数转换为时间,与TIME_TO_SEC 互为反函数
TIME_TO_SEC 将时间参数转换为秒数,是指将传入的时间转换成距离当天00:00:00的秒数,00:00:00为基数,等于 0 秒

流程控制函数

函数名称 作用
IF(expr,v1,v2) 判断,流程控制,当expr = true时返回 v1,当expr = false、null 、 0时返回v2
IFNULL(v1,v2) 判断是否为空,如果 v1 不为 NULL,则 IFNULL 函数返回 v1,否则返回 v2
CASE 搜索语句
相关推荐
苹果酱05676 分钟前
redis系列--1.redis是什么
java·vue.js·spring boot·mysql·课程设计
小安同学iter7 分钟前
Redis入门(Java中操作Redis)
数据库·redis·缓存
get lend gua8 分钟前
游戏数据分析,力扣(游戏玩法分析 I~V)mysql+pandas
python·mysql·leetcode·游戏·数据分析
zxsz_com_cn33 分钟前
医疗设备预测性维护的合规性挑战与标准化路径研究
大数据·数据库·人工智能
Json20113151 小时前
B树、红黑树、B+树和平衡二叉树(如AVL树)的区别
mysql
赤橙红的黄1 小时前
Spring编程式事务(本地事务)
java·数据库·spring
hkfkn1 小时前
SQL刷题日志(day2)
数据库·sql
SimonKing1 小时前
京东外卖,探索「距离最近」排序背后的秘密
redis·后端·mysql
潇湘秦2 小时前
Oracle19C低版本一天遭遇两BUG(ORA-04031/ORA-600)
数据库·oracle
自由生长20242 小时前
数据的多版本管理-第一篇-数据库
数据库