MySQL零基础教程SQL篇,DML增删改查详细讲解。适合小白的零基础教程。

MySQL零基础教程基础篇

大家好,我是大头,98年,职高毕业,上市公司架构师,大厂资深开发,管理过10人团队,我是如何做到的呢?

这离不开持续学习的能力,而其中最重要的当然是数据库技术了!

对于所有开发来说,都离不开数据库,因为所有的数据都是要存储的。

关注我一起学习!文末有惊喜哦!

基础篇的内容大致如下图所示。

在这里插入图片描述

SQL语句

介绍完概念以后,我们可以来看看SQL语句了。SQL语句通常由三类组成。

数据定义 DDL

  • CREATE 创建数据库或数据库对象
  • ALTER 对数据库或数据库对象进行修改
  • DROP 删除数据库或数据库对象
    数据操纵 DML
  • SELECT 从表或视图中检索数据
  • INSERT 将数据插入到表或视图中
  • UPDATE 修改表或视图中的数据
  • DELETE 从表或视图中删除数据
    数据控制 DCL
  • GRANT 用于授予权限
  • REVOKE 用于收回权限

DML

MySQL 中的 DML(数据操纵语言,Data Manipulation Language) 语句用于对数据库中的数据进行操作,主要包括数据的插入、更新、删除和查询。DML 语句是数据库操作中最常用的语句类型。

插入数据

插入数据使用insert指令,可以往创建好的一张表里面插入数据,支持多种插入方式。

最常用的方式是insert values,这种方式也支持批量插入数据。

insert into table_name[(col_name)] values ();

示例:

INSERT INTO employees (id, name, department, salary)
VALUES (1, 'John Doe', 'IT', 50000);

还有一种方式是 insert set。这种方式不支持批量插入。这种方式以键值对的形式插入数据,适用于插入单行数据。这种方式在插入单行数据时更加直观,尤其是当列名较多时。

insert into table_name
set col_name = '值', col_name = '值';

还是刚才的插入示例:

INSERT INTO employees (id, name, department, salary)
set id = 1,name = 'John Doe',department='IT',salary=50000;

还有一种方式是insert select方式,这种方式适合快速复制表数据,将查询出来的数据插入到另外一个表里面。

insert into table_name
select * from table_name;
删除数据

可以使用delete from指令来删除已经插入的数据。如果不加where条件的话,就是删除全表数据。

删除数据操作一定要慎重!!!

delete from table_name where id = 1

示例:删除刚才插入到表employeesID=1的数据。

delete from employees where id = 1

除了使用delete指令以外,还可以使用TRUNCATE指令,这个指令可以删除全表的数据,并且新的数据id自增从1开始。删除全表数据的话,该指令通常更快速。

delete TABLE table_name
修改数据

当插入的数据内容需要修改或者说更新的时候,则可以使用update set指令进行修改。修改操作可以使用where条件来选择要修改的数据,不加where条件则会更新所有数据。

update table_name set col_name = '值' where id = 1

示例:将刚才插入的数据部门修改一下。

update employees set department = 'Market' where id = 1
数据查询

数据查询语句是最复杂的语句,这里只是介绍,想要完全用明白,需要大量的实践。

select 语句

select用于查询数据表里面插入的数据。

*代表查询所有字段。

select * from table_name
列的选择与指定

如果查询指定字段,则使用字段名称代替*

实际开发中不推荐查询所有字段,推荐查询需要的字段,可以提升查询速度。

  • 如果查询的字段正好是索引,那么可以触发覆盖索引
  • 如果查询的字段过多,会增加网络传输消耗
select col_name1,col_name2... from table_name
定义别名

可以给字段和表定义别名,通过as指令实现。别名可以解决一些字段名冲突或者字段名过长的问题。

select col_name as alias from table_name

示例:department字段给一个别名是depart

select id,department as depart from employees
where条件

通过where关键字来进行条件筛选,可以选择出符合条件的数据。

比如当前用户表user有数据如下:以下数据均为随机生成,非真实数据。

IDNameGenderMobileEmail
001张三13800001234zhangsan@example.com
002李四13900005678lisi@example.com
003王五13700009012wangwu@example.com
004赵六13600003456zhaoliu@example.com
005孙七13500007890sunqi@example.com
006周八13400001234zhouba@example.com
007吴九13300005678wujiu@example.com
008郑十13200009012zhengshi@example.com
009钱伯13100003456qianbo@example.com
010孔仲13000007890kongzhong@example.com

这个时候我们需要查询出张三的用户信息,而不是将这10个数据都查询出来到程序里在筛选出张三的数据。

可以使用如下sql完成。

select * from user where name = '张三'; 

这个sql会把name字段中等于‘张三’的数据查询出来。

IDNameGenderMobileEmail
001张三13800001234zhangsan@example.com

where条件支持的类型如下:

  • 比较操作符
操作符描述
=等于
<>不等于(也可用!=
>大于
<小于
>=大于等于
<=小于等于
  • 逻辑操作符
    | 操作符 | 描述 |
    |--------|------|
    | AND | 逻辑与(两个条件都满足) |
    | OR | 逻辑或(至少一个条件满足) |
    | NOT | 逻辑非(对条件取反) |

  • 范围操作符
    | 操作符 | 描述 |
    |--------|------|
    | BETWEEN...AND... | 在指定范围内(包括边界值) |
    | NOT BETWEEN | 不在指定范围内 |

  • 列表操作符
    | 操作符 | 描述 |
    |--------|------|
    | IN | 在指定的列表中 |
    | NOT IN | 不在指定的列表中 |

  • 模糊匹配操作符
    | 操作符 | 描述 |
    |--------|------|
    | LIKE | 模糊匹配(使用%_作为通配符) |
    | NOT LIKE | 不匹配指定模式 |

  • 空值操作符
    | 操作符 | 描述 |
    |--------|------|
    | IS NULL | 判断是否为NULL |
    | IS NOT NULL | 判断是否不为NULL |

  • 其他操作符
    | 操作符 | 描述 |
    |--------|------|
    | EXISTS | 检查子查询是否存在结果 |
    | NOT EXISTS | 检查子查询是否不存在结果 |

替换查询结果集中的数据

可以使用if条件来进行结果的判定,比如性别,数据库里面存的可能是1代表男,2代表女。如果要查询出来男和女的话,就可以直接通过sql处理。

case 
when 条件1 then 表达式1
when 条件2 then 表达式2
else 表达式
end as alias

示例:性别转换。

SELECT 
    CASE 
        WHEN gender = 1 THEN '男'
        WHEN gender = 2 THEN '女'
        ELSE '未知'
    END AS 性别
FROM user;
计算列值

可以直接计算将字段的值进行加减乘除运算。

select col_name + 100 from table_name
from 子句与多表连接查询
交叉连接,笛卡尔积

交叉连接可以连接两个表,产生两个表的笛卡尔积作为结果。

语法如下:

select * from table_namme1 cross join table_name2

可以直接简写:

select * from table_name1,table_name2;

示例:获取两个表的交叉连接。

假设有表user如下:

IDNameGenderMobileEmail
001张三13800001234zhangsan@example.com
002李四13900005678lisi@example.com

还有表user_account存储用户的账户余额信息如下:

IDuser_idbalance
00100110
00200220

使用如下sql语句获取交叉连接:

select * from user,user_account;

结果如下:也就是用户表数据001和用户账户001产生一条数据,和用户账户002产生一条数据,用户数据002同样。

IDNameGenderMobileEmailID2user_idbalance
001张三13800001234zhangsan@example.com00100110
001张三13800001234zhangsan@example.com00200220
002李四13900005678lisi@example.com00100110
002李四13900005678lisi@example.com00200220
内连接

内连接返回两个表中匹配的记录。只有当两个表中的记录满足连接条件时,才会出现在结果集中。可以理解为两个表的交集。

连接的时候,on就类似于where条件,只不过仅仅在连接表数据的时候生效。内连接返回两个表都满足这个条件的交集。

语法:

select col_name from table_name inner join table_name2 on table_name.id = table_name2.t_id;

示例:获取用户数据和用户账户数据的内连接。

假设有表user如下:

IDNameGenderMobileEmail
001张三13800001234zhangsan@example.com
002李四13900005678lisi@example.com
003王五13700009012wangwu@example.com
004赵六13600003456zhaoliu@example.com
005孙七13500007890sunqi@example.com
006周八13400001234zhouba@example.com
007吴九13300005678wujiu@example.com
008郑十13200009012zhengshi@example.com
009钱伯13100003456qianbo@example.com
010孔仲13000007890kongzhong@example.com

还有表user_account存储用户的账户余额信息如下:

IDuser_idbalance
00100110
00200220
00301120

可以看到这两个表的交集就只有两条数据,也就是001和002,

使用如下sql语句获取交叉连接:

on user.id = user_account.user_id这个条件代表只有当user表的id字段和user_account表的user_id字段相等的时候,才会有结果;

select * from user inner join user_account on user.id = user_account.user_id;

结果如下:

IDNameGenderMobileEmailID2user_idbalance
001张三13800001234zhangsan@example.com00100110
002李四13900005678lisi@example.com00200220
外连接

外连接分为左连接和右连接,左连接返回内连接的结果+左表剩余的数据,右连接返回内连接的结果+右表剩余的数据。

左表就是 join左边的表,右表就是join右边的表。

左连接使用left join指令。

select col_name from table_name left join table_name2 on table_name.id = table_name2.t_id;

示例:获取用户表和用户账户表的左连接结果。

IDNameGenderMobileEmail
001张三13800001234zhangsan@example.com
002李四13900005678lisi@example.com
003王五13700009012wangwu@example.com
004赵六13600003456zhaoliu@example.com
005孙七13500007890sunqi@example.com
006周八13400001234zhouba@example.com
007吴九13300005678wujiu@example.com
008郑十13200009012zhengshi@example.com
009钱伯13100003456qianbo@example.com
010孔仲13000007890kongzhong@example.com

还有表user_account存储用户的账户余额信息如下:

IDuser_idbalance
00100110
00200220
00301120

使用如下sql语句,可以看到,仅仅是inner join换成了left join

select * from user left join user_account on user.id = user_account.user_id;

结果如下:在内连接的结果基础上,增加了左表user表剩下的8条数据,右表的字段内容则是null,代表没有对应字段的数据。

IDNameGenderMobileEmailID2user_idbalance
001张三13800001234zhangsan@example.com00100110
002李四13900005678lisi@example.com00200220
003王五13700009012wangwu@example.comnullnullnull
004赵六13600003456zhaoliu@example.comnullnullnull
005孙七13500007890sunqi@example.comnullnullnull
006周八13400001234zhouba@example.comnullnullnull
007吴九13300005678wujiu@example.comnullnullnull
008郑十13200009012zhengshi@example.comnullnullnull
009钱伯13100003456qianbo@example.comnullnullnull
010孔仲13000007890kongzhong@example.comnullnullnull

右连接使用right join指令。
语法如下:

select col_name from table_name right join table_name2 on table_name.id = table_name2.t_id;

示例:获取用户表和用户账户表的右连接结果。

IDNameGenderMobileEmail
001张三13800001234zhangsan@example.com
002李四13900005678lisi@example.com
003王五13700009012wangwu@example.com
004赵六13600003456zhaoliu@example.com
005孙七13500007890sunqi@example.com
006周八13400001234zhouba@example.com
007吴九13300005678wujiu@example.com
008郑十13200009012zhengshi@example.com
009钱伯13100003456qianbo@example.com
010孔仲13000007890kongzhong@example.com

还有表user_account存储用户的账户余额信息如下:

IDuser_idbalance
00100110
00200220
00301120

使用如下sql语句,可以看到,仅仅是left join换成了right join

select * from user right join user_account on user.id = user_account.user_id;

结果如下:在内连接的结果基础上,增加了右表user_account表剩下的1条数据,左表的字段内容则是null,代表没有对应字段的数据。

IDNameGenderMobileEmailID2user_idbalance
001张三13800001234zhangsan@example.com00100110
002李四13900005678lisi@example.com00200220
nullnullnullnullnull00301120
子查询

在MySQL中,子查询是一种强大的功能,允许在一个查询中嵌套另一个查询。根据子查询返回的结果类型,可以将其分为以下几种:

  • 表子查询
  • 行子查询
  • 列子查询
  • 标量子查询

注意:所有的子查询应该慎重使用,因为子查询会导致查询速度降低。

子查询类型定义特点示例
表子查询返回一个完整的表(多行多列)通常用于FROM子句或JOIN操作中,结果是一个表结构sql <br>SELECT * FROM (SELECT id, name FROM users) AS subquery;<br>
行子查询返回一行数据(多列)通常用于WHERE子句中,结果是一行数据,可以与多列比较sql <br>SELECT * FROM users WHERE (id, name) = (SELECT id, name FROM users WHERE age = 25);<br>
列子查询返回一列数据(多行)通常用于WHERE子句中,结果是一列数据,可以与INANYALL等操作符配合使用sql<br>SELECT * FROM users WHERE id IN (SELECT id FROM orders);<br>
标量子查询返回单个值(一行一列)通常用于WHERE子句中,结果是一个单一值,可以与比较操作符配合使用sql<br>SELECT * FROM users WHERE age = (SELECT MAX(age) FROM users);<br>
表子查询
  • 定义:返回一个完整的表(多行多列)。
  • 特点:可以作为虚拟表使用,通常用于FROM子句或JOIN操作中。
  • 示例:SELECT id, name FROM users 这就是一个子查询,该子查询返回的结果是一张表的数据,将该子查询的结果作为一张表,供外部的查询使用。
SELECT * 
FROM (SELECT id, name FROM users) AS subquery;
行子查询
  • 定义:返回一行数据(多列)。
  • 特点:结果是一行数据,可以与多列比较,通常用于WHERE子句中。
  • 示例:SELECT id, name FROM users WHERE mobile = “13012345678” 是一个子查询,该子查询返回了mobile字段等于13012345678的一行数据,并且只查询了id和name字段。将这两个字段作为外部查询的where条件。
SELECT * 
FROM users 
WHERE (id, name) = (SELECT id, name FROM users WHERE mobile = "13012345678");
列子查询
  • 定义:返回一列数据(多行)。
  • 特点:结果是一列数据,可以与IN、ANY、ALL等操作符配合使用,通常用于WHERE子句中。
  • 示例:SELECT user_id FROM orders 是一个子查询,该子查询返回了orders表的所有用户id信息,并将这些用户id作为外部查询的where条件。
SELECT * 
FROM users 
WHERE id IN (SELECT user_id FROM orders);
标量子查询
  • 定义:返回单个值(一行一列)。
  • 特点:结果是一个单一值,可以与比较操作符配合使用,通常用于WHERE子句中。
  • 示例:SELECT MAX(age) FROM users 是一个子查询,该子查询返回了users表的最大的年龄信息,并将最大的用户年龄作为外部查询的where条件。
SELECT * 
FROM users 
WHERE age = (SELECT MAX(age) FROM users);
group by
  • group语句可以实现分组的效果,什么是分组?

假设该数据表中存储了10条订单信息,有3条是张三的,3条是李四的,剩下4条是王五的。

group分组以后就可以分成3组,一组是张三的3条数据,一组是李四的3条数据,一组是王五的4条数据。

  • 分组能干什么?

分组以后可以统计每个分组中的订单数量、订单总额、订单平均金额等。

语法

SELECT * 
FROM table_name 
group by col_name

支持的聚合函数:

  • count(col_name): 计算每个分组中该字段的数量,比如订单数量
  • sum(col_name): 计算每个分组中该字段的总额,比如订单总金额
  • avg(col_name): 计算每个分组中该字段的平均值,比如订单平均金额
  • min(col_name): 获取每个分组中该字段的最小值
  • max(col_name): 获取每个分组中该字段的最大值

有人要问了?那我不使用group by的情况下,可以使用上面的聚合函数吗?

当然可以了,没有分组,其实相当于所有数据是一个大分组,所以计算的是所有数据数量、总额等。

示例:下表是订单表,记录了3个用户的订单信息,现在需要查询这3个用户的订单数量、订单总金额、订单平均金额、最小金额以及最大金额。

OrderIDUserIDOrderDateOrderAmountOrderStatus
100112025-02-01120.00Completed
100212025-02-0285.00Pending
100312025-02-03230.00Shipped
100422025-02-04150.00Completed
100522025-02-0590.25Pending
100622025-02-06110.00Shipped
100732025-02-07100.00Completed
100832025-02-08200.00Pending
100932025-02-09130.75Shipped
101032025-02-10160.00Completed

使用如下sql:对userID进行分组,就可以分成三组数据了,在对每个分组使用聚合函数。

SELECT UserID, count(OrderID), sum(OrderAmount), avg(OrderAmount), min(OrderAmount), max(OrderAmount)
FROM orders 
group by UserID

结果如下:

UserIDcount(OrderID)sum(OrderAmount)avg(OrderAmount)min(OrderAmount)max(OrderAmount)
13435.00145.0085.00230.00
23350.25116.7590.25150.00
34590.75147.68100.00200.00
having

having语句用来过滤group by分组以后的数据。

简单点说,就是相当于where条件,只不过where条件的执行顺序在group by之前,having条件的执行顺序在group by之后。

语法如下:

SELECT * 
FROM table_name 
group by col_name [having col_name = 任何数]

示例:还是上面group by的表,这次我们只需要总金额大于400的数据,从上面的结果来看,我们知道,只需要userId为1和3的数据。

但是注意,where条件是在group by之前执行,这个时候还没有总金额这个字段呢。所以,就需要使用having了。

使用的sql如下:可以看到,仅仅是在后面增加了having sum(OrderAmount) > 400这一条。

SELECT UserID, count(OrderID), sum(OrderAmount), avg(OrderAmount), min(OrderAmount), max(OrderAmount)
FROM orders 
group by UserID having sum(OrderAmount) > 400

结果如下:

UserIDcount(OrderID)sum(OrderAmount)avg(OrderAmount)min(OrderAmount)max(OrderAmount)
13435.00145.0085.00230.00
34590.75147.68100.00200.00
order by

如果想对查询出来的结果集进行排序,可以使用order by语句。

语法如下:asc代表升序,即1,2,3这种排序,desc代表降序,即3,2,1这种。默认是asc。

SELECT * 
FROM table_name 
order by col_name [ascdesc]

order by排序作用在group by分组之后,这意味着可以使用分组之后的聚合函数的结果进行排序,同时也意味着可以影响group by之后的数据。

示例:对上面group by之后的数据按照总金额进行降序排序。

SELECT UserID, count(OrderID), sum(OrderAmount), avg(OrderAmount), min(OrderAmount), max(OrderAmount)
FROM orders 
group by UserID having sum(OrderAmount) > 400
order by sum(OrderAmount) desc

结果如下:

UserIDcount(OrderID)sum(OrderAmount)avg(OrderAmount)min(OrderAmount)max(OrderAmount)
34590.75147.68100.00200.00
13435.00145.0085.00230.00
group 和 order的差别
grouporder
分组行,但输出可能不是分组的排序排序产生的输出
只能使用选择列或表达式列任意列都可以使用
若与聚合函数一起使用列或表达式, 则必须使用group不一定需要
limit

如果不想每次都查询数据表的全部数据,只想获取几条数据呢?比如分页功能,一页10条数据这种,就可以使用limit命令来实现。

语法如下:start代表开始的位置,end代表结束的位置。

SELECT *
FROM orders 
limit [start, end]

比如表中有100条数据。获取1-10条数据就是limit 1,10,获取11-20条数据就是limit 11,20

limit最好是配合order by使用。性能更佳,另外,如果只获取1条数据,也建议使用limit 1代表获取1条数据。

具体的原因在后面原理篇会讲到。

文末福利

关注我发送“MySQL知识图谱”领取完整的MySQL学习路线。
发送“电子书”即可领取价值上千的电子书资源。
发送“大厂内推”即可获取京东、美团等大厂内推信息,祝你获得高薪职位。
发送“AI”即可领取AI学习资料。
部分电子书如图所示。

概念学习

概念学习

概念学习

概念学习

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值