MySQL基础(学习笔记)
MySQL學習筆記
前言
此筆記為我在觀看老杜的MySQL教程時所整理的筆記,原視頻鏈接:老杜數據庫,在原視頻評論區也有老師的資料和筆記。
基本概念
數據庫
Database, 簡稱DB, 指按照一定格式存儲數據的一些文件組合。
顧名思義:存儲數據的倉庫,實際就是一堆文件,這些文件中存儲了具有特定格式的數據。
數據庫管理系統
Database Management System, 簡稱DBMS,
數據庫管理系統是專門用來管理數據庫中的數據的,可以對數據庫中的數據進行增刪改查。
常見的DBMS:
MySQL , Oracle , Ms sqlserver , DB2 , sybase…
SQL:結構化查詢語言
Structured Query Language,
程序員通過學習并編寫SQL語句,由DBMS負責執行SQL語句,最終完成數據庫中數據的增刪改查(CRUD)操作。
SQL語句的分類
-
DQL
數據查詢語言(帶有select關鍵字的)
select…
-
DML
數據操作語言(對表中數據進行增刪改查)
- insert 增
- delete 刪
- update 改
-
DDL
數據定義語言(主要操作的是表的結構,而不是數據)
- create 新建,等同于增
- drop 刪除
- alter 修改
-
TCL
事務控制語言
- commit 事務提交
- rollback 事務回滾
-
DCL
數據控制語言
- grant 授權
- revoke 撤銷權限
三者的關系
DBMS ------執行-------> SQL ---------操作---------> DB
端口號
端口號(port)是任何一個軟件/應用都會有的,端口號是應用的唯一代表,端口號通常和IP地址在一塊,IP地址是用來定位計算機的,而port是用來定位計算機上某個服務/應用的。
在同一臺計算機上,端口號不能重復,具有唯一性。
表(table)
表是數據庫中的最基本單元,非常的直觀
每一個表都有行和列
- 行(row):被稱為數據/記錄。
- 列(column): 被稱為字段,每一個字段都有字段名,數據類型,約束等屬性。
MySQL中常用的數據類型
-
varchar(最長255)
可變長度字符串
比較智能,節省空間
會根據實際的數據長度動態分配空間。
- 優點:節省空間
- 缺點:需要動態分配空間,速度慢
-
char(最長255)
定長字符串
不管實際的數據長度是多少
分配固定長度的空間去存儲數據
使用不恰當的時候,可能導致空間的浪費。
- 優點:不需要動態分配空間,速度快
- 缺點:使用不當可能導致空間的浪費
-
int(最長11)
數字中的整數型
-
bigint
數字中的長整型
-
float
單精度浮點型數據
-
double
雙精度浮點型數據
-
date
短日期類型
-
datetime
長日期類型
-
clob(Character Large Object)
字符大對象
最多可以存儲4G的字符串
超過255個字符串的都要采用CLOB字符大對象來存儲。
-
blob(Binary Large Object)
二進制大對象
專門用來存儲圖片,聲音,視頻等流媒體數據
在BLOG類型的字段上插入數據的時候,例如插入一個圖片,視頻等,
需要使用IO流。
注釋
兩個破折號加上一個空格可以注釋一條SQL語句
select ename from emp; --
基本操作
MySQL服務的啟動和關閉
以管理員權限啟動終端,使用net start MySQL啟動服務,使用net stop MySQL停止服務。
登錄MySQL數據庫
以管理員權限啟動終端,使用mysql -uroot -p密碼登錄數據庫,u指代user,p指代password,使用mysql -uroot -p命令可以以隱藏密碼的形式登錄。
退出MySQL數據庫
使用exit命令
常用命令
- 查看mysql中有哪些數據庫:show databases;
- 選擇使用某個數據庫:use 數據庫名稱;
- 創建數據庫:creat database 創建數據庫名稱;
- 查看數據庫下的表:show tables;
- 導入.sql數據:source 文件路徑
- 查看表中的數據:select * from 表名; 其中* 表示全部
- 查看表的結構:desc 表名; 其中desc為describe的縮寫
- 查看MySQL數據庫版本號:select version();
- 查看當前使用的數據庫:select database();
- 終止一條命令的輸入:\c
SQL語句
注意:所有的SQL語句都以;結尾,并且不區分大小寫。
DQL
簡單查詢
查詢一個字段
select 字段名 from 表名;
其中select 和from 都是關鍵字,字段名和表名都是標識符。
查詢多個字段
select 字段名,字段名 from 表名;
字段和字段之間用逗號,隔開。
查詢所有字段
select * from 表名;
使用*可以查詢所有字段,但是開發中不建議使用,由于系統會將*先轉換成字段,效率較低,可讀性差。
給查詢的列起別名
-
select 字段名 as 別名 from 表名;
select 字段名 as 別名 , 字段名 as 別名 from 表名;
使用as關鍵字起別名
注意:只是將顯示的查詢結果列名顯示為別名,原表列名不變,select語句只負責查詢,不會進行修改操作。
-
select 字段名 別名 from 表名;
as關鍵字可以省略
-
select 字段名 as '別 名' from 表名;
別名中如果有空格則可以使用單雙引號括起來。
注意:在所有數據庫中,字符串統一使用單引號括起來,單引號是標準,雙引號在oracle數據庫中使用不了,所以建議所有字符串都使用單引號括起來。
列參與數學計算
Example: select ename,sal*12 from emp;
字段可以使用數學表達式
Example: select ename,sal*12 as '年薪' from emp;
條件查詢
什么是條件查詢?
不是將表中的數據都查出來,是查詢出來符合條件的。
語法格式:
select 字段一,字段二,字段三... from 表名 where 條件;
都有哪些條件?
-
= 等于
Example: 查詢薪資等于800的員工姓名和編號
select empno , ename from emp where sal = 800;
-
<> 或 != 不等于
Example: 查詢薪資不等于800的員工姓名和編號
select empno , ename from emp where sal != 800;
-
< 小于
-
<= 小于等于
-
> 大于
-
>= 大于等于
-
between ... and ... 兩個值之間,等同于 >= and <=
使用between and 必須遵循左小右大格式且為閉區間。
-
is null 為空(is not null不為空)
-
and 并且
-
or 或者
Example: 找出工資大于2500并且部門編號為10或20的員工,注意優先級問題
and的優先級大于or
select * from emp where sal > 2500 and (deptno = 10 or deptno = 20);
-
in 包含,相當于多個or(not in 不在這個范圍內)
注意:not in在使用時要排除后面的NULL.
Example: 查詢薪資是800和1500的員工
select * from emp where sal in (800 , 1500);
注意in不是一個區間,后面跟的是具體的值。
-
not 取非
-
like 模糊查詢,支持%或者_匹配
% 匹配任意多個字符
_ 匹配任意一個字符
Example: 找出名字中含有o的
select ename from emp where ename like '%o%';
Example: 找出名字以t結尾的
select ename from emp where ename like '%t';
Example: 找出第二個字母為a的
select ename from emp where ename like '_a%';
-
\ 轉義字符
-
exists存在
select * from employee as e1 where exists (select * from employee as e2 where e1.name = e2.manager);
-
all
select name from employee where salary >= all(select salary from employee);
-
any
select name from employee where salary > any(select salary from employee);
排序
查詢所有員工薪資并排序(默認升序)。
select ename , sal from emp order by sal;
指定降序,指定升序。
降序:select ename , sal from emp order by sal desc;
升序:select ename , sal from emp order by sal asc;
多個字段排序
Example: 查詢員工名字和薪資,要求按照薪資排序,如果薪資一樣的話再按照名字升序排列。
select ename , sal from emp order by sal asc , ename asc;
tip:sal在前,起主導,只有sal相等的時候才會考慮啟用ename排序.
了解:根據字段位置排序
select ename , sal from emp order by 2;
2表示第二列,第二列為sal。
綜合案例
Example: 找出工資在1250到3000之間的員工信息,要求按照薪資降序排列。
select ename , sal from emp where sal between 1250 and 3000 order by sal desc;關鍵字順序不能改變!
去重【distinct】
把查詢結果去除重復記錄,原表數據不會刪改,需要使用關鍵字:distinct.
select distinct job from emp;
多個字段去重
注意:distinct只能出現在所有字段的最前方。
select distinct job,deptno from emp;
表示兩個字段聯合起來去重。
統計數量
select count(distinct job) from emp;
全部讀取【all】
all的用法與distinct相反,在查找時不使用distinct時默認使用all。
數據處理函數(單行處理函數)
數據處理函數又被稱為單行處理函數
單行處理函數特點:一個輸入對應一個輸出
和單行處理函數對應的是:多行處理函數
多行處理函數特點:多個輸入對應一個輸出
常見的單行處理函數
-
lower() 轉換小寫
select lower(ename) as ename from emp;
-
upper() 轉換大寫
-
substr() 取子串(substr(被截取的字符串 , 起始下標 , 截取的長度))
注意:起始下標從1開始!
-
concat() 字符串連接
-
length() 取長度
-
trim() 去空格
-
round(,) 四舍五入
select round(123.5 , 0) from emp;
0保留個位,1保留一位小數,-1保留十位,以此類推。
-
rand() 生成隨機數
select round(rand()*100 , 0); 生成100以內隨機數。
-
ifnull(數據,被當做哪個值) 可以將null轉換成一個具體值
ifnull是空處理函數,專門處理空的,
注意:在所有數據庫中,只要有NULL參與的數學運算,最終結果就是NULL。
Example: 計算年薪
select ename , (sal + ifnull(comm , 0))*12 as yearsal from emp;
-
case .. when .. then .. when .. then .. else .. end
Example: 當員工崗位為Manager時,工資上調10%,員工崗位為Salesman時,工資上調50%,其他正常
selectename,job,sal as oldsal,(case job when 'MANAGER' then sal*1.1 when 'SALESMAN' then sal*1.5 else sal end) as newsal fromemp;
分組函數(多行處理函數)
多行處理函數的特點:輸入多行,最終輸出一行。
共五個:
-
count() 計數
-
sum() 求和
-
avg() 平均值
-
max() 最大值 注:可以用limit或者not in取代
-
min() 最小值
Tip:
代碼示例: 語句1:select * from student limit 9,4 語句2:slect * from student limit 4 offset 9 // 語句1和2均返回表student的第10、11、12、13行 //語句2中的4表示返回4行,9表示從表的第十行開始SELECT * FROM orange LIMIT 5; //檢索前5條記錄(1-5)# Write your MySQL query statement below 查找第二高的薪水,如果沒有的話返回null select ifnull((select distinct salary fromemployee order by salary desc limit 1 offset 1), null) as 'SecondHighestSalary' ;
注意:分組函數在使用的時候必須先進行分組,然后才能用,如果沒有對數據進行分組,整張表默認為一組。
分組函數自動忽略NULL,不需要提前對NULL進行處理。
- count(具體字段) 表示統計該字段下所有不為NULL的元素的總數。
- count(*) 統計表當中的總行數。因為每一行記錄不可能都為NULL,一行數據中有一列不為NULL,則這行數據就是有效的。
分組函數不能夠直接使用在where子句中。
所有分組函數可以組合起來一起用。
分組查詢(重要)
什么是分組查詢?
在實際應用中,可能有這樣的需求,需要先進行分組,然后對每一組數據進行操作。
select ... from ... group by ...;
關鍵字執行順序
select... from... where... group by... order by...;以上關鍵字的順序不能顛倒!
執行順序如下(重要):
分組函數不能直接用在where后面因為where的執行優先度高,where執行的時候還沒有分組,
因為select在group by 后執行,可以先使用分組函數。
找出每個崗位的工資和?
實現思路:按照工作崗位分組,然后對工資求和。
select job , sum(sal) from emp group by job;
以上語句的執行順序:
先從emp表中查詢數據,根據job字段進行分組,然后對每一組數據進行sum(sal)。
重點結論:
在一條select語句當中,如果有group by 語句的話,select 后面只能跟參加分組的字段,以及分組函數。
使用having可以對分完組的數據進一步過濾
having不能單獨使用,having不能代替where,having必須和group by 聯合使用。
Example: 找出每個部門最高薪資,要求顯示最高薪資大于3000的
select deptno , max(sal) from emp group by deptno having max(sal) > 3000;
注意:當where和having都可以使用時優先使用where。
單表查詢總結
select... from... where... group by... having... order by...;執行順序:
從某張表中查詢數據,
先經過where條件篩選出有價值的數據,
對這些數據進行分組,
分組后使用having繼續篩選,
select查詢出來,
最后排序輸出。
Example: 找出每個崗位的平均薪資,要求顯示平均薪資大于1500的,除MANAGER崗位外,按照平均薪資降序排列。
selectjob , avg(sal) as avgsal from emp where job != 'manager' group by job having avg(sal) > 1500 order by avgsal desc;連接查詢
什么是連接查詢?
從一張表中單獨查詢,稱為單表查詢。emp表和dept表聯合起來查詢數據,從emp表中取員工名字,從dept表中取部門名字。
這種跨表查詢,多張表聯合起來查詢數據,被稱為連接查詢。
連接查詢的分類
-
根據語法的年代分類:
- SQL92:1992年的時候出現的語法
- SQL99:1999年的時候出現的語法
-
根據表連接方式分類:
-
內連接:
- 等值連接
- 非等值連接
- 自連接
-
外連接
- 左外連接(左連接)
- 右外連接(右連接)
-
全連接
-
笛卡爾積現象
select ename , dname from emp , dept;
當兩張表進行連接查詢時,沒有任何條件限制的時候,最終查詢結果的條數,是兩張表條數的乘積,這種現象被稱為“笛卡爾積現象”。
避免笛卡爾積現象
連接時加條件,滿足條件的記錄被篩選出來,
但是在查詢過程中的匹配次數并,沒有減少。
select ename , dname from emp , dept where emp.deptno = dept.deptno;
【重要】表起別名,會有效率提升
selecte.ename , d.dname fromemp e , dept d wheree.deptno = d.deptno; // SQL92語法注意:通過笛卡爾積現象得出,表的連接次數越多效率越低,盡量避免標的連接次數。
內連接之等值連接
Example: 查詢每個員工所在的部門名稱,顯示員工名和部門名,emp e 和dept d 表進行連接,條件是:e.deptmo = d.deptno.
-
SQL92 語法
selecte.ename , d.dname fromemp e , dept d wheree.deptno = d.deptno;【缺點】結構不清晰,表的連接條件,和后期的進一步篩選,都放到了where后面.
-
SQL99 語法
selecte.ename , d.dname fromemp e inner join // inner可以省略(帶著inner可讀性更好)dept d on e.deptno = d.deptno; // 條件是等量關系,所以被稱為等值連接【優點】表連接條件是獨立的,連接之后如果需要進一步篩選,再往后繼續添加where.
內連接之非等值連接
Example: 找出每個員工的薪資等級,要求顯示員工名,薪資,薪資等級。
selecte.ename , e.sal , s.grade fromemp e inner joinsalgrade s one.sal between s.losal and s.hisal;內連接之自連接
Example: 查詢員工的上級領導,要求顯示員工名和對應的領導名。
技巧:一張表看成兩張表
selecta.ename as 員工名 , b.ename as 領導名 fromemp a inner joinemp b ona.mgr = b.empno;外連接(右外連接)
select e.ename , d.dname from emp e right join dept d one.deptno = d.deptno;【right】代表將join關鍵字右邊的這張表看成主表,主要是為了將這張表的數據全部查詢出來,捎帶著關聯查詢左邊的表。
在外連接當中,兩張表連接,產生了主次關系
外連接(左外連接)
select e.ename , d.dname from dept d left outer join emp e // outer可以省略與inner同理 one.deptno = d.deptno;右連接和左連接可以寫法互換。
外連接(Full Outer Join)
會顯示兩個表的全部內容
多表連接
語法:
select... froma joinb ona和b的連接條件 joinc ona和c的連接條件 right joind ona和d的連接條件;一條SQL中內連接和外連接可以混合,都可以出現。
Example: 找出每個員工的部門名稱 ,領導名以及工資等級,要求顯示員工名,領導名,部門名,薪資,薪資等級。
selecte.ename , l.ename , d.dname , e.sal , s.grade fromemp e joindept d one.deptno = d.deptno joinsalgrade s one.sal between s.losal and s.hisal left joinemp l one.mgr = l.empno;子查詢
什么是子查詢?
select語句中嵌套select語句,被嵌套的select語句稱為子查詢。
子查詢可以出現在哪里?
select..(select) from..(select) where..(select);where子句中的子查詢
Example: 找出比最低工資高的員工姓名和工資。
實現思路:
-
第一步:查詢最低工資是多少
select min(sal) from emp;
-
第二步:找出大于800的
select ename , sal from emp where sal > 800;
-
第三步:合并
select ename , sal from emp where sal > (select min(sal) from emp);
from字句中的子查詢
注意:from后面的子查詢,可以將子查詢的查詢結果當做一張臨時表。
Example: 找出每個崗位的平均工資的薪資等級。
實現思路:
-
第一步:找出每個崗位的平均工資(按照崗位分組求平均值)
select job , avg(sal) from emp group by job;
-
第二步:
將第一步的查詢結果當成一張臨時表
-
第三部:連接
selectt.* , s.grade from(select job , avg(sal) as avgsal from emp group by job) t joinsalgrade s ont.avgsal between s.losal and s.hisal;
select后面出現的子查詢(了解即可)
Example: 找出每個員工的部門名稱,要求顯示員工名,部門名。
select e.ename , (select d.dname from dept d where e.deptno = d.deptno) as dname from emp e;
注意:對于select 后面的子查詢來說,這個子查詢只能一次返回1條結果,多于一條,就報錯了。
union合并查詢結果集
Example: 查詢工作崗位是MANAGER和SALSMAN員工。
-
select ename , job from emp where job = 'manager' or job = 'salesman';
-
select ename , job from emp where job in('manager' , 'salesman');
- select ename , job from emp where job = 'manager'
union
select ename , job from emp where job = 'salesman';
union的效率要高一些,對于表連接來說,每連接一次新表,則匹配的次數滿足笛卡爾積,但是union可以在減少匹配次數的情況下完成兩個結果集的拼接。
注意:union在進行結果集合并的時候,要求兩個結果集的列數相同。
limit(重要)
limit是將查詢結果集的一部分取出來,通常使用在分頁查詢當中。
分頁的作用是提高用戶的體驗,因為一次全部都查出來,用戶體驗差,可以一頁一頁翻頁看。
limit的使用
-
完整用法:limit startIndex , length
startIndex是起始下標(從0開始),length是長度。
-
缺省用法:limit 5這是取前五。
Example: 按照薪資降序,取出排名在前五名的員工。
selectename , sal fromemp order by sal desc limit 5; // 取前五注意:在MySQL中limit 在order by 之后執行!
分頁
每頁顯示pageSize條記錄
第pageNo頁:limit (pageNo - 1) * pageSize , pageSize
DDL
表的創建(create)
注意:創建的數據庫、表、索引、列和別名用的是引用符是反勾號(`) ,用單引號會出現奇怪的語法問題,單引號主要用于字符串。
建表的語法格式
create table 表名(字段名1 數據類型,字段名2 數據類型,字段名3 數據類型 );- 表名:建議以 t_ 或者 tbl_開始,可讀性強。見名知意。
- 字段名:見名知意。
表名和字段名都屬于標識符。
MySQL中的數據類型(常用)
-
varchar(最長255)
可變長度字符串
比較智能,節省空間
會根據實際的數據長度動態分配空間。
- 優點:節省空間
- 缺點:需要動態分配空間,速度慢
-
char(最長255)
定長字符串
不管實際的數據長度是多少
分配固定長度的空間去存儲數據
使用不恰當的時候,可能導致空間的浪費。
- 優點:不需要動態分配空間,速度快
- 缺點:使用不當可能導致空間的浪費
-
int(最長11)
數字中的整數型
-
bigint
數字中的長整型
-
float
單精度浮點型數據
-
double
雙精度浮點型數據
-
date
短日期類型
-
datetime
長日期類型
-
clob(Character Large Object)
字符大對象
最多可以存儲4G的字符串
超過255個字符串的都要采用CLOB字符大對象來存儲。
-
blob(Binary Large Object)
二進制大對象
專門用來存儲圖片,聲音,視頻等流媒體數據
在BLOG類型的字段上插入數據的時候,例如插入一個圖片,視頻等,
需要使用IO流。
創建一個學生表
學號 , 姓名 , 年齡 , 性別 , 郵箱地址
create table t_student(no int,name varchar(32),sex char(1),age int(3),email varchar(255) );表的復制
create table emp2 as select * from emp;
原理:
將一個查詢結果當做一張表創建,
這個可以快速完成表的復制,
表創建的同時,數據也存在。
刪除表(drop)
drop table t_student; // 當這張表不存在時會報錯
drop table if exists t_student; // 如果表存在的話刪除
快速刪除(truncate)
-
delete語句的刪除數據原理:
表中的數據刪除了,但數據在硬盤上的真實存儲空間不會被釋放。
- 缺點:刪除效率低
- 優點:支持回滾
-
truncate語句的刪除數據原理:
刪除效率高,表被一次截斷,物理刪除
- 缺點:不支持回滾
- 優點:快速
用法:
truncate table 表名;
alter
-
Add column:
alter table 表名 add 列名 數據類型 [約束等];
-
Drop column:
alter table 表名 drop column 列名;
-
Modify column name and definition:
alter table 表名 change column 列名 新列名 數據類型 [約束等];
-
Modify column definition only:
alter table 表名 modify column 列名 數據類型 [約束等];
-
Add constraints:
alter table 表名 add constraint 約束名 約束(列名);
Example:
alter table emp add constraint empno_unique unique(empno);
alter table staff add constraint fk_staff_staff foreign key(branchNo) references branch(branchNo);
-
Removing Constraints:
alter table 表名 drop index 約束名 | drop foreign key 約束名 | drop primary key ;
Example:
alter table staff drop primary key;
alter table branch drop index ck_branch;
DML
insert
插入數據
語法格式:
insert into 表名(字段名1 , 字段名2 , 字段名3...) values(值1 , 值2 , 值3...);
注意:字段名要和值一一對應(數量對應 , 數據類型對應)。
Example:
insert into t_student(no , name , sex , age , email) values(1 , 'zhangsan' , 'm' , 20 , 'zhangsan@email.com');
注意:insert語句但凡是執行成功了,那么必然會多一條記錄,沒有給其他字段指定值的話,默認值是NULL。
insert語句中的“字段名”可以省略,如果省略的話,等于都寫上了,所以值也要都寫上。
insert into t_student values(1 , 'zhangsan' , 'm' , 20 , 'zhangsan@email.com');
設置默認值
create table t_student(no int,name varchar(32),sex char(1) default 'm', // 設置默認值age int(3),email varchar(255) );insert插入日期
- str_to_date: 將字符串varchar類型轉成date類型
數據庫命名規范:所有的標識符全部都是小寫,單詞和單詞之間使用下劃線進行銜接。
語法格式:
str_to_date('字符串日期' , '日期格式')
如果你提供的日期字符串是 %Y-%m-%d 格式,就不需要轉格式,系統會自動轉換。
MySQL日期格式:
- %Y 年
- %m 月
- %d 日
- %h 時
- %i 分
- %s 秒
- date_format: 將date類型轉換成具有一定格式的varchar字符串類型
語法格式:
date_format(日期類型數據 , '日期格式')
這個函數通常使用在查詢日期方面,設置日期的展示格式,
不設置展示格式則將使用MySQL默認日期格式。
Example:
select id,name,date_format(birth , '%Y/%m/%d') from t_user;
date 和 datetime 兩個類型的區別
date是短日期,只包括年月日信息,
datetime是長日期,包括年月日時分秒信息。
MySQL長日期默認格式:%Y-%m-%d %h:%i:%s
在MySQL當中獲取當前系統時間:now()函數,并且獲取的時間帶有時分秒信息。
insert插入多條記錄
語法:
insert into 表名(字段名1 , 字段名2...) values() , () , ()...;
將查詢結果插入表
insert into dept_bak select * from dept; // 不常見
update
語法格式:
update 表名 set 字段名1 = 值1 , 字段名2 = 值2 , 字段名3 = 值3 ... where 條件;
注意:沒有限制條件會導致所有數據全部更新。
Example:
update t_user set name = 'jack' , birth = '2000-10-13' where id = 2;
update emp set sal = sai * 12;
delete
語法格式:
delete from 表名 where 條件;
Example:
delete from emp where empno = 1;
注意:沒有限制條件,整張表數據會全部刪除。
delete from t_user; // 刪除所有數據
約束(constraint)
基本概念
什么是約束
約束對應的英語單詞:constraint
在創建表的時候,我們可以給表中的字段加上一些約束,來保證這個表中數據的完整性,有效性。
約束的作用就是為了保證:表中的數據有效。
約束包括什么
- 非空約束:not null
- 唯一性約束:unique
- 主鍵約束:primary key (簡稱PK)
- 外鍵約束:foreign key (簡稱FK)
- 檢查約束:check (MySQL不支持 , oracle支持)
非空約束(not null)
只允許列級約束
非空約束約束的字段不能為NULL。
drop table if exists t_vip; create table t_vip(id int,name varchar(255) not null );插曲:
xxxx.sql這種文件被稱為sql腳本文件,腳本文件中編寫了大量sql語句,我們執行腳本文件時,該文件中所有sql語句會全部執行。
source 文件路徑
唯一性約束(unique)
支持列級約束和表級約束
唯一性約束unique約束的字段不能重復,但是可以為NULL。
create table t_vip(id int,name varchar(255) unique // 列級約束 );聯合唯一:
Example: name 和 email 兩個字段聯合起來具有唯一性。
creat table t_vip(id inr,name varchar(255),email varchar(255), // 注意逗號unique(name , email) // 表級約束 或者 constraint diy_constraint_name unique(name , email) );什么時候使用表級約束?
需要給多個字段聯合起來添加某一個約束的時候,需要使用表級約束。
聯合unique和not null:
creat table t_vip(id int,name varchar(255) not null unique );注意:在MySQL中,如果一個字段同時被not null和unique約束的話,
該字段自動變成主鍵字段(oracle中不同)。
主鍵約束(primary key , PK)
支持列級約束和表級約束
相關術語
主鍵約束:一種約束類型
主鍵字段:該字段上添加了主鍵約束,這樣的字段叫做主鍵字段
主鍵值:主鍵字段中每一個值叫做主鍵值
主鍵概念及作用
主鍵是每一行記錄的唯一標識,主鍵是每一行記錄的身份證號。
注意:任何一張表都應該有主鍵,沒有主鍵,表無效。
主鍵的特征:not null + unique(主鍵值不能是NULL,同時也不能重復!)
添加主鍵約束
- 列級約束
- 表級約束
主鍵自動維護機制(auto_increment)
create table t_vip(id int primary key auto_increment,name varchar(255) );insert into t_vip(name) values('zhangsan'); insert into t_vip(name) values('zhangsan'); insert into t_vip(name) values('zhangsan'); insert into t_vip(name) values('zhangsan'); insert into t_vip(name) values('zhangsan'); // 自動添加主鍵值id建議
-
注意:在實際開發中不建議使用符合主鍵,建議使用單一主鍵。并且一張表中,主鍵只能有一個!!!
-
主鍵建議使用:int , bigint , char等類型,不建議使用varchar 來做主鍵,主鍵值一般都是數字,一般都是定長的。
-
在實際開發中一般使用自然主鍵,業務主鍵不建議使用。
外鍵約束(foreign key , FK)
Example: “ 請設計數據庫表,來描述“班級和學生”的信息。
設計方案:設計兩張表,班級一張表,學生一張表,班級為父表,學生為子表,為學生表添加外鍵約束。
注意:
- t_class是父表
- t_student是子表
- 刪除表的順序:先子后父
- 創建表的數據:先父后子
- 刪除數據的順序:先子后父
- 插入數據的順序:先父后子
注意:
-
子表中的外鍵引用的父表中的某個字段,被引用的這個字段必須是主鍵嗎?
答:不一定是主鍵,但至少具有unique約束。
-
外鍵可以為NULL嗎?
答:外鍵值可以為NULL。
主外鍵關聯刪除
主外鍵關聯,當刪除的是父表數據,參照這些要刪除的數據,Oracle有三種處理方式:
禁止刪除,也是Oracle默認方法。
將參照要刪除數據的子表對應數據置空:ON DELETE SET NULL
將參照要刪除數據的子表對應數據刪除:ON UPDATE CASCADE
相應語句添加在外鍵約束后即可。
存儲引擎(了解)
概念
存儲引擎是MySQL中特有的一個術語,
實際上存儲引擎是一個表存儲/組織數據的方式,
不同的數據引擎,表存儲數據的方式不同。
給表添加/指定存儲引擎
create table t_product(id int primary key,name varchar(255) ) engine = InnoDB default charset = utf8;-
查看MySQL支持的存儲引擎
show engines \G
MySQL支持九大存儲引擎,版本不同支持情況不同。
-
顯示表的存儲引擎等信息:
show create table 表名;
-
添加/指定存儲引擎
在建表的時候可以在最后小括號)的右邊使用:
ENGINE來指定存儲引擎,
CHARSET來指定這張表的字符編碼方式。
MySQL的默認存儲引擎是:InnoDB,
MySQL的默認字符編碼方式是:utf8。
常用的存儲引擎
MyISAM存儲引擎
-
它管理的表具有以下特征:
使用三個文件表示每個表
- 格式文件- 存儲表結構的定義(mytable.frm)
- 數據文件- 存儲表行的內容(mytable.MYD)
- 索引文件- 存儲表上的索引(mytable.MYI)
注意:對于一張表來說,只要是主鍵或者加有unique 約束的字段上會自動創建索引。
-
MyISAM的特點:
可被轉換為壓縮,只讀表來節省空間。但是不支持事務機制,安全性低。
InnoDB存儲引擎
-
這是MySQL默認的存儲引擎,同時也是一個重量級的存儲引擎。
-
InnoDB支持事務,支持數據庫崩潰后自動恢復機制。
-
InnoDB的特點:
支持事務,非常安全,但是效率不是很高,并且也不能壓縮,不能轉換為只讀,不能很好的節省存儲空間。
-
它管理的表具有下列主要特征:
- 每個 InnoDB 表在數據庫目錄中以.frm 格式文件表示
- InnoDB 表空間 tablespace 被用于存儲表的內容(表空間是一個邏輯名稱。表空間存儲數據+索引)
- 提供一組用來記錄事務性活動的日志文件
- 用 COMMIT(提交)、SAVEPOINT 及ROLLBACK(回滾)支持事務處理
- 提供全 ACID 兼容
- 在 MySQL 服務器崩潰后提供自動恢復
- 多版本(MVCC)和行級鎖定
- 支持外鍵及引用的完整性,包括級聯刪除和更新
MEMORY存儲引擎
- 使用 MEMORY 存儲引擎的表,其數據存儲在內存中,且行的長度固定,這兩個特點使得 MEMORY 存儲引擎非常快。
- MEMORY 存儲引擎管理的表具有下列特征:
- 在數據庫目錄內,每個表均以.frm 格式的文件表示。
- 表數據及索引被存儲在內存中。
- 表級鎖機制。
- 不能包含 TEXT 或 BLOB 字段。
- MEMORY 存儲引擎以前被稱為HEAP 引擎。
- MEMORY引擎優點:查詢效率是最高的。不需要和硬盤交互。
- MEMORY引擎缺點:不安全,關機之后數據消失。因為數據和索引都是在內存當中。
事務(transaction)
概述
什么是事務?
一個事務就是一個完整的業務邏輯,是一個最小的工作單元,不可再分。
本質:批量的DML語句同時成功或者同時失敗。
Example: 假設轉賬,從A賬戶向B賬戶中轉賬10000.
將A賬戶的錢減去10000(update語句),
將B賬戶的錢加上10000(update語句),
這就是一個完整的業務邏輯。
以上的操作是一個最小的工作單元,要么同時成功,要么同時失敗,不可再分。
這兩個update語句要求必須同時成功或者同時失敗,這樣才能保證錢是正確的。
DML與事務
只有DML語句才有事務這一概念。
- insert
- delete
- update
只有以上三個語句是對數據庫表中數據進行增刪改的,
只要你的操作一旦涉及到數據的增,刪,改,那么就一定要考慮安全問題。
數據安全在第一位!
事務是如何做到多條DML語句同時成功和同時失敗的?
InnoDB存儲引擎:提供一組用來記錄事務性活動的日志文件
Example:
事務開啟了: insert insert insert delete update update upadte 事務結束了。在事務的執行過程中,每一條DML的操作都會記錄到“事務性活動的日志文件”中。
在事務的執行過程中,我們可以提交事務,也可以回滾事務。
-
提交事務:
清空事務性活動的日志文件,將數據全部徹底持久化到數據庫表中。
提交事務標志著,事務的結束。并且是一種全部成功的結束。
-
回滾事務:
將之前所有的DML操作全部撤銷,并且清空事務性活動的日志文件。
回滾事務標志著,事務的結束。并且是一種全部失敗的結束。
提交事務與回滾事務
提交事務:commit語句
回滾事務:rollback語句**(回滾永遠都是只能回滾到上一次的提交點!)**
-
在MySQL當中默認的事務行為是怎樣的?
MySQL默認情況下是支持自動提交事務的(自動提交)。
-
什么是自動提交?
每執行一條DML語句,則提交一次!
注:這種自動提交實際上是不符合我們的開發習慣,因為一個業務
通常是需要多條DML語句共同執行才能完成的,為了保證數據
的安全,必須要求同時成功之后再提交,所以不能執行一條
就提交一條。 -
如何關閉MySQL自動提交機制?
先執行命令start transaction;
Example: 事務演示(回滾事務)
start transaction;insert into t_test values(1 , 'Jack' , 'm'); insert into t_test values(2 , 'Blue' , 'm'); insert into t_test values(3 , 'Anmory' , 'f');select * from t_test;rollback;select * from t_test;
Example: 事務演示(提交事務)
start transaction;insert into t_test values(1 , 'Jack' , 'm'); insert into t_test values(2 , 'Blue' , 'm'); insert into t_test values(3 , 'Anmory' , 'f');commit;select * from t_test;rollback;select * from t_test;事務的四個特性
-
Atomicity(原子性)
說明事務是最小的工作單元,不可再分。
-
Consistency(一致性)
所有事務要求,在同一個事務當中,所有操作必須同時成功,或者同時失敗,以保證數據的一致性。
-
Isolation(隔離性)
A事務和B事務之間具有一定的隔離。
-
Durability(持久性)
事務最終結束的一個保障。事務提交,就相當于將沒有保存到硬盤上的數據保存到硬盤上。
事務隔離級別
-
讀未提交:read uncommitted(最低隔離級別)沒有提交就讀到了
事務A可以讀取到事務B未提交的數據。
這種隔離級別存在的問題:臟讀現象(Dirty Read)
這種隔離級別一般都是理論上的,大多數數據庫都是從讀已提交開始。
-
讀已提交:read committed 提交之后才能讀到
事務A只能讀取到事務B提交之后的數據。
這種隔離級別解決了臟讀現象,但是存在不可重復讀取數據的問題。
注:什么是不可重復讀取數據?
? 在事務開啟之后,第一次讀到的數據是3條,當前事務還沒有結束,
? 可能第二次再讀取的時候,讀到的數據是4條,
? 3不等于4稱為不可重復讀取。
這種隔離級別是比較真實的數據,每一次讀到的數據是絕對的真實。
oracle數據庫默認的隔離級別是:read committed
-
可重復讀:repeatable read 提交之后也讀不到,永遠讀取的都是剛開啟事務時的數據
事務A開啟之后,不管是多久,每一次在事務A中讀取到的數據都是一致的。
即使事務B將數據已經修改,并且提交了,事務A讀取到的數據還是沒有發生改變,這就是可重復讀。
可重復讀可能存在會出現幻影讀的現象,每一次讀取到的數據都是幻想,不夠真實。
Example:
早晨9點開始開啟了事務,只要事務不結束,到晚上9點,讀到的數據還是那樣!讀到的是假象。不夠絕對的真實。
repeatable read為MySQL默認隔離級別
-
序列化/串行化:serializable(最高隔離級別)
這是最高隔離級別,效率最低。解決了所有的問題。
這種隔離級別表示事務排隊,不能并發!
synchronized,線程同步(事務同步)
每一次讀取到的數據都是最真實的,并且效率是最低的。
查看和設置隔離級別
-
查看隔離級別
SELECT @@tx_isolation;
-
設置全局事務隔離級別
set global transaction isolation level 隔離級別名稱;
索引(index)
什么是索引?
索引是在數據庫表的字段上添加的,是為了提高查詢效率存在的一種機制。
一張表的一個字段可以添加一個索引,當然,多個字段聯合起來也可以添加索引。
索引相當于一本書的目錄,是為了縮小掃描范圍而存在的一種機制。
MySQL在查詢方面的主要兩種方式:
- 全表掃描
- 根據索引檢索
**MySQL中的索引主要依賴B+ 樹實現。**遵循左小右大原則存放,采用中序遍歷遍歷取數據。
索引的實現原理
注意:
-
在任何數據庫當中主鍵上都會自動添加索引對象,另外在MySQL中,一個字段上如果有unique約束的話,也會自動創建索引對象。
-
在任何數據庫當中,任何一張表的任何一條記錄在硬盤存儲上都有一個硬盤的物理存儲編號。
-
在mysql當中,索引是一個單獨的對象,不同的存儲引擎以不同的形式存在,
在MyISAM存儲引擎中,索引存儲在一個.MYI文件中
在InnoDB存儲引擎中,索引存儲在一個邏輯名稱叫做tablespace的當中。
在MEMORY存儲引擎當中,索引被存儲在內存當中。
不管索引存儲在哪里,索引在mysql當中都是一個樹的形式存在(B+ 樹)。
添加索引的條件
- 條件1:數據量龐大(到底有多么龐大算龐大,這個需要測試,因為每一個硬件環境不同)
- 條件2:該字段經常出現在where的后面,以條件的形式存在,也就是說這個字段總是被掃描
- 條件3:該字段很少的DML(insert delete update)操作(因為DML之后,索引需要重新排序)
建議不要隨意添加索引,因為索引也是需要維護的,太多的話反而會降低系統的性能。
建議通過主鍵查詢,建議通過unique約束的字段進行查詢,效率是比較高的。
索引的創建和刪除
-
創建索引
create index 索引名 on 表名(字段名);
Example: 給emp表的ename字段添加索引,起名:emp_ename_index
create index emp_ename_index on emp(ename);
-
刪除索引
drop index 索引名 on 表名;
Example:
drop index emp_ename_index on emp;
查看一個SQL語句是否使用了索引進行檢索
explain select * from emp where ename = 'king';
索引失效
-
第一種情況
select * from emp where ename = '%T';
ename 上即使添加了索引,也不會走索引,因為在模糊匹配當中以%開頭了,
盡量避免模糊查詢時以%開始,這是一種優化策略/手段。
-
第二種情況
使用or的時候會失效,如果使用or那么要求or兩邊的條件字段都要有索引,才會走索引,
如果其中一邊有一個字段沒有索引,那么另一個字段上的索引也會失效。所以這就是為什么不建議使用or的原因。
建議使用union,union不會使索引失效
-
第三種情況
使用復合索引的時候,沒有使用左側的列查找,索引失效。
-
什么是復合索引?
兩個或者更多字段聯合起來添加一個索引,叫做復合索引。
create index emp_job_sal_index on emp(job , sal);
Example:
explain select sal from emp where sal = 800; // 索引失效
-
-
第四種情況
在where中索引列參加了運算,索引失效。
create index emp_sal_index on emp(sal);explain select * from emp where sal + 1 = 800; // 索引失效 -
失效的第五種情況
在where當中,索引列使用了函數
explain select * from emp where lower(name) = 'smith'; // 索引失效
索引的分類
索引是各種數據庫進行優化的重要手段。
優化的時候優先考慮的因素就是索引,
索引的分類:
- 單一索引:一個字段上添加索引
- 復合索引:兩個字段或者更多字段上添加索引
- 主鍵索引:主鍵上添加索引
- 唯一性索引:具有unique約束的字段上添加索引
- …
注意:唯一性比較弱的字段上添加索引用處不大,越唯一效率越高。
視圖(view)
什么是視圖?
view:站在不同角度去看待同一份數據。
視圖的創建和刪除
-
創建視圖對象
create view dept2_view as select * from dept2; // dept2_view 為自定義視圖名,dept2為表名
-
刪除視圖對象
drop view dept2_view;
注意:只有DQL語句才能以view的形式創建
視圖的作用
方便,簡化開發,利于維護
我們可以面向視圖對象進行增刪改查,對視圖對象的增刪改查,會導致原表被操作。
視圖的特點:通過對視圖的操作,會影響到原表數據。
-
面向視圖查詢
select * from dept2_view;
-
面向視圖插入
insert into dept2_view(deptno , dname , loc) values(60 , 'sales' , 'xian');
-
面向視圖刪除
delete from dept2_view;
Example:
// 創建視圖對象 create view emp_dept_view asselect e.ename , e.sal , d.dnamefromemp ejoindept done.deptno = d.deptno;// 面向視圖更新 update emp_dept_view set sal = 1000 where dname = 'accounting';// 原表數據被更新 select * from emp;假設有一條非常復雜的SQL語句,而這條SQL語句需要在不同的位置上反復使用。
每一次使用這個sql語句的時候都需要重新編寫,很長,很麻煩,怎么辦?
可以把這條復雜的SQL語句以視圖對象的形式新建。
在需要編寫這條SQL語句的位置直接使用視圖對象,可以大大簡化開發。
并且利于后期的維護,因為修改的時候也只需要修改一個位置就行,只需要修改視圖對象所映射的SQL語句。
我們以后面向視圖開發的時候,使用視圖的時候可以像使用table一樣。
可以對視圖進行增刪改查等操作。視圖不是在內存當中,視圖對象也是存儲在硬盤上的,不會消失。
視圖對應的語句只能是DQL語句。但是視圖對象創建完成之后,可以對視圖進行增刪改查等操作。
增刪改查,又叫做:CRUD
- C:Create(增)
- R:Retrive(查:檢索)
- U:Update(改)
- D:Delete(刪)
DBA命令
重點掌握:數據的導出和導入(數據的備份)
數據導出
-
導出數據庫
注意:在windows的dos命令行窗口執行
mysqldump test>D:\test.sql -uroot -p123456 // test為數據庫名稱,后面為文件導出路徑,最后為密碼
-
導出指定的表
mysqldump test emp>D:\emp.sql -uroot -p123456
數據導入
source D:\test.sql // 文件路徑
數據庫設計三范式
概述
- 第一范式:要求任何一個表必須有主鍵,每一個字段原子性不可再分。
- 第二范式:建立在第一范式的基礎之上,要求所有非主鍵字段完全依賴主鍵,不要產生部分依賴。
- 第三范式:建立在第二范式基礎之上,要求所有非主鍵字段直接依賴主鍵,不要產生依賴傳遞。
使用范式設計數據庫表,可以避免表中數據冗余,空間的浪費。
第一范式
最核心,最重要的范式,所有表的設計都需要滿足。
必須有主鍵,并且每一個字段都是原子性不可再分。
背口訣:
一對一,外鍵唯一!!!
第二范式
建立在第一范式的基礎之上,要求所有非主鍵字段完全依賴主鍵,不要產生部分依賴。
背口訣:
多對多,三張表,關系表兩個外鍵!!!
第三范式
建立在第二范式基礎之上,要求所有非主鍵字段直接依賴主鍵,不要產生依賴傳遞。
背口訣:
一對多,兩張表,多的表加外鍵!!!
補充說明
數據庫設計三范式是理論上的。
實踐和理論有的時候有偏差。
最終的目的都是為了滿足客戶的需求,有的時候會拿冗余換執行速度。
因為在SQL當中,表和表之間連接次數越多,效率越低(笛卡爾積)。
有的時候可能會存在冗余,但是為了減少表的連接次數,這樣做也是合理的,并且對于開發人員來說,SQL語句的編寫難度也會降低。
Author: Lorain.
Completion time: 2021/9/9
總結
以上是生活随笔為你收集整理的MySQL基础(学习笔记)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于W5500/LAN8720与STM3
- 下一篇: java基础--接口