軟件測試之MySQL數據庫必知必會,面試必備!
一、前言
1.1 數據庫概念及分類
首先,我們經常說的
MySQL是一個數據庫管理系統
,而非數據庫。數據庫是組織、存儲和管理數據的倉庫,存儲數據的容器。而數據庫管理系統是操縱和管理數據庫的大型軟件,建立、使用和維護數據庫。數據表是真正的數據存儲單元,其他對象的基礎。三者之間的關係爲:一個數據庫管理系統維護了多個數據庫,一個數據庫包含若干數據表
。
關於數據庫的分類,可能有很多種分類。一般來說,我們用到最多的就是
關係型數據庫
和NoSQL數據庫
。而其中關係型數據庫又是應用最爲廣泛的。
1.2 SQL語句概念及分類
SQL:一種
結構化查詢語句
,用於訪問和操作數據庫的標準計算機語言。通常用途爲操作數據庫對象
(表、存儲過程、函數、索引),表記錄的增刪改查
。SQL是一門弱語言
,不區分大小寫
。通常,將SQL語句分爲下面五大類。
1.3 MySQL數據類型
MySQL支持多種數據類型,大致可以分爲四大類,如下圖所示。關於MySQL數據類型的詳細內容,請參考鏈接 MySQL常見的數據類型
二、常用SQL語句
2.1 數據庫相關SQL
- 查詢所有數據庫
show databases;
- 創建數據庫
create database 數據庫名稱;
- 刪除數據庫
drop database 數據庫名稱;
- 查詢數據庫詳情、查看數據庫的字符集
show create database 數據庫名稱;
- 創建指定字符集數據庫
##創建數據庫語句後面用character set設置數據庫字符集,注意這裏是utf8,不是utf-8 create database 數據庫名稱 character set gbk/utf8;
- 選中數據庫
use 數據庫名稱;
2.2 表相關SQL
如果不借助工具的情況下,在命令中輸入下面相關的命令,需要先使用
use 數據庫名
選擇要操作表所屬的數據庫。
- 創建表
##創建數據庫表語句如下: CREATE TABLE IF NOT EXISTS 表名( 字段名1 字段類型, 字段名2 字段類型 )ENGINE=InnoDB DEFAULT CHARSET=utf8; ## 實際案例語句 CREATE TABLE IF NOT EXISTS NUMBER( ID INT NOT NULL AUTO_INCREMENT, USERNAME VARCHAR(40), PRIMARY KEY (ID) )ENGINE=INNODB DEFAULT CHARSET=UTF8;
- 查詢所有表
show tables;
- 查詢表詳情
show create table 表名;
- 查看錶結構
desc 表名;
- 刪除表
drop table 表名;
2.3 修改表相關SQL
關於修改表相關的SQL,除了修改表前沒加
alter table 表名
,其他都是在該基礎添加的語句。這部分的SQL一般來說在實際工作中用的不多,因爲相關操作都可以藉助Navicat實現
。
- 修改表名
rename table 原表名 to 新表名;
- 修改表引擎和字符集
alter table 表名 engine=innodb/myisam charset=gbk;
- 添加表字段(在最後)
alter table 表名 add 字段名 字段類型;
- 添加表字段(最前面)
alter table 表名 add 字段名 字段類型 first;
- 添加字段(某個字段後添加)
alter table 表名 add 字段名A 字段A類型 after 字段名B;
- 刪除表字段
alter table 表名 drop 字段名;
- 修改表字段名稱和類型
alter table 表名 change字段名 原字段名 新字段名 新類型;
2.4 操作表記錄相關SQL
對於測試工程師而言,SQL語言中最常用的就是DML——數據操作語言,即爲增刪改查。而其中
用到最多的就是DQL——數據查詢語句
。
- 插入數據(全表插入)
insert into 表名 values (字段1值,字段2值); insert into 表名 values (字段1值,字段2值),(字段1值,字段2值);
- 插入數據(指定字段)
insert into 表名 (字段1,字段2) values (值1,值2); insert into 表名 (字段1,字段2) values (值1,值2),(值1,值2);
- 刪除數據
#刪除指定數據 delete from 表名 where 字段名=值; #刪除表中全部數據 delete from 表名;
- 修改數據
#修改指定值 update 表名 set 字段名=值1 where 字段名=值2; #修改全部值 update 表名 set 字段名=值1;
- 查詢數據
#查詢所有 select * from 表名
三、DQL(查詢)詳解
DQL即爲數據查詢語句,也是使用最多的一種SQL語句。將該部分的內容分爲以下幾部分:其中最爲常用的是
關聯查詢
、分組
、分頁
、排序
、條件查詢
這幾種。對於其中常用的where 、group by、having、order by、limit,其順序爲:·select * from 表A join 表B on 條件 where 條件 group by 分組字段 having 聚合函數過濾 order by 排序字段 limit ...
3.1 條件查詢
- 判斷是否爲空(
is null
、is not null
)# is null代表爲空 is not null代表不爲空 #案例 查看圖書借閱表中歸還時間爲空的借閱記錄 SELECT * FROM book_borrow WHERE return_time is NULL;
- 比較運行符(
>、<、>=、<=、!=、<>
)#分別代表大於、小於、大於等於、小於等於、不等於、不等於 #案例 查看圖書表中圖書id大於2的圖書信息 SELECT * FROM book WHERE book_id>2
and
和or
## 等同於 &&和 || ,表示同時滿足兩個條件和滿足兩個條件中一個 ## 案例1:查詢圖書借閱表中用戶id和圖書id都爲1的圖書信息 SELECT * FROM book_borrow WHERE user_id=1 AND book_id=1; ##案例2:查詢圖書借閱表中用戶id爲1或者圖書id爲1的圖書信息 SELECT * FROM book_borrow WHERE user_id=1 OR book_id=1;
in
在某些可選值範圍內# select * from 表名 where 字段 in (值1,值2,值3); # 案例1 查詢圖書借閱表中讀者id在1,2,3範圍內 SELECT * FROM book_borrow WHERE user_id in (1,2,3);
between
和not between
# 字段 between 值1 and 值2; 字段在值1和值2之間 #案例1:查詢圖書借閱表中讀者id在1-2範圍內,包含1和2 SELECT * FROM book_borrow WHERE user_id BETWEEN 1 AND 2;
- 模糊查詢
like
_代表單個字符
,%代表0個或多個字符
# 案例1 查詢圖書表中圖書名字爲兩個字符,且圖書名第一個字爲三的圖書信息 SELECT * FROM book WHERE book_name LIKE '三_'; # 案例2 查詢圖書表中圖書名以天才開頭的圖書信息 SELECT * FROM book WHERE book_name LIKE '天才%';
3.2 別名、去重
- 別名——使用
as
關鍵字或空格 給表名或字段別名# 案例 查詢圖書表中圖書名稱爲‘天才在左 瘋子在右’的作者 SELECT b.author as 作者 FROM book b WHERE b.book_name ='天才在左 瘋子在右';
- 去重——使用
distinct
對查詢出來的去重#案例 查詢員工表中所有的員工名稱,且不重複 select distinct employeeName from employee;
3.3 排序、分頁查詢
- 排序——
order by
(ASC 升序 默認、DESC 降序 )#案例:查詢學生表數據並以id降序、年齡升序排序 select * from student order by id desc,age;
- 分頁查詢——
limit 跳過條數A 每頁數量B
#案例 查詢學生表中年齡第三大的學生信息 select * from student order by age desc limit 2,1; #分頁查詢sql的格式爲 start爲頁碼 pageSize是每頁顯示的條數 select * from table limit (start-1)*pageSize,pageSize;
3.4 聚合函數、時間相關函數
- 聚合函數——sum(字段名) 求和
#案例 對分數表中分數進行求和 SELECT SUM(a.score) FROM table_socre as a;
- 聚合函數——avg(字段名) 平均值
#案例 求分數表中分數平均值 SELECT AVG(a.score) FROM table_socre as a;
- 聚合函數——max(字段名) 最大值
#案例 求分數表中最大值 SELECT MAX(a.score) FROM table_socre as a;
- 聚合函數——min(字段名) 最小值
#案例 求分數表中最小值 SELECT MIN(a.score) FROM table_socre as a;
- 聚合函數——count(字段名) 統計數量
#實例 查詢圖書表中圖書總數 SELECT COUNT(*) as 圖書總數 FROM book 注意點,count()函數的擴號中也可以填寫字段,如果 字段的值爲0,則不參與合計
- 時間函數——now() 當前年月日時分秒
SELECT NOW(); #輸出當前時間 2020-07-03 23:21:03
- 時間函數——current_date() 當前時間年月日
SELECT CURRENT_DATE(); #輸出當前時間年月日 2020-07-03
3.5 分組與having
- 分組——
group by
group by的常規用法是配合聚合函數,利用分組信息進行統計。#案例 以title字段分組,查詢每個分組中score的最大值 SELECT t.t.title,MAX(score) FROM table_socre t GROUP BY t.title;
having
——解決聚合函數過濾問題,一般配合group by一起使用。#案例 以title字段分組,查詢每個分組中score的最大值,並且通過最大值必須大於20來過濾數據 SELECT t.t.title,MAX(score) FROM table_socre t GROUP BY t.title having MAX(score)>20;
3.6 子查詢
- 寫在where/having後作爲查詢條件的值
#案例 查詢員工工資最低的員工信息,由於可能最低有多個員工,所以需要先查詢出最低工資 SELECT * FROM employees WHERE salary=( SELECT MIN(salary) FROM employees );
臨時表
——用在from後面,當做一個新表,新表必須有名稱#案例 將一個查詢結果作爲一個新表,讓後從這個新表中查詢數據 select cou,name from (select count(*) AS cou,enabled AS name from `user` group by enabled ) as a where cou>0
3.7 關聯查詢
- 內連接——
表A inner join 表B on 條件
,特點:只查詢連接的表中能夠有對應的記錄的數據#查詢員工姓名及對應部門名稱 沒有部門的人員和沒有人員的部門都不顯示 SELECT e.empName, d.deptName FROM t_employee e INNER JOIN t_dept d ON e.dept = d.id;
- 左外連接——
表A left join 表B on 條件
,特點:以左邊的表的數據爲基準,去匹配右邊的表的數據
,如果匹配到就顯示,匹配不到就顯示爲null#查詢員工表中員工姓名及對應部門名稱,若員工沒有部門,則顯示null SELECT e.empName, d.deptName FROM t_employee e LEFT JOIN t_dept d ON d.id = e.dept;
- 右外連接——
表A right join 表B on 條件
,特點:與坐外連接類似,只是基準表變了,用右表去匹配左表
。所以左外連接能做到的事情,右外連接也能做到。#查詢所有部門和對應的員工,如果部門沒有員工,則顯示null SELECT e.empName, d.deptName FROM t_employee e RIGHT JOIN t_dept d ON d.id = e.dept;
- 自連接——當前表與自身連接查詢
#查詢員工以及他的上司的名稱,由於上司也是員工,所以這裏虛擬化出一張上司表 SELECT e.empName, b.empName FROM t_employee e LEFT JOIN t_employee b ON e.bossId = b.id;
四、約束、索引、存儲過程、事務
4.1 約束
MySQL中約束是一種
限制
,它通過對錶的行或列的數據做出限制,來確保表的數據的完整性、唯一性。
4.2 索引
MySQL中的索引是一種高效獲取數據的存儲結構——
B+Tree
;MySQL中索引的好處在於加快查詢速度
,壞處就是降低了增刪改的速度
,增大了表的文件大小(索引文件可能比數據文件還要大)。MySQL索引實現原理可以參考:mysql索引實現原理
#1.如何創建索引 注意:添加主鍵約束是,會自動創建主鍵字段的索引
create index 索引名 on 表名(字段);
#2.查看索引
show index from 表名;
#3.刪除索引
drop index 索引名 on 表名;
4.3 存儲過程
MySQL中存儲過程
類似於函數
,就是把一段代碼封裝起來
,當要執行這一段代碼的時候,可以通過調用該存儲過程來實現。
#1.查看數據庫中的存儲過程
show procedure status;
#2.查看存儲過程的創建代碼
show create PROCEDURE 存儲過程名;
#3.創建存儲過程
CREATE PROCEDURE 名稱()
BEGIN
.........
END
#4.創建存儲過程,並執行存儲過程
#4.1創建存儲過程
drop procedure if exists proc_addNum;
create procedure proc_addNum (in x int,in y int,out sum int)
BEGIN
SET sum= x + y;
end
#4.2執行過程,out輸出返回值
call proc_addNum(2,3,@sum);
select @sum;
4.4 事務
事務:是數據庫中執行SQL語句的工作單元,可以保證事務內的SQL語句要麼全部成功,要麼全部失敗。
五、相關面試題
對於軟件測試而言,在MySQL數據庫相關的面試題中,除了上面
MySQL數據庫相關的概念
,最重要的就是DQL語句
的編寫。關於DQL相關語句的考題,可以直接參考牛客網中SQL實戰編程:牛客網SQL實戰。
分組(group by) + 聚合函數篩選(having) + join on(關聯查詢)——第12題
#獲取部門中員工薪水最高相關信息
SELECT
B.dept_no,
B.emp_no,
A.salary AS salary
FROM
salaries AS A
JOIN dept_emp AS B ON A.emp_no = B.emp_no
WHERE
A.to_date = '9999-01-01'
AND B.to_date = '9999-01-01'
GROUP BY
B.dept_no
HAVING
A.salary = max( A.salary );
自連接——第19題
#查看薪水第二多的員工信息(不使用order by)
#思路一:查詢最大薪水,然後查詢小於最大薪水的薪水值中的最大值
SELECT
e.emp_no,
s.salary,
e.last_name,
e.first_name
FROM
employees e
JOIN salaries s ON e.emp_no = s.emp_no
AND s.to_date = '9999-01-01'
AND s.salary = (
SELECT
max( salary )
FROM
salaries
WHERE
salary < ( SELECT max( salary ) FROM salaries WHERE to_date = '9999-01-01' )
AND to_date = '9999-01-01'
)
#思路二:對薪水錶自連接,使用s1.salary <= s2.salary查詢出第二多薪水
SELECT
e.emp_no,
s.salary,
e.last_name,
e.first_name
FROM
employees e
JOIN salaries s ON e.emp_no = s.emp_no
AND s.to_date = '9999-01-01'
AND s.salary = (
SELECT
s1.salary
FROM
salaries s1
JOIN salaries s2 ON s1.salary <= s2.salary
AND s1.to_date = '9999-01-01'
AND s2.to_date = '9999-01-01'
GROUP BY
s1.salary
HAVING
count( DISTINCT s2.salary ) = 2
)
使用同一個表兩次、解題思路——第24題
#獲取員工其當前的薪水比其manager當前薪水還高的相關信息
#1.先查出員工的工號和薪水:
SELECT
de.emp_no,
sa.salary
FROM
dept_emp de,
salaries sa
WHERE
de.emp_no = sa.emp_no
AND de.to_date = '9999-01-01'
AND sa.to_date = '9999-01-01'
#2.再查出經理的工號和薪水:
SELECT
dm.emp_no manager_no,
sal.salary
FROM
dept_manager dm,
salaries sal
WHERE
dm.emp_no = sal.emp_no
AND dm.to_date = '9999-01-01'
AND sal.to_date = '9999-01-01'
#3.最後就是組合,看準條件,做好條件銜接
SELECT
de.emp_no,
dm.emp_no manager_no,
sa.salary emp_salary,
sal.salary manager_salary
FROM
dept_emp de,
salaries sa,
dept_manager dm,
salaries sal
WHERE
de.emp_no = sa.emp_no
AND dm.emp_no = sal.emp_no
AND de.dept_no = dm.dept_no
AND de.to_date = '9999-01-01'
AND sa.to_date = '9999-01-01'
AND dm.to_date = '9999-01-01'
AND sal.to_date = '9999-01-01'
AND sa.salary > sal.salary
對於測試工程師而言,在面試中,應該不會遇到特別難的SQL題目。且工作中,對於SQL要求不會特別高,重點在於根據需求梳理好思路,然後編寫相關的SQL,對於其SQL的效率不回特別追求。