這是一篇mysql的學習筆記,整理結合了網上搜索的教程以及自己看的視頻教程,看完這篇能夠滿足80%的日常開發了。
菜鳥教程:https://www.runoob.com/mysql/mysql-tutorial.html
MySQL參考手冊中文版:https://tool.oschina.net/apidocs/apidoc?api=mysql-5.1-zh
1 前言
1.1 什么是關系型數據庫
MySQL 為關系型數據庫。
關系數據庫管理系統RDBMS(Relational Database Management System)的特點:
- 數據以表格的形式出現
- 每行為各種記錄
- 每列為記錄所對應的數據域
- 許多的行和列組成一張表單
- 若干的表單組成database
在(數據)表中有行、列之分。在多數數據庫系統中,數據表中的列稱為字段,有的也稱為域,數據表中的行稱為記錄。一個(數據)表由行(記錄)和列(字段)構成,組成一個二維關系表。而一個真正的數據庫由若干張表、視圖及相關的文件等組成一個統一的相關聯的系統。
1.2 RDBMS 術語
在我們開始學習MySQL 數據庫前,讓我們先了解下RDBMS的一些術語:
- 數據庫: 數據庫是一些關聯表的集合。
- 數據表: 表是數據的矩陣。在一個數據庫中的表看起來像一個簡單的電子表格。
- 列: 一列(數據元素) 包含了相同的數據, 例如郵政編碼的數據。
- 行:一行(=元組,或記錄)是一組相關的數據,例如一條用戶訂閱的數據。
- 冗余:存儲兩倍數據,冗余降低了性能,但提高了數據的安全性。
- 主鍵:主鍵是唯一的。一個數據表中只能包含一個主鍵。你可以使用主鍵來查詢數據。
- 外鍵:外鍵用於關聯兩個表。
- 復合鍵:復合鍵(組合鍵)將多個列作為一個索引鍵,一般用於復合索引。
- 索引:使用索引可快速訪問數據庫表中的特定信息。索引是對數據庫表中一列或多列的值進行排序的一種結構。類似於書籍的目錄。
- 參照完整性: 參照的完整性要求關系中不允許引用不存在的實體,是關系模型必須滿足的完整性約束條件,目的是保證數據的一致性。
- 表頭(header): 每一列的名稱;
- 行(row): 每一行用來描述某條記錄的具體信息;
- 值(value): 行的具體信息, 每個值必須與該列的數據類型相同;
- 鍵(key): 鍵的值在當前列中具有唯一性。
1.3 與非關系型數據對比
1)關系型數據庫
最典型的數據結構是表,由二維表及其之間的聯系所組成的一個數據組織
優點:
- 易於維護:都是使用表結構,格式一致;
- 使用方便:SQL語言通用,可用於復雜查詢;
- 復雜操作:支持SQL,可用於一個表以及多個表之間非常復雜的查詢。
缺點:
- 讀寫性能比較差,尤其是海量數據的高效率讀寫;
- 固定的表結構,靈活度稍欠;
- 高並發讀寫需求,傳統關系型數據庫來說,硬盤I/O是一個很大的瓶頸。
2)非關系型數據庫
非關系型數據庫嚴格上不是一種數據庫,應該是一種數據結構化存儲方法的集合,可以是文檔或者鍵值對等。
優點:
- 格式靈活:存儲數據的格式可以是key,value形式、文檔形式、圖片形式等等,文檔形式、圖片形式等等,使用靈活,應用場景廣泛,而關系型數據庫則只支持基礎類型。
- 速度快:nosql可以使用硬盤或內存作為載體,而關系型數據庫只能使用硬盤;
- 高擴展性;
- 成本低:nosql數據庫部署簡單,基本都是開源軟件。
缺點:
- 不提供sql支持,學習和使用成本較高。
- 數據結構相對復雜,復雜查詢方面稍欠。
2 環境搭建
方法一: 使用phpstudy快速搭建(如果是學習建議用此方法)。
方法二:自己下載源碼搭建,這里以windows下搭建為例。
mysql下載地址:https://dev.mysql.com/downloads/mysql/
1)將下好的壓縮包解壓
這里壓縮在:C:\Program Files\mysql-8.0.15-winx64
2)在安裝目錄下,新建my.ini文件,
文件內容如下,其中basedir\datadir根據實際情況修改:
注意這里保存時編碼為ansi,用記事本編輯就好了
[mysqld]
# 設置3306端口
port=3306
# 設置mysql的安裝目錄
basedir=C:\Program Files\mysql-8.0.15-winx64
# 設置mysql數據庫的數據的存放目錄
datadir=C:\Program Files\mysql-8.0.15-winx64\data
# 允許最大連接數
max_connections=200
# 允許連接失敗的次數。
max_connect_errors=10
# 服務端使用的字符集默認為UTF8
character-set-server=utf8
# 創建新表時將使用的默認存儲引擎
default-storage-engine=INNODB
# 默認使用“mysql_native_password”插件認證
#mysql_native_password
default_authentication_plugin=mysql_native_password
[mysql]
# 設置mysql客戶端默認字符集
default-character-set=utf8
[client]
# 設置mysql客戶端連接服務端時默認使用的端口
port=3306
default-character-set=utf8
3)配置環境變量:
我的電腦右鍵-->屬性-->高級系統設置-->環境變量-->修改PATH,將mysql路徑添加進去,
例如:C:\Program Files\mysql-8.0.15-winx64\bin
4)安裝
用管理員身份運行CMD:
mysqld --initialize --console
在MySQL的安裝目錄下執行命令,記錄下生成的臨時密碼,例如:
lu?T,<0uKlz+
開始安裝:
mysqld --install
服務名默認為mysql,如果需要修改名,可以執行 mysqld --install [服務名](建議別改了)
若提示The service already exists!
執行命令sc delete mysql,先刪除該mysql
5)啟動服務
服務安裝成功之后通過命令啟動MySQL的服務
net start mysql
若不成功,到mysql安裝目錄下
mysqld --remove
mysqld --install
net start mysql
注意事項:
1)如果前面安裝時指定了別的服務嗎,這里mysql也要替換成對應的值
2)重啟后默認不會啟動mysql,可以手動以管理員權限執行net start mysql啟動,也可以修改服務啟動,我平時不用,所以選擇每次重啟后手動執行命令啟動。
6)修改密碼
mysql -u root -p 使用臨時密碼登陸
接着這里修改密碼為123456
ALTER user 'root'@'localhost' IDENTIFIED BY '123456';
7)查看版本,數據庫路徑
SELECT @@version,@@datadir
3 數據類型
3.1 數值類型
DECIMAL說明:
1)M 表示數據的最大總長度(不包括小數點,范圍為1~65);D 表示:固定小數位(范圍0~30,但不得超過M);
例:decimal(5,2)
可以存儲123.45 ,存入數據的時候,按四舍五入計算。
2)在計算總長度時要優先考慮小數位,也就是D的約束
例:DECIMAL(5,3)
1.2345 --- 小數點后最多3位,自動四舍五入數據截斷后保存,1.235
1.2 --- 小數未滿部分補0。按照1.200保存。
123.45 --- 因為小數部分未滿3位,要補0.所以保存應該123.450。所以整個位數超出了5,有問題。
3)D不能超過M值,若D等於M,如DECIMAL(5,5)
最大存儲值為0.99999
4)適用場景
適合保存貨幣值,比如話費就可以用decimal來裝的
int(xx)說明:
int(11)不是限制int的長度為11位,而是字符的顯示寬度,例如插入數據1,顯示為00000000001。
在字段類型為int時,無論你顯示寬度設置為多少,int類型能存儲的最大值和最小值永遠都是固定的。
3.2 日期和時間類型
表示時間值的日期和時間類型為DATETIME、DATE、TIMESTAMP、TIME和YEAR。
每個時間類型有一個有效值范圍和一個"零"值,當指定不合法的MySQL不能表示的值時使用"零"值。
TIMESTAMP類型有專有的自動更新特性。
3.3 字符串類型
字符串類型指CHAR、VARCHAR、BINARY、VARBINARY、BLOB、TEXT、ENUM和SET。該節描述了這些類型如何工作以及如何在查詢中使用這些類型。
3.3.1 CHAR和VARCHAR比較
都需要指定長度,他們的區別在於:
1)存儲方式不同:
- char 對英文(ASCII)字符占用1個字節,對一個漢字占用2個字節,varchar 對每個英文(ASCII)字符都占用2個字節,對一個漢字也只占用兩個字節。但對於utf8,一個字符都會占用3個字節。
- char(n),如果實際使用字符不足n,會在后面用空格補全存入數據庫中。varchar(n)則不會。
- 因為varchar要記錄數據長度(系統根據數據長度自動分配空間),所以每個varchar數據產生后,系統都會在數據后面增加1-2個字節的額外開銷:是用來保存數據所占用的空間長度,如果數據本身小於127個字符:額外開銷一個字節;如果大於127個,就開銷兩個字節。例如對於utf8:
2)char效率高於varchar
因此當在長度固定的場景,例如:身份證號,手機號,電話等用char效率高,空間也不浪費
3.3.2 關於TEXT類的數據
1)text不設置長度, 當不知道屬性的最大長度時,適合用text。
2)按照查詢速度: char > varchar > text
3)需要額外的字節來存儲長度:
Tinytext:系統使用一個字節來保存,實際能夠存儲的數據為:2 ^ 8 + 1
Text:使用兩個字節保存,實際存儲為:2 ^ 16 + 2
Mediumtext:使用三個字節保存,實際存儲為:2 ^ 24 + 3
Longtext:使用四個字節保存,實際存儲為:2 ^ 32 + 4
3.3.3 null與空字符串的不同
在MySQL里,null與空字符串 ' '是完全不同的:NULL是指沒有值,而' '則表示值是存在的,只不過是個空值。判斷NULL用is null 或者 is not null。
判斷空字符串‘’,要用 ='' 或者 <>''。sql語句里可以用if(col,col,0)處理,即:當col為true時(非null,及非'')顯示,否則打印0
3.4 二進制類型
BINARY 和 VARBINARY 類似於 CHAR 和 VARCHAR,不同的是它們包含二進制字符串而不要非二進制字符串。也就是說,它們沒有字符集,並且排序和比較基於列值字節的數值。
BLOB是可變數據類型,但是一般開發中,除非文件時機密型的,否正不存數據庫。一般做法是把文件存儲的路徑存到數據庫中,當要取文件時,去數據庫中指定的路徑中去找。
4 數據庫的基本操作
注意sql語句不區分大小寫,而且所有命令都需要以 ; 結尾
4.1 顯示所有數據庫
show databases;
4.2 創建數據庫
create database 數據庫命;
4.3 選擇數據庫
use 數據庫命;
4.4 查看當前數據庫
方法一:
方法二:
show tables; #首行顯示數據庫名
方法三:
status;
4.5 刪除數據庫
drop database 數據庫名;
5 數據庫表基本操作
注,本章及之后的章節里,[ ]表示為可選參數。
5.1 創建表
表是數據庫存儲數據的基本單位。一個表包含若干字段或記錄;
創建表語法:
CREATE TABLE [if not exists] 表名(
屬性名 數據類型 [完整性約束條件],
. .
屬性名 數據類型 [完整性約束條件]
)[ENGINE=引擎名 AUTO_INCREMENT=自動累加起始值 CHARSET=編碼格式;];
若表名已存在則會報錯。若不想報錯,可以使用 CREATE TABLE IF NOT EXISTS 表名 這種方式。這樣會返回成功,但是有一個warning。若表名有特殊字符,例如帶有空格,可以將使用 `表名 1` 這種方式。
根據已有表創建新表,包括數據和結構:
CREATE TABLE 新表名 as select * from 已有表名;
實例:
CREATE TABLE t_bookType( id int primary key auto_increment, bookTypeName varchar(20), bookTypeDesc varchar(200) ); CREATE TABLE t_book( id int primary key auto_increment, bookName varchar(20), author varchar(10), price decimal(6,2), bookTypeId int, constraint `fk` foreign key (`bookTypeId`) references `t_bookType`(`id`) ); CREATE TABLE t_bookType5( id1 INT AUTO_INCREMENT, id2 INT, val1 INT, val2 INT, PRIMARY KEY (id1,id2), UNIQUE (val1,val2) );
decimal /ˈdesɪml/ n. 小數
constraint /kənˈstreɪnt/ n. 限定;約束
5.1.1完整性約束條件
5.1.2 數據表的復合主鍵
所謂的復合主鍵 就是指表的主鍵含有一個以上的字段組成
比如
上面的name和id字段組合起來就是你test表的復合主鍵
它的出現是因為你的name字段可能會出現重名,所以要加上ID字段這樣就可以保證你記錄的唯一性
一般情況下,主鍵的字段長度和字段數目要越少越好
5.1.3 主鍵(PRIMARY KEY)與UNIQUE 對比
1)UNIQUE 約束唯一標識數據庫表中的每條記錄。它 和 PRIMARY KEY 約束均為列或列集合提供了唯一性的保證。
2)PRIMARY KEY 擁有自動定義的 UNIQUE 約束。
3)每張表可以有多個 UNIQUE,但是每個表只能有一個PRIMARY KEY。
4)UNIQUE 可為空,而PRIMARY KEY不能
5.1.4 主鍵與外鍵
1)主鍵是唯一標識一條記錄,不能有重復的,不允許為空
2)外鍵可以有重復的, 可以是空值,用來和其他表建立聯系用的。
用到外鍵一定是至少涉及到兩張表。例如有兩張表,部門表(主表,主鍵ID)、員工表(從表,外鍵Dept_id),因為員工表中的員工需要知道自己屬於哪個部門,就可以通過外鍵Dept_id找到對應的部門,然后才能找到部門表里的各種字段信息,從而讓二者相關聯。外鍵一定是在“從表”中創建,並由“從表”負責維護二者之間的關系。
5.1.5 外鍵的使用條件
1)兩個表必須是InnoDB表,MyISAM表暫時不支持外鍵
2) 外鍵列必須建立了索引,MySQL 4.1.2以后的版本在建立外鍵時會自動創建索引,但如果在較早的版本則需要顯式建立;
3)外鍵關系的兩個表的列必須是數據類相似,也就是可以相互轉換類型的列,比如int和tinyint可以,而int和char則不可以
為什么說外鍵能保持數據的一致性、完整性?
在不設置外鍵的情況下(兩表獨立建立dept_id),員工表的dept_id字段和部門表的dept_id字段是沒有關聯的。只是你自己認為他們有關系而已,數據庫並不認為它倆有關系。也就是說,你在員工表的dept_id字段插了一個值(比如1234),但是這個值在部門表中並沒有,這個時候,數據庫還是允許你插入的,它並不會對插入的數據做關系檢查。然而在設置外鍵的情況下,你插入員工表的dept_id字段的值必須要求在部門表的dept_id字段能找到。 同時,如果你要刪除部門表的某個dept_id字段,必須保證員工表中沒有引用該字段值,否則就沒法刪除。這就是所謂的保持數據的一致性和完整性。
外鍵語法
[CONSTRAINT symbol] FOREIGN KEY [id] (index_col_name, ...)
REFERENCES tbl_name (index_col_name, ...)
[ON DELETE {RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT}]
[ON UPDATE {RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT}]
該語法可以在 CREATE TABLE 和 ALTER TABLE 時使用,如果不指定CONSTRAINT symbol,MYSQL會自動生成一個名字。
ON DELETE、ON UPDATE表示事件觸發限制,可設參數:
RESTRICT(限制外表中的外鍵改動)
CASCADE(跟隨外鍵改動)
SET NULL(設空值)
SET DEFAULT(設默認值)
NO ACTION(無動作,默認的)
實例:
create table t_department( id int primary key auto_increment, name varchar(20), author varchar(10), price decimal(6,2), booktypeid int, constraint `fk` foreign key (`booktypeid`) references `t_booktype` (`id`) );
注:fk為約束名,booktypeid為本表的外鍵名,t_booktype為主表名,主表后面跟的id為主表的主鍵名。
5.1.6 引擎與編碼
ENGINE 設置存儲引擎,DEFAULT CHARSET 設置編碼。例如ENGINE=InnoDB DEFAULT CHARSET=utf8
CREATE TABLE 時有多種數據庫存儲引擎:
TYPE = {BDB | HEAP | ISAM | InnoDB | MERGE | MRG_MYISAM | MYISAM }
兩種常用引擎MyISAM、InnoDB 大至區別如下:
1)高級處理:
MyISAM類型不支持事務處理等高級處理,而InnoDB類型支持。
2)執行速度:
MyISAM類型的表強調的是性能,其執行數度比InnoDB類型更快。
3)移值性:
MyISAM類型的二進制數據文件可以在不同操作系統中遷移。也就是可以直接從Windows系統拷貝到Linux系統中使用。
5.2 查看表結構
1)查看基本表結構:DESCRIBE(縮寫DESC) 表名;
2)查看表詳細結構: SHOW CREATE TABLE 表名; 這種方法可以看到建表的sql
實例:
desc t_bookType;
show create table t_bookType;
這里我們可以加上格式化輸出信息 \G,將查到的結構旋轉90度變成縱向,因為有的時候因為格式問題,或是太長導致顯示錯行
例:
上面的查找的表的創建語句看着很別扭,那么可以使用\G
5.3 修改表
1)修改表名
ALTER TABLE 舊表名 RENMAE 新表名 ;
2)修改字段
ALTER TABLE 表名 CHANGE 舊屬性名 新屬性名 新數據類型
3)增加字段
ALTER TABLE 表名 ADD 屬性名1 數據類型 [完整性約束條件] [FIRST | AFTER 屬性名 2]
4)刪除字段
ALTER TABLE 表名 DROP 屬性名
實例:
alter table t_book rename t_book2; alter table t_book change bookName bookName2 varchar(20); alter table t_book add testField int first ; alter table t_book drop testField;
注:
alter [ˈɔːltər] v.(使) 改變,更改
5.4 刪除表
DROP TABLE 表名;
實例:
6 查詢數據
准備:創建用於測試的數據表
create table `t_student` ( `id` double , `stuName` varchar (60), `age` double , `sex` varchar (30), `gradeName` varchar (60) ); insert into `t_student` (`id`, `stuName`, `age`, `sex`, `gradeName`) values('1','張三','23','男','一年級'); insert into `t_student` (`id`, `stuName`, `age`, `sex`, `gradeName`) values('2','張三豐','25','男','二年級'); insert into `t_student` (`id`, `stuName`, `age`, `sex`, `gradeName`) values('3','李四','23','男','一年級'); insert into `t_student` (`id`, `stuName`, `age`, `sex`, `gradeName`) values('4','王五','22','男','三年級'); insert into `t_student` (`id`, `stuName`, `age`, `sex`, `gradeName`) values('5','珍妮','21','女','一年級'); insert into `t_student` (`id`, `stuName`, `age`, `sex`, `gradeName`) values('6','李娜','26','女','二年級'); insert into `t_student` (`id`, `stuName`, `age`, `sex`, `gradeName`) values('7','王峰','20','男','三年級'); insert into `t_student` (`id`, `stuName`, `age`, `sex`, `gradeName`) values('8','夢娜','21','女','二年級'); insert into `t_student` (`id`, `stuName`, `age`, `sex`, `gradeName`) values('9','小黑','22','男','一年級'); insert into `t_student` (`id`, `stuName`, `age`, `sex`, `gradeName`) values('10','追風','25','男','二年級'); insert into `t_student` (`id`, `stuName`, `age`, `sex`, `gradeName`) values('11','小小張三','21',NULL,'二年級'); insert into `t_student` (`id`, `stuName`, `age`, `sex`, `gradeName`) values('12','小張三','23','男','二年級'); insert into `t_student` (`id`, `stuName`, `age`, `sex`, `gradeName`) values('13','張三鋒小','24',NULL,'二年級');
6.1 單表查詢
6.1.1 查詢所有字段
6.1.2 查詢指定字段
SELECT 字段1,字段2,字段3...FROM 表名;
6.1.3 Where 條件查詢
SELECT 字段1,字段2,字段3...FROM 表名 WHERE 條件表達式;
SELECT * FROM t_student WHERE id=1; SELECT * FROM t_student WHERE not id=1; SELECT * FROM t_student WHERE age<20; SELECT * FROM t_student WHERE age>22; SELECT * FROM t_student WHERE not age>22;
6.1.4 為表格和字段取別名
表名 [AS] 表的別名
SELECT * FROM t_book WHERE id=1; SELECT * FROM t_book t WHERE t.id=1; SELECT t.bookName FROM t_book t WHERE t.id=1;
為字段取別名:字段 [AS] 字段的別名
SELECT t.bookName bName FROM t_book t WHERE t.id=1; SELECT t.bookName AS bName FROM t_book t WHERE t.id=1;
6.1.5 帶 IN 關鍵字查詢
SELECT 字段1,字段2,字段3...FROM 表名 WHERE 字段 [NOT] IN (元素1,元素2);
查找年齡在21或23的學生
查找年齡不在21或23的學生
6.1.6 帶 BETWEEN AND 的范圍查詢
SELECT 字段 1,字段 2,字段 3...FROM 表名 WHERE 字段 [NOT] BETWEEN 取值 1 AND 取值 2;
SELECT * FROM t_student WHERE age BETWEEN 21 AND 24; SELECT * FROM t_student WHERE age NOT BETWEEN 21 AND 24;
6.1.7 帶 LIKE 的模糊查詢
SELECT 字段1,字段2,字段3...FROM 表名 WHERE 字段 [NOT] LIKE ‘字符串’;
注:
1)“%”代表任意字符且任意長度,“_” 代表任意單個字符
2)這里輸入的是字符串,但是不要求被查的字段也是字符串,也可以查int類型的
SELECT * FROM t_student WHERE stuName LIKE '張三'; SELECT * FROM t_student WHERE stuName LIKE '張三%'; SELECT * FROM t_student WHERE stuName LIKE '張三_'; SELECT * FROM t_student WHERE stuName LIKE '張三__'; SELECT * FROM t_student WHERE stuName LIKE '_張三'; SELECT * FROM t_student WHERE stuName LIKE '__張三'; SELECT * FROM t_student WHERE stuName LIKE '%張三%'; SELECT * FROM t_student WHERE id LIKE '1%';
6.1.8 空值查詢
SELECT 字段1,字段2,字段3...FROM 表名 WHERE 字段 IS [NOT] NULL;
6.1.9 帶 AND 的多條件查詢
SELECT 字段1,字段2...FROM 表名 WHERE 條件表達式1 AND 條件表達式2 [...AND 條件表達式n]
6.1.10 帶 OR 的多條件查詢
SELECT 字段 1,字段 2...FROM 表名 WHERE 條件表達式 1 OR 條件表達式 2 [...OR 條件表達式 n]
6.1.11 DISTINCT 去重復查詢
[dɪ'stɪŋkt] 獨特的
SELECT DISTINCT 字段名 FROM 表名;
6.1.12 對查詢結果排序
SELECT 字段 1,字段 2...FROM 表名 ORDER BY (屬性名|列號如1,2,3,4) [ASC|DESC]
注:ASC升序(默認),DESC降序
SELECT * FROM t_student ORDER BY age ASC; SELECT * FROM t_student ORDER BY age DESC; SELECT * FROM t_student GROUP BY gradeName;
6.1.13 GROUP BY 分組查詢
GROUP BY 屬性名 [HAVING 條件表達式][WITH ROLLUP]
在有group by的查詢語句中,select指定的字段要么就包含在group by語句的后面,作為分組的依據,要么就包含在聚合函數中。
1)與 GROUP_CONCAT()函數一起使用
GROUP_CONCAT將group by產生的同一個分組中的值連接起來,返回一個字符串結果。
例:將所有學生按年級分組
SELECT gradeName,GROUP_CONCAT(stuName) FROM t_student GROUP BY gradeName;
2)與COUNT函數一起使用
例:查詢各年級的學生人數
3)與 HAVING 一起使用(限制輸出的結果)
HAVING 子句可以讓我們篩選分組后的各組數據。它的用法與where類似,但是在GROUP BY后只能用HAVING不能用WHERE。
例:
4)與 WITH ROLLUP 一起使用(最后加入一個總和行);
6.1.14 LIMIT 分頁查詢
SELECT 字段 1,字段 2...FROM 表名 LIMIT [初始位置,]記錄數;
注,這里初始位置從0開始。
SELECT * FROM t_student LIMIT 0,5; SELECT * FROM t_student LIMIT 5,5; SELECT * FROM t_student LIMIT 10,5;
SELECT 字段 1,字段 2...FROM 表名 LIMIT 記錄數 OFFSET 偏移;
查詢第二條記錄:
6.2 使用聚合函數查詢
本小節使用到的表數據
create table `t_grade` ( `id` int , `stuName` varchar (60), `course` varchar (60), `score` int ); insert into `t_grade` (`id`, `stuName`, `course`, `score`) values('1','張三','語文','91'); insert into `t_grade` (`id`, `stuName`, `course`, `score`) values('2','張三','數學','90'); insert into `t_grade` (`id`, `stuName`, `course`, `score`) values('3','張三','英語','87'); insert into `t_grade` (`id`, `stuName`, `course`, `score`) values('4','李四','語文','79'); insert into `t_grade` (`id`, `stuName`, `course`, `score`) values('5','李四','數學','95'); insert into `t_grade` (`id`, `stuName`, `course`, `score`) values('6','李四','英語','80'); insert into `t_grade` (`id`, `stuName`, `course`, `score`) values('7','王五','語文','77'); insert into `t_grade` (`id`, `stuName`, `course`, `score`) values('8','王五','數學','81'); insert into `t_grade` (`id`, `stuName`, `course`, `score`) values('9','王五','英語','89');
6.2.1 COUNT()函數
1)COUNT()函數用來統計記錄的條數;
統計表的記錄個數
統計表的記錄個數,並以別名total顯示
2)與 GOUPE BY 關鍵字一起使用
統計根據stuName分組后的統計值
6.2.2 SUN()函數
1)SUM()函數是求和函數
統計張三的成績
2)與 GOUPE BY 關鍵字一起使用
統計各學生的總成績
6.2.3 AVG()函數
1)AVG()函數是求平均值的函數;
統計張三的平均成績
2)與 GOUPE BY 關鍵字一起使用;
統計各學生的平均成績
6.2.4 MAX()函數
1)MAX()函數是求最大值的函數;
統計張三的最高分
2)與 GOUPE BY 關鍵字一起使用;
統計各學生的最高分
6.2.5 MIN()函數
1)MIN()函數是求最小值的函數;
統計張三各科成績中的最低分
注:這里如果加上科目course會報錯,因為MySQL5.7.5后,默認開啟了ONLY_FULL_GROUP_BY,對於不確定輸出的會報錯。
查詢:SELECT stuName,course,MIN(score) FROM t_grade WHERE stuName="張三";
錯誤代碼: 1140
In aggregated query without GROUP BY, expression #2 of SELECT list contains nonaggregated column 'test.t_grade.course'; this is incompatible with sql_mode=only_full_group_by
我的理解是,通過張三stuName有多條記錄但是內容一樣,MIN(score)聚合后只出一條記錄,所以這兩個字段能輸出,但是沒有針對course進行處理,此時不知該輸出何止,導致錯誤。
規避方案:
不確定返回字段可以使用ANY_VALUE(column_name),但這個值不一定是你想要的。
思考,那如何才能顯示最低分及其科目呢?
2)與 GOUPE BY 關鍵字一起使用;
統計各學生的最低分
總結,使用了聚合函數,字段必須是唯一的才能一起輸出,否則會報錯。
6.3 連接查詢
連接查詢是將兩個或兩個以上的表按照某個條件連接起來,從中選取需要的數據。
本小節使用到的表數據
CREATE DATABASE `db_book`; USE `db_book`; /*Table structure for table `t_book` */ DROP TABLE IF EXISTS `t_book`; CREATE TABLE `t_book` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `bookName` VARCHAR(20) DEFAULT NULL, `price` DECIMAL(6,2) DEFAULT NULL, `author` VARCHAR(20) DEFAULT NULL, `bookTypeId` INT(11) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=INNODB CHARSET=utf8; /*Data for the table `t_book` */ INSERT INTO `t_book`(`id`,`bookName`,`price`,`author`,`bookTypeId`) VALUES (1,'Java編程思想','100.00','埃史爾',1),(2,'Java從入門到精通','80.00','李鍾尉',1),(3,'三劍客','70.00','大仲馬',2),(4,'生理學(第二版)','24.00','劉先國',4); /*Table structure for table `t_booktype` */ DROP TABLE IF EXISTS `t_booktype`; CREATE TABLE `t_booktype` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `bookTypeName` VARCHAR(20) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=INNODB CHARSET=utf8; /*Data for the table `t_booktype` */ INSERT INTO `t_booktype`(`id`,`bookTypeName`) VALUES (1,'計算機類'),(2,'文學類'),(3,'教育類');
表t_book
表t_booktype
這里如果select兩張表,查詢的是所有可能的組合,這里有12條記錄
6.3.1 內連接與外連接的區別:
1)內連接查詢:
查出來的數據可能不能覆蓋所有數據(只查詢到匹配的),比如查詢表一
中bookId等於表二中的id的數據,但如果表一中某條數據的bookId在表二
中查不到,那么對應的這條數據就不顯示。
2)外連接查詢:
舉例同上,在查不到的情況下,內連接的處理有可能導致兩張表可能都不全,
但是外連接能夠保證始終會顯示其中一張表的所有信息,比如使用左連接查
詢,表一的bookId沒有在表二中查到,對應的表一數據仍顯示,對應的表二
數據使用NULL代替。
6.3.2 內連接查詢
需要查找多張表同時存在的數據時,使用內連接。
1)查詢兩張表bookTypeId相同的記錄
SELECT * FROM t_book,t_bookType WHERE t_book.bookTypeId=t_bookType.id;
2)查詢時過濾部分字段
下面的語句中如果添加id,就會報錯。因為兩張表都有ID不知該輸出哪列,但如果t_bookType.id就可以。
SELECT bookName,author,bookTypeName FROM t_book,t_bookType WHERE t_book.bookTypeId=t_bookType.id;
t_book 取別名tb,select可以使用tb.bookName,若不用別名則使用t_book.bookName。取別名的時候as可以省略
SELECT tb.bookName,tb.author,tby.bookTypeName FROM t_book as tb,t_bookType as tby WHERE tb.bookTypeId=tby.id;
6.3.2 外連接查詢
外連接可以查出某一張表的所有信息,其他表多沒有的字段可以置NULL
SELECT 屬性名列表 FROM 表名1 LEFT|RIGHT JOIN 表名2 ON 表名1.屬性名1=表名2.屬性名2;
6.3.2.1 左連接查詢
LEFT JOIN 關鍵字從左表(table1)返回所有的行,即使右表(table2)中沒有匹配。如果右表中沒有匹配,則結果為 NULL。
注釋:在某些數據庫中,LEFT JOIN 稱為 LEFT OUTER JOIN。
SELECT * FROM t_book LEFT JOIN t_bookType ON t_book.bookTypeId=t_bookType.id;
SELECT tb.bookName,tb.author,tby.bookTypeName FROM t_book tb LEFT JOIN t_bookType tby ON tb.bookTypeId=tby.id;
6.3.2.2 右連接查詢
可以查詢出“表名 2”的所有記錄,而“表名 1”中,只能查詢出匹配的記錄;
SELECT * FROM t_book RIGHT JOIN t_bookType ON t_book.bookTypeId=t_bookType.id;
SELECT tb.bookName,tb.author,tby.bookTypeName FROM t_book tb RIGHT JOIN t_bookType tby ON tb.bookTypeId=tby.id;
6.3.4 多條件連接查詢
內連接的多條件查詢,或外連接的多條件查詢。通過and來指定多個條件。
SELECT tb.bookName,tb.author,tby.bookTypeName FROM t_book tb,t_bookType tby WHERE tb.bookTypeId=tby.id AND tb.price>70;
6.4 子查詢
本小結用到了上節的t_book和t_bookType,新增一張表t_pricelevel
CREATE TABLE `t_pricelevel` ( `id` INT PRIMARY KEY AUTO_INCREMENT, `priceLevel` INT , `price` FLOAT , `description` VARCHAR (300) ); INSERT INTO `t_pricelevel` (`id`, `priceLevel`, `price`, `description`) VALUES('1','1','80.00','價格貴的書'); INSERT INTO `t_pricelevel` (`id`, `priceLevel`, `price`, `description`) VALUES('2','2','60.00','價格適中的書'); INSERT INTO `t_pricelevel` (`id`, `priceLevel`, `price`, `description`) VALUES('3','3','40.00','價格便宜的書');
表t_pricelevel
表t_book
表t_booktype
6.4.1 帶 In 關鍵字的子查詢
一個查詢語句的條件可能落在另一個 SELECT 語句的查詢結果中。
6.4.2 帶比較運算符的子查詢
子查詢可以使用比較運算符,這里的子查詢必須為可比較的值。
6.4.3 帶 Exists 關鍵字的子查詢
假如子查詢查詢到記錄,則進行外層查詢,否則,不執行外層查詢:
同理,也可以使用NOT EXISTS:
6.4.4 帶 Any 關鍵字的子查詢
ANY 關鍵字表示滿足子查詢中任一條件
6.4.5 帶 All 關鍵字的子查詢
ALL 關鍵字表示滿足所有條件
6.4.6 將select結果保存為臨時的表,作為另一個select的數據源
例1:
這里必須給臨時表去一個別名,否則報錯。
例2:
這句話的意思是將SELECT id FROM t_book LIMIT 100,100的結果保存為臨時表並顯示出來。
注,只能是返回最多一行一個字段的值,在有的數據庫里如果里頭的這個select數據limit超范圍了,會報錯,通過這樣轉一下能保證不出錯,若超范圍了返回空。
因為select null返回null。
6.5 合並查詢結果
用於將多張表的查詢結果合並
表t_book
表t_booktype
6.5.1 UNION
使用 UNION 關鍵字是,數據庫系統會將所有的查詢結果合並到一起,然后去除掉相同的記錄
6.5.2 UNION ALL
使用 UNION ALL,不會去除掉相同的記錄
7 數據的更改
7.1 插入數據
1) 給表的所有字段插入數據
格式:INSERT INTO 表名 VALUES(值1,值2,值3,...,值n);
2)給表的指定字段插入數據
格式:INSERT INTO 表名(屬性1,屬性2,...,屬性n) VALUES(值1,值2,值3,...,值n);
3)同時插入多條記錄
INSERT INTO 表名 [(屬性列表)] VALUES(取值列表1),(取值列表2) ..., (取值列表 n);
INSERT INTO t_book(id,bookName,price,author,bookTypeId) VALUES (NULL,'我愛我家2',20,'張三',1),(NULL,'我愛我家3',20,'張三',1);
7.2 更新數據
UPDATE 表名 SET 屬性名1=取值1,屬性名2=取值2,...,屬性名n=取值n WHERE 條件表達式;
UPDATE t_book SET bookName='Java編程思想',price=120 WHERE id=1; UPDATE t_book SET bookName='我' WHERE bookName LIKE '%我愛我家%';
7.3 刪除數據
DELETE FROM 表名 [WHERE 條件表達式]
8 索引
8.1 索引的引入
索引定義:索引是由數據庫表中一列或者多列組合而成,其作用是提高對表中數據的查詢速度;
類似於圖書的目錄,方便快速定位,尋找指定的內容;
8.2 索引的優缺點
優點:提高查詢數據的速度。
創建索引時,你需要確保該索引是應用在 SQL 查詢語句的條件(一般作為 WHERE 子句的條件)。
缺點:過多的使用索引將會造成濫用,雖然索引大大提高了查詢速度,同時卻會降低更新表的速度,如對表進行INSERT、UPDATE和DELETE。
索引也是一張表,該表保存了主鍵與索引字段,並指向實體表的記錄。
因為更新表時,MySQL不僅要保存數據,還要保存一下索引文件。
同時建立索引也會占用磁盤空間。
8.3 性能對比實例
110000條記錄
建立索引前測試查詢時間,70毫秒。建立索引后,0毫秒。
在sqlyog中查看索引:
8.4 索引分類和創建
8.4.1 創建語法
1、創建表的時候創建索引
CREATE TABLE 表名 (屬性名 數據類型 [完整性約束條件], 屬性名 數據類型 [完整性約束條件], .... 屬性名 數據類型 [UNIQUE | FULLTEXT | SPATIAL ] INDEX|KEY [別名] (屬性名1 [(長度)] [ASC | DESC]) );
說明:
- UNIQUE | FULLTEXT | SPATIAL 為可選參數,分別表示唯一索引、全文索引、空間索引
- INDEX和KEY是同義詞,可以替換使用
- 只有字符串類型的字段才能指定索引長度,其中如果是BLOB和TEXT類型,必須指定 length,如果是CHAR,VARCHAR類型,長度可以小於字段實際長度,也可以不指定長度。
- asc或desc指定升序或降序的索引值存儲
2、在已經存在的表上創建索引
CREATE [ UNIQUE | FULLTEXT | SPATIAL ] INDEX 索引名 ON 表名 (屬性名 [(長度)] [ ASC | DESC]);
3、用 ALTER TABLE 語句來創建索引
ALTER TABLE 表名 ADD [ UNIQUE | FULLTEXT | SPATIAL ] INDEX 索引名 (屬性名 [(長度)] [ ASC | DESC]);
ALTER TABLE和CREATE INDEX的區別
- CREATE INDEX必須提供索引名,對於ALTER TABLE,如果你不提供將會自動創建;
- CREATE INDEX一個語句一次只能建立一個索引,ALTER TABLE可以在一個語句建立多個,如:
ALTER TABLE HeadOfState ADD PRIMARY KEY (ID), ADD INDEX (LastName,FirstName);
- 只有ALTER TABLE 才能創建主鍵,
英文原句如下:
With CREATE INDEX, we must provide a name for the index. With ALTER TABLE, MySQL creates an index name automatically if you don’t provide one.Unlike ALTER TABLE, the CREATE INDEX statement can create only a single index per statement. In addition, only ALTER TABLE supports the use of PRIMARY KEY.
8.4.2 索引的分類和舉例
8.4.2.1 普通索引
這類索引可以創建在任何數據類型中,它沒有任何限制
1)創建表的時候同時創建索引:
CREATE TABLE t_test1( id INT, userName TEXT(20), pwd VARCHAR(20), des VARCHAR(20), INDEX (userName(20)) );
2)CREATE方式創建索引
3)ALTER方式創建索引
8.4.2.2 唯一性索引
使用 UNIQUE 參數可以設置,與普通索引類似不同之處在於,索引列的值必須唯一,但允許有空值。如果是組合索引,則列值的組合必須唯一。
1)創建表的時候同時創建索引
CREATE TABLE t_test2( id INT, userName TEXT(20), pwd VARCHAR(20), des VARCHAR(20), UNIQUE INDEX (userName(20)) );
2)CREATE方式創建索引
3)ALTER方式創建索引
8.4.2.3 主鍵索引
主鍵索引是一種特殊的唯一索引,一個表只能有一個主鍵,不允許有空值。一般是在建表的時候同時創建主鍵索引:
CREATE TABLE t_test3( id INT, userName TEXT(20), pwd VARCHAR(20), des VARCHAR(20), PRIMARY KEY (`id`) );
8.4.2.4 全文索引
主要用來查找文本中的關鍵字,而不是直接與索引中的值相比較。fulltext索引跟其它索引大不相同,它更像是一個搜索引擎,而不是簡單的where語句的參數匹配。fulltext索引配合match against操作使用,而不是一般的where語句加like。不過目前只有char、varchar,text 列上可以創建全文索引。值得一提的是,在數據量較大時候,現將數據放入一個沒有全局索引的表中,然后再用CREATE index創建fulltext索引,要比先為一張表建立fulltext然后再將數據寫入的速度快很多。只有 MyISAM 引擎支持該索引。
1)創建表的適合添加全文索引
CREATE TABLE t_test4( id INT, userName TEXT(20), pwd VARCHAR(20), des VARCHAR(20), FULLTEXT (userName) );
2)CREATE方式創建索引
3)ALTER方式創建索引
8.4.2.5 空間索引
5.7之后的版本支持了空間索引,而且支持OpenGIS幾何數據模型。
使用 SPATIAL 參數可以設置空間索引。空間索引只能建立在空間數據類型上,這樣可以提高系統獲取空間數據的效率。
MyISAM 引擎支持該索引。
其他說明:
多列索引(組合索引)
指多個字段上創建的索引,當我們的where查詢存在多個條件查詢的時候,我們需要對查詢的列創建組合索引。
最左匹配原則
假設我們創建(col1,col2,col3)這樣的一個組合索引,那么相當於對col1列進行排序,也就是我們創建組合索引,以最左邊的為准,只要查詢條件中帶有最左邊的列,不管該列在查詢條件中的位置,都會使用索引進行查詢。
8.4.3 索引的刪除
1)drop命令刪除
DROP INDEX 索引名 ON 表名;
2)ALTER命令刪除索引
刪除主鍵索引:
不需要指定主鍵名
ALTER TABLE 表名 DROP PRIMARY KEY;
其他索引:
ALTER TABLE 表名 DROP INDEX 索引名;
8.4.3 顯示索引信息
SHOW INDEX FROM 表名;
例:
9 視圖view
9.1 視圖的介紹
什么是試圖?
- 視圖是一種虛擬的表,是從數據庫中一個或者多個表中導出來的表。
- 數據庫中只存放了視圖的定義,而並沒有存放視圖中的數據,這些數據存放在原來的表中。
- 使用視圖查詢數據時,數據庫系統會從原來的表中取出對應的數據。
視圖的作用?
作用一:使操作簡便化
比如原本表里有20個字段,視圖可以只取我們需要的幾個字段,方便操作,例如我們要頻繁獲取user表中的name和group表中的gname。我們可以創建一個視圖,包含這兩個字段,使用一條select *語句就能獲取想要的內容。
作用二:對數據庫重構,卻不影響程序的運行。
例1,A表創建了視圖V1,之后A表添加了新的字段,但是我們對V1的操作不受影響,只要保證V1使用的字段還在就可以。
例2,假如因為某種需求,需要將user拆分成表usera和表userb,該兩張表的結構如下:
測試表:usera有id,name,age字段
測試表:userb有id,name,sex字段
這時如果使用sql語句:select * from user;那就會提示該表不存在,這時我們就可以通過創建視圖來解決。
作用三:提高了安全性能。
例1,可以對不同的用戶,設定不同的視圖。如某用戶只能獲取user表的name和age數據,不能獲取sex數據。則可以創建視圖。使用sql語句:select * 語句最多就只能獲取name和age的數據,其他的數據就獲取不了了。
例2,我們對視圖進行操作,只會影響我們關系的幾個字段,其他的字段比如某些重要字段不會因為誤操作而受到影響。
9.2 視圖的創建
CREATE [ ALGORITHM ={ UNDEFIEND | MERGE | TEMPTABLE }] VIEW 視圖名 [ ( 屬性清單) ] AS SELECT 語句 [ WITH [ CASCADED | LOCAL ] CHECK OPTION ];
1)語法說明:
- ALGORITHM 是可選參數,表示視圖選擇的算法。
ALGORITHM 包括 3 個選項 UNDEFINED、MERGE 和 TEMPTABLE。其中,UNDEFINED 選項表示 MySQL 將自動選擇所要使用的算法;MERGE 選項表示將使用視圖的語句與視圖定義合並起來,使得視圖定義的某一部分取代語句的對應部分;TEMPTABLE 選項表示將視圖的結果存入臨時表,然后使用臨時表執行語句。
- “視圖名”參數表示要創建的視圖的名稱。
- “屬性清單”是可選參數,其指定了視圖中各種屬性的名詞,默認情況下與 SELECT 語句中查詢的屬性相同。
- SELECT 語句參數是一個完整的查詢語句,標識從某個表查出某些滿足條件的記錄,將這些記錄導入視圖中。
- WITH CHECK OPTION 是可選參數,表似更新視圖時要保證在該視圖的權限范圍之內。
- CASCADED可選參數,表示更新視圖時要滿足所有相關視圖和表的條件,該參數為默認值。LOCAL 表示更新視圖時,要滿足該視圖本身的定義條件即可。
注:我們可以在已有視圖上再創建視圖
接下來的例子,會使用我們之前創建的t_book和t_bookType作為演示
2)在單表上創建視圖
創建視圖后對字段取別名
3)在多表上創建視圖
CREATE VIEW v4 AS SELECT bookName,bookTypeName FROM t_book,t_booktype WHERE t_book.bookTypeId=t_booktype.id; SELECT * FROM v4;
創建時使用別名
CREATE VIEW v5 AS SELECT tb.bookName,tby.bookTypeName FROM t_book tb,t_booktype tby WHERE tb.bookTypeId=tby.id; SELECT * FROM v5;
9.3 查看視圖
1)DESCRIBE 語句查看
DESCRIBE v5;
2)SHOW TABLE STATUS 語句查看
3)SHOW CREATE VIEW 語句查看詳細信息
注:這里我使用SHOW CREATE TABLE v5;得到的結果一樣。
4)在 views 表中查看視圖詳細信息
information_schema庫-->views表
9.4 修改視圖
使用v1視圖為例
1)CREATE OR REPLACE 創建或替換已有視圖
CREATE OR REPLACE [ ALGORITHM ={ UNDEFINED | MERGE | TEMPTABLE }] VIEW 視圖名 [( 屬性清單 )] AS SELECT 語句 [ WITH [ CASCADED | LOCAL ] CHECK OPTION ];
例:
2) ALTER 語句修改視圖
ALTER [ ALGORITHM ={ UNDEFINED | MERGE | TEMPTABLE }] VIEW 視圖名 [( 屬性清單 )] AS SELECT 語句 [ WITH [ CASCADED | LOCAL ] CHECK OPTION ];
9.5 更新視圖
更新視圖是指通過視圖來插入(INSERT)、更新(UPDATE)和刪除(DELETE)表中的數據。因為視圖是一個虛擬的表,其中沒有數據。通過視圖更新時,都是轉換基本表來更新。更新視圖時,只能更新權限范圍內的數據。超出了范圍,就不能更新。
以下操作同對表的操作,語法同對表操作一樣
1) 插入(INSERT)
2) 更新(UPDATE)
3) 刪除(DELETE)
9.6 刪除視圖
刪除視圖是指刪除數據庫中已存在的視圖。刪除視圖時只會刪除視圖的定義,不會刪除數據。
DROP VIEW [ IF EXISTS ] 視圖名列表 [ RESTRICT | CASCADE ]
10 觸發器
10.1 觸發器的介紹
觸發器(TRIGGER)是由事件來觸發某個操作。這些事件包括 INSERT 語句、UPDATE 語句和 DELETE 語句。
當數據庫系統執行這些事件時,就會激活觸發器執行相應的操作。
例如:你在一張表插入了一條數據,業務上要求在另一張表也需要插入,這時候就可以使用觸發器
t_book表
t_bookType表
10.2 創建與使用觸發器
1)創建只有一個執行語句的觸發器
CREATE TRIGGER 觸發器名 BEFORE | AFTER 觸發事件 ON 表名 FOR EACH ROW 執行語句
觸發事件: INSERT、UPDATE 、 DELETE
實例:
在t_book插入一條數據后,t_bookType里的bookNum相應記錄累加
CREATE TRIGGER trig_book AFTER INSERT ON t_book FOR EACH ROW UPDATE t_bookType SET bookNum=bookNum+1 WHERE new.bookTypeId=t_bookType.id; INSERT INTO t_book VALUE(NULL, 'java新書', 100, 'aaa', 1); SELECT * FROM t_bookType;
這里涉及到兩個過渡變量:new和old,指代新插入的或即將刪除的那條記錄。
對於INSERT語句,只有NEW是合法的;對於DELETE語句,只有OLD才合法;而UPDATE語句可以在NEW及OLD同時使用。
說明:
for each row代表行級觸發器,任意一行受影響都會觸發的,叫行級觸發器。
在oracle 觸發器中,分“行級觸發器”和“語句級觸發器”,“語句級觸發器”可不寫for each row,無論影響多少行都只執行一次。
mysql不支持語句觸發器,所以必須寫for each row。
2)創建有多個執行語句的觸發器
CREATE TRIGGER 觸發器名 BEFORE | AFTER 觸發事件 ON 表名 FOR EACH ROW
BEGIN
執行語句1;
...
執行語句N;
END
注:mysql語句執行是以封號做判斷,這個多行觸發器里帶有多條語句,因此需要使用DELIMTTER重新定義結束符為 |(也可以是別的)。
例如下面這個例子中,當從t_book中刪除一條語句,會觸發三條語句:
DELIMITER | CREATE TRIGGER trig_book2 AFTER DELETE ON t_book FOR EACH ROW BEGIN UPDATE t_bookType SET bookNum=bookNum-1 WHERE old.bookTypeId=t_booktype.id; INSERT INTO t_log VALUES(NULL,NOW(),'在book表里刪除了一條數據'); DELETE FROM t_test WHERE old.bookTypeId=t_test.id; END | DELIMITER ;
10.3 查看觸發器
10.3.1 SHOW TRIGGERS
10.3.2 在 triggers 表中查看
10.4 刪除觸發器
DROP TRIGGER 觸發器名;
11 常用函數
11.1 日期和時間函數
1)CURDATE() 返回當前日期
2)CURTIME() 返回當前時間
3)MONTH(d) 返回日期 d 中的月份值,范圍是 1~12
11.2 字符串函數
1)CHAR_LENGTH(s) 計算字符串 s 的字符數;
2)UPPER(s) 把所有字母變成大寫字母;
3)LOWER(s) 把所有字母變成小寫字母
11.3 數學函數
1)ABS(x) 求絕對值
2)SQRT(x) 求平方根
3)MOD(x,y) 求余
11.4 加密函數
1)PASSWORD(str) 一般對用戶的密碼加密 不可逆
2)MD5(str) 普通加密 不可逆
3)ENCODE(str,pswd_str) 加密函數,結果是一個二進制數,必須使用 BLOB 類型的字段來保存它;
4)DECODE(crypt_str,pswd_str) 解密函數;
11.5 判斷函數
1)if(條件判斷,值1,值2)
如果條件判斷是true,就等於值1,false就等於值2,有點像三元表達式
例,把salary表中的女改成男,男改成女:
update salary set sex = if( sex = '男','女','男');
2)ifnull(值1, 值2)
ifnull里有兩個數,如果值1不是null則取值1,否則取值2
例:
12 存儲過程和函數
存儲過程(Stored Procedure)是一種在數據庫中存儲復雜程序,以便外部程序調用的一種數據庫對象。
存儲過程是為了完成特定功能的SQL語句集,經編譯創建並保存在數據庫中,用戶可通過指定存儲過程的名字並給定參數(需要時)來調用執行。
存儲過程思想上很簡單,就是數據庫 SQL 語言層面的代碼封裝與重用。
優點
- 存儲過程可封裝,並隱藏復雜的商業邏輯。
- 存儲過程可以回傳值,並可以接受參數。
- 存儲過程無法使用 SELECT 指令來運行,因為它是子程序,與查看表,數據表或用戶定義函數不同。
- 存儲過程可以用在數據檢驗,強制實行商業邏輯等。
缺點
- 存儲過程,往往定制化於特定的數據庫上,因為支持的編程語言不同。當切換到其他廠商的數據庫系統時,需要重寫原有的存儲過程。
- 存儲過程的性能調校與撰寫,受限於各種數據庫系統。
12.1 創建存儲過程,函數
CREATE [DEFINER = user] PROCEDURE sp_name ([proc_parameter[,...]]) [characteristic ...] routine_body CREATE [DEFINER = user] FUNCTION sp_name ([func_parameter[,...]]) RETURNS type [characteristic ...] routine_body proc_parameter: [ IN | OUT | INOUT ] param_name type func_parameter: param_name type type: Any valid MySQL data type characteristic: COMMENT 'string' | LANGUAGE SQL | [NOT] DETERMINISTIC | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA } | SQL SECURITY { DEFINER | INVOKER } routine_body(存儲過程體): [begin_label:] BEGIN [statement_list] …… END [end_label]
例:
創建存儲過程,根據ID刪除t_book表中數據
DELIMITER $$
CREATE PROCEDURE del_matches(IN bid INTEGER)
BEGIN
DELETE FROM t_book WHERE id = bid;
END $$
DELIMITER;
調用存儲過程:
call 存儲過程名[(傳參)];
例:
調用函數:
select call 函數名[(傳參)];
12.2 存儲過程的參數
PROCEDURE 共有三種參數類型:
- IN 輸入參數:表示調用者向過程傳入值(傳入值可以是字面量或變量)
- OUT 輸出參數:表示過程向調用者傳出值(可以返回多個值)(傳出值只能是變量)
- INOUT 輸入輸出參數:既表示調用者向過程傳入值,又表示過程向調用者傳出值(值只能是變量)
FUNCTION參數總是被認為是IN參數。
1)in 輸入參數
輸入參數(局部變量)在存儲過程中被修改,但並不影響全局變量中同名的變量值,例:
mysql> delimiter $$ mysql> create procedure in_param(in p_in int) -> begin -> select p_in; -> set p_in=2; -> select P_in; -> end$$ mysql> delimiter ; mysql> set @p_in=1; mysql> call in_param(@p_in); +------+ | p_in | +------+ | 1 | +------+ +------+ | P_in | +------+ | 2 | +------+ mysql> select @p_in; +---------+ | @p_in | +---------+ | 1 | +---------+
2)out輸出參數
在存儲過程中修改out參數的值,存儲過程外的變量值也被修改。
mysql> delimiter // mysql> create procedure out_param(out p_out int) -> begin -> select p_out; -> set p_out=2; -> select p_out; -> end -> // mysql> delimiter ; mysql> set @p_out=1; mysql> call out_param(@p_out); +---------+ | p_out | +---------+ | NULL | +---------+ #因為out是向調用者輸出參數,不接收輸入的參數,所以存儲過程里的p_out為null +---------+ | p_out | +---------+ | 2 | +---------+ mysql> select @p_out; +-----------+ | @p_out | +-----------+ | 2 | +-----------+ #調用了out_param存儲過程,輸出參數,改變了p_out變量的值
3)inout輸入參數
mysql> delimiter $$ mysql> create procedure inout_param(inout p_inout int) -> begin -> select p_inout; -> set p_inout=2; -> select p_inout; -> end -> $$ mysql> delimiter ; mysql> set @p_inout=1; mysql> call inout_param(@p_inout); +----------+ | p_inout | +----------+ | | +----------+ +----------+ | p_inout | +----------+ | 2 | +----------+ mysql> select @p_inout; +-------------+ | @p_inout | +-------------+ | 2 | +-------------+ #調用了inout_param存儲過程,接受了輸入的參數,也輸出參數,改變了變量
注意:
1、如果過程沒有參數,也必須在過程名后面寫上小括號例
2、確保參數的名字不等於列的名字,否則在過程體中,參數名被當做列名來處理
建議:inout參數就盡量的少用。
12.2 變量
1)變量定義
局部變量聲明一定要放在存儲過程體的開始:
DECLARE variable_name [,variable_name...] datatype [DEFAULT value];
其中,datatype 為 MySQL 的數據類型,如: int, float, date,varchar(length)
例如:
DECLARE l_int int unsigned default 4000000;
DECLARE l_numeric number(8,2) DEFAULT 9.95;
DECLARE l_date date DEFAULT '1999-12-31';
DECLARE l_datetime datetime DEFAULT '1999-12-31 23:59:59';
DECLARE l_varchar varchar(255) DEFAULT 'This will not be padded';
2)變量賦值
SET 變量名 = 表達式值 [,variable_name = expression ...]
3) 用戶變量
在MySQL客戶端使用用戶變量:
mysql > SELECT 'Hello World' into @x; mysql > SELECT @x; +---------------+ | @x | +---------------+ | Hello World | +---------------+ mysql > SET @y='Goodbye Cruel World'; mysql > SELECT @y; +---------------------+ | @y | +---------------------+ | Goodbye Cruel World | +---------------------+ mysql > SET @z=1+2+3; mysql > SELECT @z; +------+ | @z | +------+ | 6 | +------+
在存儲過程中使用用戶變量
mysql > CREATE PROCEDURE GreetWorld() SELECT CONCAT(@greeting,' World'); mysql > SET @greeting='Hello'; mysql > CALL GreetWorld( ); +----------------------------+ | CONCAT(@greeting,' World') | +----------------------------+ | Hello World | +----------------------------+
在存儲過程間傳遞全局范圍的用戶變量
mysql> CREATE PROCEDURE p1() SET @last_procedure='p1'; mysql> CREATE PROCEDURE p2() SELECT CONCAT('Last procedure was ',@last_procedure); mysql> CALL p1( ); mysql> CALL p2( ); +-----------------------------------------------+ | CONCAT('Last procedure was ',@last_proc | +-----------------------------------------------+ | Last procedure was p1 | +-----------------------------------------------+
注:
- 用戶變量名一般以@開頭
- 濫用用戶變量會導致程序難以理解及管理
12.3 MySQL存儲過程的查詢
我們可以用以下語句進行查詢:
select name from mysql.proc where db='數據庫名';
select routine_name from information_schema.routines where routine_schema='數據庫名';
show procedure status where db='數據庫名';
查看存儲過程的詳細信息:
SHOW CREATE PROCEDURE 數據庫.存儲過程名;
12.3 存儲過程的修改
ALTER PROCEDURE 存儲過程名 [ 特征 ... ];
該語句用於修改存儲過程的某些特征,如執行權限等。
12.4 存儲過程的刪除
DROP {PROCEDURE|FUNCTION} [if exists] 名稱;
注:如果存儲過程或存儲函數不存在時,仍然進行刪除,可以使用IF EXISTS子句,它可以防止發生錯誤。
12.5 MySQL存儲過程的控制語句
1)條件語句
if 語句
mysql > DELIMITER // mysql > CREATE PROCEDURE proc2(IN parameter int) -> begin -> declare var int; -> set var=parameter+1; -> if var=0 then -> insert into t values(17); -> end if; -> if parameter=0 then -> update t set s1=s1+1; -> else -> update t set s1=s1+2; -> end if; -> end; -> // mysql > DELIMITER ;
case 語句:
mysql > DELIMITER // mysql > CREATE PROCEDURE proc3 (in parameter int) -> begin -> declare var int; -> set var=parameter+1; -> case var -> when 0 then -> insert into t values(17); -> when 1 then -> insert into t values(18); -> else -> insert into t values(19); -> end case; -> end; -> // mysql > DELIMITER ; case when var=0 then insert into t values(30); when var>0 then when var<0 then else end case
3)循環語句
while 條件 do 循環體 end while
mysql > DELIMITER // mysql > CREATE PROCEDURE proc4() -> begin -> declare var int; -> set var=0; -> while var<6 do -> insert into t values(var); -> set var=var+1; -> end while; -> end; -> // mysql > DELIMITER ;
repeat 循環體 until 循環條件 end repeat
它在執行操作后檢查結果,而 while 則是執行前進行檢查。
mysql > DELIMITER // mysql > CREATE PROCEDURE proc5 () -> begin -> declare v int; -> set v=0; -> repeat -> insert into t values(v); -> set v=v+1; -> until v>=5 -> end repeat; -> end; -> // mysql > DELIMITER ;
4)LABLES 標號
標號可以用在 begin repeat while 或者 loop 語句前,語句標號只能在合法的語句前面使用。可以跳出循環,使運行指令達到復合語句的最后一步。
ITERATE迭代
ITERATE 通過引用復合語句的標號,來從新開始復合語句:
mysql > DELIMITER // mysql > CREATE PROCEDURE proc10 () -> begin -> declare v int; -> set v=0; -> LOOP_LABLE:loop -> if v=3 then -> set v=v+1; -> ITERATE LOOP_LABLE; -> end if; -> insert into t values(v); -> set v=v+1; -> if v>=5 then -> leave LOOP_LABLE; -> end if; -> end loop; -> end; -> // mysql > DELIMITER ;
13 事務
事務主要用於處理操作量大,復雜度高的數據。比如說,在人員管理系統中,你刪除一個人員,你既需要刪除人員的基本資料,也要刪除和該人員相關的信息,如信箱,文章等等,這樣,這些數據庫操作語句就構成一個事務!
- 在 MySQL 中只有使用了 Innodb 數據庫引擎的數據庫或表才支持事務。
- 事務處理可以用來維護數據庫的完整性,保證成批的 SQL 語句要么全部執行,要么全部不執行。
- 事務用來管理 insert,update,delete 語句
一般來說,事務是必須滿足4個條件(ACID):原子性(Atomicity,或稱不可分割性)、一致性(Consistency)、隔離性(Isolation,又稱獨立性)、持久性(Durability)。
- 原子性:一個事務(transaction)中的所有操作,要么全部完成,要么全部不完成,不會結束在中間某個環節。事務在執行過程中發生錯誤,會被回滾(Rollback)到事務開始前的狀態,就像這個事務從來沒有執行過一樣。
- 一致性:在事務開始之前和事務結束以后,數據庫的完整性沒有被破壞。這表示寫入的資料必須完全符合所有的預設規則,這包含資料的精確度、串聯性以及后續數據庫可以自發性地完成預定的工作。
- 隔離性:數據庫允許多個並發事務同時對其數據進行讀寫和修改的能力,隔離性可以防止多個事務並發執行時由於交叉執行而導致數據的不一致。事務隔離分為不同級別,包括讀未提交(Read uncommitted)、讀提交(read committed)、可重復讀(repeatable read)和串行化(Serializable)。
- 持久性:事務處理結束后,對數據的修改就是永久的,即便系統故障也不會丟失。
在 MySQL 命令行的默認設置下,事務都是自動提交的,即執行 SQL 語句后就會馬上執行 COMMIT 操作。因此要顯式地開啟一個事務務須使用命令 BEGIN 或 START TRANSACTION,或者執行命令 SET AUTOCOMMIT=0,用來禁止使用當前會話的自動提交。
事務控制語句:
- BEGIN 或 START TRANSACTION 顯式地開啟一個事務;
- COMMIT (COMMIT WORK)。COMMIT 會提交事務,並使已對數據庫進行的所有修改成為永久性的;
- ROLLBACK ( ROLLBACK WORK),不過二者是等價的。回滾會結束用戶的事務,並撤銷正在進行的所有未提交的修改;
- SAVEPOINT identifier,SAVEPOINT 允許在事務中創建一個保存點,一個事務中可以有多個 SAVEPOINT;
- RELEASE SAVEPOINT identifier 刪除一個事務的保存點,當沒有指定的保存點時,執行該語句會拋出一個異常;
- ROLLBACK TO identifier 把事務回滾到標記點;
- SET TRANSACTION 用來設置事務的隔離級別。InnoDB 存儲引擎提供事務的隔離級別有READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ 和 SERIALIZABLE。
MYSQL 事務處理主要有兩種方法:
1)用 BEGIN, ROLLBACK, COMMIT來實現
- BEGIN 開始一個事務
- ROLLBACK 事務回滾
- COMMIT 事務確認
2)直接用 SET 來改變 MySQL 的自動提交模式:
- SET AUTOCOMMIT=0 禁止自動提交
- SET AUTOCOMMIT=1 開啟自動提交
例:
CREATE TABLE test( id INT(5) ) ENGINE=INNODB; SELECT * FROM test;#查詢為空 begin; # 開始事務 insert into test value(5); insert into test value(6); commit; select * from test;#查詢到兩數據 begin; # 開始事務 insert into test values(7); rollback; #回滾 select * from test; # 因為回滾所以數據沒有插入
14 數據備份與還原
14.1 數據備份
備份數據可以保證數據庫中數據的安全,數據庫管理員需要定期的進行數據庫備份;
使用 mysqldump 命令備份
mysqldump -u username -p dbname [table1 table2 ...] > BackupName.sql
dbname 參數表示數據庫的名稱;table1 和 table2 參數表示表的名稱,沒有該參數時將備份整個數據庫;
BackupName.sql 參數表示備份文件的名稱,文件名前面可以加上路徑。通常以 sql 作為后綴。
14.2 數據還原
Mysql -u root -p [dbname] < backup.sql
dbname 參數表示數據庫名稱。該參數是可選參數,可以指定數據庫名,也可以不指定。指定數據庫名時,表
示還原該數據庫下的表。不指定數據庫名時,表示還原特定的一個數據庫。而備份文件中有創建數據庫的語句。






































































