【数据库】MySQL知识点总结(一):基础操作

本系列包含:


在学习 MySQL 的基础操作之前,我们应该首先了解一下 MySQL 中的语句执行顺序。

(8) SELECT (9) DISTINCT column,# (8)选择字段 、(9)去重
(6) AGG_FUNC(column or expression),# (6)聚合函数
(1) FROM [left_table]                  # (1)选择表
(3) <join_type> JOIN <right_table>     # (3)链接
(2) ON <join_condition>                # (2)链接条件
(4) WHERE <where_condition>            # (4)条件过滤
(5) GROUP BY <group_by_list>           # (5)分组
(7) HAVING <having_condition>          # (7)分组过滤
(10) ORDER BY <order_by_list>          # (10)排序
(11) LIMIT count OFFSET count;         # (11)分页

1.检索数据

1.1 检索单个列

select name from student

1.2 检索多个列

select name, age, class from student

1.3 检索所有列

select * from student

1.4 检索不同的值

即利用 distinct 去重。

select distinct class from student

1.5 限制结果

使用 LIMIT 子句。

select * from student limit 10 offset 1
  • offset 基数为 0,所以 offset 1 代表从第 2 行开始
  • 第一个数字是检索的行数,第二个数字是指从哪儿开始。

若使用下面这个语法,逗号之前的值对应 OFFSET,逗号之后的值对应 LIMIT

select * from student limit 1, 10

1.6 注释

# 注释 1
-- 注释 2
/* 注释 3
   注释 3
   注释 3 */

2.排序

2.1 排序数据

在指定一条 ORDER BY 子句时,应该保证它是 SELECT 语句中最后一条子句。

select prod_name
from Products
order by prod_name

2.2 按多个列排序

select prod_id, prod_price, prod_name
from Products 
order by prod_price, prod_name

2.3 按列位置排序

select prod_id, prod_price, prod_name
from Products 
order by 2, 3

2.4 指定排序方向

默认排序是 ASC,所以一般升序的时候不需指定,降序的关键字是 DESC。如果想在多个列上进行降序排序,必须对每一列指定 DESC 关键字。

select prod_id, prod_price, prod_name
from Products 
order by prod_price desc
select prod_id, prod_price, prod_name
from Products 
order by prod_price desc, prod_name

3.过滤数据

3.1 使用 WHERE 子句

# 找到学号为 1 的学生。
select * from student 
where number = 1

3.2 WHERE 子句操作符

说明操作符
等于=
不等于<>
不等于!=
小于<
小于等于<=
不小于!<
大于>
大于等于>=
不大于!>
在指定的两个值之间BETWEEN
为 NULL 值IS NULL
# 找到学号为在 [1, 10] 的学生(闭区间)
select * from student 
where number between 1 and 10
# 找到未设置电子邮箱的学生,注意不能使用 =
select * from student 
where email is null

4.高级数据过滤

4.1 组合数据过滤

# 找到一班中大于 23 岁的学生
select * from student 
where class_id = 1 and age > 23
# 找到一班或者大于 23 岁的学生
select * from student 
where class_id = 1 or age > 22

4.2 IN 操作符

# 找到一班与二班的学生
select * from student 
where class_id in (1, 2)

4.3 NOT 操作符

WHERE 子句中的 NOT 操作符有且只有一个功能,那就是否定其后所跟的任何条件。

# 找到不是一班二班的学生
select * from student 
where class_id not in (1, 2)

5.通配符过滤

5.1 百分号 % 通配符

# 所有以词 Fish 起头的产品
select prod_id, prod_name
from Products 
where prod_name like 'Fish%'

5.2 下划线 _ 通配符

下划线的用途与 % 一样,但它只匹配单个字符,而不是多个字符。

select prod_id, prod_name
from Products
where prod_name like '__ inch teddy bear'

5.3 方括号 [] 通配符

用来指定一个字符集,它必须匹配指定位置(通配符的位置)的一个字符,此通配符可以用前缀字符 ^(脱字号)来否定。

# 找出所有名字以 J 或 M 起头的联系人
select cust_contact
from Customers 
where cust_contact LIKE '[JM]%' 
order by cust_contact

6.创建计算字段

6.1 拼接字段

select concat(name, '(', age, ')') as nameWithAge 
from student;
select concat('hello', 'world') as helloworld

6.2 算术计算

select age - 18 as relativeAge from student;
SELECT prod_id, quantity, item_price, quantity * item_price AS expanded_price
FROM OrderItems
WHERE order_num = 20008:

7.函数

7.1 DBMS 函数的差异

与 SQL 语句不一样,SQL 函数不是可移植的。

函数语法
提取字符串的组成部分DB2、Oracle、PostgreSQL 和 SQLite 使用 SUBSTR();MariaDB、MySQL 和 SQL Server 使用 SUBSTRING()
数据类型转换Oracle 使用多个函数,每种类型的转换有一个函数;DB2 和 PostgreSQL 使用 CAST()。MariaDB、MySQL 和 SQL Server 使用CONVERT()
提取当前日期DB2 和 PostgreSQL 使用 CURRENT_DATE;MariaDB 和 MySQL 使用 CURDATE()。Oracle 使用 SYSDATE;SQL Server 使用 GETDATE();SQLite 使用 DATE()

SQL 中,关键字与函数名不区分字母的大小写。

7.2 常用的文本处理函数

函数说明
LEFT(str, length)从左边开始截取 strlength 是截取的长度
RIGHT(str, length)从右边开始截取 strlength 是截取的长度
LENGTH(str)计算字符串 str 的长度
LOCATE(substr, str)返回子串 substr 在字符串 str 中第一次出现的位置,如果字符 substr 在字符串 str 中不存在,则返回 0
POSITION(substr IN str)返回子串 substr 在字符串 str 中第一次出现的位置,如果字符 substr 在字符串 str 中不存在,与 LOCATE 函数作用相同
SUBSTRING(str, n, m)返回字符串 str 从 第 n 个字符截取,共截取 m 个字符
SUBSTRING_INDEX(str, substr, n)返回字符 substrstr 中第 n 次出现位置之前的字符串
REPLACE(str, n, m)将字符串 str 中的 n 字符替换成 m 字符
TRIM()去掉字符串左右两边的空格
RTRIM()去掉字符串右边的空格
LTRIM()去掉字符串左边的空格
LOWER()将字符串转换为小写
UPPER()将字符串转换为大写

7.3 日期和时间处理函数

函数说明
YEAR()从日期中提取年份
MONTH()从日期中提取月份
DAY()从日期中提取天
TIMESTAMPDIFF(interval,datetime1,datetime2)datetime2 - datetime1 的时间差, 比较的单位 interval 可以为:FRAC_SECONDSECONDMINUTEHOURDAYWEEKMONTHQUARTERYEAR
DATEDIFF(datepart,startdate,enddate)department 可为:yearquartermonth weekdayhourminutesecondmillisecond
UNIX_TIMESTAMP()返回时间戳
select order_num
from Orders 
where YEAR(order_date) = 2020
# 获取月
MONTH(date);
# 或者
date_format(date,'%m');
# 获取天
DAY(date);
# 或者
date_format(date,'%d');
# 获取两个时间之间相差多少分钟
(UNIX_TIMESTAMP(submit_time) - UNIX_TIMESTAMP(start_time)) / 60

7.4 数值处理函数

函数说明
ABS()返回一个数的绝对值
EXP()返回一个数的指数值
SQRT()返回一个数的平方根

8.数据汇总

聚集函数,一些对数据进行汇总的函数,常见有 COUNTMINMAXAVGSUM 五种。

# 统计1班人数
select count(*) from student 
where class_id = 1;

9.分组数据

使用 group by 进行数据分组,可以使用聚合函数对分组数据进行汇总,使用 having 对分组数据进行筛选。group by 子句必须出现在 where 子句之后,order by 子句之前。

# 按照班级进行分组并统计各班人数
select class_id, count(*) 
from student 
group by class_id
# 列出大于三个学生的班级
select class_id, count(*) as cnt 
from student
group by class_id 
having cnt > 3

10.子查询

作为子查询的 SELECT 语句只能查询单个列。

# 列出软件工程班级中的学生
select * from student
where class_id in (
    select id 
    from class 
    where class_id = '软件工程'
);

作为计算字段使用子查询

SELECT cust_name, cust_state, (
  SELECT COUNT(*)
  FROM Orders
  WHERE Orders.cust_id = Customers.cust_id) AS orders
FROM Customers
ORDER BY cust_name;

11.联结表

11.1 创建联结

要保证所有联结都有 WHERE 子句,否则 DBMS 将返回比想要的数据多得多的数据。同理,要保证 WHERE 子句的正确性。

# 列出软件工程班级中的学生
select * 
from student, class
where student.class_id = class.id and class.name = '软件工程';

虽然两个表拥有公共字段便可以创建联结,但是使用外键可以更好地保证数据完整性。比如当对一个学生插入一条不存在的班级的时候,便会插入失败。一般来说,联结比子查询拥有更好的性能。

11.2 内联结

目前为止使用的联结称为等值联结,它基于两个表之间的相等测试。这种联结也称为内联结 inner join。其实,可以对这种联结使用稍微不同的语法,明确指定联结的类型。下面的 SELECT 语句返回与前面例子完全相同的数据。

# 列出软件工程班级中的学生
select * 
from student
inner join class on student.class_id = class.id
where class.name = '软件工程';

11.3 自联结

假如要给与 Jim Jones 同一公司的所有顾客发送一封信件。这个查询要求首先找出 Jim Jones 工作的公司,然后找出在该公司工作的顾客。

# 列出与张三同一班级的学生
SELECT cust_id, cust_name, cust_contact
FROM Customers
WHERE cust_name = (
  SELECT cust_name
  FROM Customers
  WHERE cust_contact ='Jim Jones'
  )

使用自联结

SELECT cl.cust_id, cl.cust_name, cl.cust_contact
FROM Customers AS cl, Customers AS c2
WHERE cl.cust_name = c2.cust_name AND c2.cust_contact = 'Jim Jones'

此查询中需要的两个表实际上是相同的表,因此 Customers 表在 FROM 子句中出现了两次。虽然这是完全合法的,但对 Customers 的引用具有歧义性,因为 DBMS 不知道你引用的是哪个 Customers 表。

11.4 自然联结

无论何时对表进行联结,应该至少有一列不止出现在一个表中(被联结的列)。标准的联结(前一课中介绍的内联结)返回所有数据,相同的列甚至多次出现。自然联结排除多次出现,使每一列只返回一次。

怎样完成这项工作呢?答案是,系统不完成这项工作,由你自己完成它。自然联结要求你只能选择那些唯一的列,一般通过对一个表使用通配符 SELECT *,而对其他表的列使用明确的子集来完成。

SELECT C. *, O.order_num, O.order_date, OI.prod_id, OI. quantity, OI.item_price
FROM Customers AS C, Orders AS O, OrderItems AS OI
WHERE C.cust_id = O.cust_id AND OI.order_num = 0.order_num AND prod_id = 'RGANO1'

11.5 外连接

许多联结将一个表中的行与另一个表中的行相关联,但有时候需要包含没有关联行的那些行。例如,可能需要使用联结完成以下工作:

  • 对每个顾客下的订单进行计数,包括那些至今尚未下订单的顾客;
  • 列出所有产品以及订购数量,包括没有人订购的产品;
  • 计算平均销售规模,包括那些至今尚未下订单的顾客。

在上述例子中,联结包含了那些在相关表中没有关联行的行。这种联结称为外联结。外连接只限制一张表中的数据必须满足连接条件,而另一张表中数据可以不满足连接条件。语法格式为:

SELECT ... 
FROM1 
LEFT | RIGHT [OUTER] JOIN2 
ON <连接条件>
  • left join:包含左表的所有行,对应的右表行可能为空
  • right join:包含右表的所有行,对应的左表行可能为空
  • full join:左右表格的行全部都有,左右表格判断一致的在同一行,不一致的单独一行
-- 列出每个学生的班级,若没有班级则为 null
select name, class.name 
from student
left join class on student.class_id = class.id;

12.组合查询

假如需要 Illinois、Indiana 和 Michigan 等美国几个州的所有顾客的报表,还想包括不管位于哪个州的所有的 Fun4All。

SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_state IN ('IL','IN','MI')
UNION
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_name = 'Fun4All';

UNION 从查询结果集中自动去除了重复的行;如果想返回所有的匹配行,可使用 UNION ALL

SELECT 语句的输出用 ORDER BY 子句排序。在用 UNION 组合查询时,只能使用一条 ORDER BY 子句,它必须位于最后一条 SELECT 语句之后。

13.插入数据

13.1 数据插入

插入单条语句。

INSERT INTO table_name ( field1, field2,...fieldN ) VALUES ( value1, value2,...valueN );

可以采用以下方法插入一条数据。

insert into student values (8, '陆小凤', 24, 1, 3);

不过上面的做法严重依赖表中列的顺序关系,推荐指定列名插入数据,并且可以插入部分列。

insert into student(name, age, sex, class_id) values(9, '花无缺', 25, 1, 3);

插入多条语句。

INSERT INTO table_name (a,b,c)  VALUES (1,2,3), (4,5,6), (7,8,9);

带更新的插入

REPLACE INTO table_name VALUES (value1, value2, ...) 

13.2 从一个表复制到另一个表

有一种数据插入不使用 INSERT 语句。要将一个表的内容复制到一个全新的表(运行中创建的表),可以使用 CREATE SELECT 语句。

CREATE TABLE CustCopy AS SELECT * FROM Customers;

14.更新和删除数据

14.1 更新数据

# 修改张三的班级
update student 
set class_id = 2 
where name = '张三'

14.2 删除数据

# 删除张三的数据
delete from student where name = '张三'
# 删除表中所有数据
delete from student
# 更快地删除表中所有数据
truncate table student

15.创建和操纵表

15.1 创建表

# 创建学生表
create table student (
  id int(11) not null auto_increment,
  name varchar(50) not null,
  age smallint default 20,
  sex enum('male', 'famale'),
  score tinyint comment '入学成绩',
  class_id int(11),
  createTime timestamp default current_timestamp,
  primary key (id),
  foreign key (class_id) references class (id)
);

根据旧表创建新表

create table student_copy as select * from student;

15.2 更新表

# 删除 age 列
alter table student 
drop column age;
# 添加 age 列
alter table student 
add column age smallint
# 在某列前插入列 
alter table table_name 
add column column_name 数据类型 AFTER 列名
# 修改某列名字和数据类型
alter table table_name 
change 原来的列名 新列名 数据类型
# 为某列添加默认值
alter table table_name 
modify coulmn 列名 数据类型 default 默认值
# 修改表名
alter table 表名 rename (to) 新表名
# 将某一列放到第一列
alter table 表名 modify column 列名 类型 first

15.3 删除表

drop table if exists student

16.视图

视图是一种虚拟的表,便于更好地在多个表中检索数据,视图也可以作写操作,不过最好作为只读。在需要多个表联结的时候可以使用视图。

  • 重用 SQL 语句。
  • 简化复杂的 SQL 操作。
  • 使用表的一部分而不是整个表。
  • 保护数据。可以授予用户访问表的特定部分的权限,而不是整个表的访问权限。
  • 更改数据格式和表示。
create view v_student_with_classname as
select student.name name, class.name class_name
from student 
left join class
where student.class_id = class.id;
select * 
from v_student_with_classname

因为视图不包含数据,所以每次使用视图时,都必须处理查询执行时需要的所有检索。如果你用多个联结和过滤创建了复杂的视图或者嵌套了视图,性能可能会下降得很厉害。因此,在部署使用了大量视图的应用前,应该进行测试。

17.存储过程

存储过程可以视为一个函数,根据输入执行一系列的 sql 语句。存储过程也可以看做对一系列数据库操作的封装,一定程度上可以提高数据库的安全性。

# 创建存储过程
create procedure create_student(name varchar(50))
begin
  insert into students(name) values (name);
end;

# 调用存储过程
call create_student('shanyue');

18.高级SQL特性

18.1 约束

18.1.1 主键

表中任意列只要满足以下条件,都可以用于主键。

  • 任意两行的主键值都不相同。
  • 每行都具有一个主键值(即列中不允许 NULL 值)。
  • 包含主键值的列从不修改或更新。
  • 主键值不能重用。如果从表中删除某一行,其主键值不分配给新行。

任意两行绝对没有相同的主键,且任一行不会有两个主键且主键绝不为空。使用主键可以加快索引。

# primiry key
alter table student add constraint primary key (id);

18.1.2 外键

外键可以保证数据的完整性,有助防止意外删除。

alter table student add constraint 
foreign key (class_id) references class (id);

18.1.3 唯一约束

唯一约束用来保证一列(或一组列)中的数据是唯一的。它们类似于主键,但存在以下重要区别。

  • 表可包含多个唯一约束,但每个表只允许一个主键。
  • 唯一约束列可包含 NULL 值。
  • 唯一约束列可修改或更新。
  • 唯一约束列的值可重复使用。
  • 与主键不一样,唯一约束不能用来定义外键。
alter table student add constraint unique key (name);

18.1.4 检查约束

检查约束可以使列满足特定的条件,如果学生表中所有的人的年龄都应该大于 0。不过很可惜 mysql 不支持,可以使用触发器代替。

alter table student add constraint check (age > 0);

18.2 索引

索引用来排序数据以加快搜索和排序操作的速度。

  • 索引改善检索操作的性能,但降低了数据插入、修改和删除的性能。在执行这些操作时,DBMS 必须动态地更新索引。
  • 索引数据可能要占用大量的存储空间。
  • 并非所有数据都适合做索引。取值不多的数据(如州)不如具有更多可能值的数据(如姓或名),能通过索引得到那么多的好处。
  • 索引用于数据过滤和数据排序。如果你经常以某种特定的顺序排序数据,则该数据可能适合做索引。
  • 可以在索引中定义多个列(例如,州加上城市)。这样的索引仅在以州加城市的顺序排序时有用。如果想按城市排序,则这种索引没有用处。
create index index_on_student_name on student (name);
alter table student add constraint key(name);

例:现有一张试卷信息表 examination_info,要求如下。

  • duration 列创建普通索引 idx_duration
  • exam_id 列创建唯一性索引 uniq_idx_exam_id
  • tag 列创建全文索引 full_idx_tag
-- 普通索引
ALTER TABLE examination_info
ADD INDEX idx_duration(duration);

-- 唯一索引
ALTER TABLE examination_info
ADD UNIQUE INDEX uniq_idx_exam_id(exam_id);

-- 全文索引
ALTER TABLE examination_info
ADD FULLTEXT INDEX full_idx_tag(tag);

create index idx_duration on examination_info(duration);
create unique index uniq_idx_exam_id on examination_info(exam_id);
create fulltext index full_idx_tag on examination_info(tag);

删除索引

drop index 索引名 on 表名
alter table 表名 drop index 索引名 

18.3 触发器

触发器是特殊的存储过程。可以在插入,更新,删除行的时候触发事件。

与存储过程不一样(存储过程只是简单的存储 SQL 语句),触发器与单个的表相关联。与 Orders 表上的 INSERT 操作相关联的触发器只在 Orders 表中插入行时执行。类似地,Customers 表上的 INSERTUPDATE 操作的触发器只在表上出现这些操作时执行。

触发器内的代码具有以下数据的访问权。

  • INSERT 操作中的所有新数据;
  • UPDATE 操作中的所有新数据和旧数据;
  • DELETE 操作中删除的数据。

下面是触发器的一些常见用途。

  • 保证数据一致。例如,在 INSERTUPDATE 操作中将所有州名转换为大写。
  • 基于某个表的变动在其他表上执行活动。例如,每当更新或删除一行时将审计跟踪记录写入某个日志表。
  • 进行额外的验证并根据需要回退数据。例如,保证某个顾客的可用资金不超限定,如果已经超出,则阻塞插入。
  • 计算计算列的值或更新时间戳。
# 创建触发器
# 比如 mysql 中没有 check 约束,可以使用创建触发器,当插入数据小于 0 时,置为 0。
create trigger reset_age before insert on student for each row
begin
  if NEW.age < 0 then set NEW.age = 0;
  end if;
end;

# 打印触发器列表
show triggers;

一般来说,约束的处理比触发器快,因此在可能的时候,应该尽量使用约束。

文献参考

[1]《SQL必知必会》(第5版) 作者:本·福达
[2] 8000字《SQL必知必会》精华笔记

  • 8
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
测试工程师在使用MySQL时需要掌握以下知识点: 1. SQL语句的使用:熟悉SQL语句可以提高测试工程师在数据库校验和接口自动化的效率。常用的SQL语句包括查询、插入、更新和删除等操作,测试工程师需要了解这些基本的SQL操作以及各种查询条件的使用。 引用 2. MySQL客户端工具:测试工程师可以使用MySQL的客户端工具来连接和管理数据库。常用的MySQL客户端工具包括Sequel Pro、Navicat和SQLyog等。测试工程师需要熟悉这些工具的使用,包括连接数据库、执行SQL语句以及查看和修改数据等操作。 引用 3. 数据库校验:测试工程师在测试过程通常需要对数据库的数据进行校验,确保系统的各个模块正常运行和数据的一致性。测试工程师需要了解如何编写SQL语句来验证数据库的数据是否符合预期结果。 引用 总结起来,测试工程师在MySQL方面的知识点包括SQL语句的使用、MySQL客户端工具的操作以及数据库校验等方面的知识。这些知识可以帮助测试工程师进行数据库相关的测试工作。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [测试工程师入门知识点整理](https://blog.csdn.net/embracestar/article/details/125818154)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

G皮T

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值