MySQL數據庫總結

2020-08-08 12:14:40

第一章 數據庫的相關概念

1.1 數據庫的好處

  • 可以持久化數據到本地
  • 結構化查詢

1.2 數據庫的常見概念

  • DB:數據庫,儲存數據的容器。
  • DBMS:數據庫管理系統,又稱爲數據庫軟體或者數據庫產品,用於建立或管理DB。
  • SQL:結構化查詢語言,用於和數據庫通訊的語言,不是某個數據庫軟體特有的,而是幾乎所有主流數據庫軟體通用的語言。

1.3 數據庫儲存數據的特點

  • 數據存放到表中,然後表再放到庫中。
  • 一個庫中可以有多張表,每張表具有唯一的表名用來標識自己。
  • 表中有一個或多個列,列又稱爲「欄位」,相當於java中的「屬性」。
  • 表中的每一行數據,相當於java中的物件。

第二章 MySQL介紹

2.1 MySQL的優點

  • 開源、免費、成本低
  • 效能高、移植性好
  • 體積小,便於安裝

2.2 MySQL服務的啓動和停止

  • 方式一、通過命令列
    • net start 服務名
    • net stop 服務名
  • 方式二
    • 計算機——右鍵——管理——服務

2.3 MySQL服務的登陸和退出

  • 登錄
    • mysql 【-h 主機名 -p 埠號】-u 使用者名稱 -p密碼
  • 退出
    • exit

第三章 DQL語言

3.1 基礎查詢

3.1.1 語法

select 查詢列表 from 表名;

3.1.2 特點

  • 查詢列表可以是欄位、常數、表達式、函數、也可以是多個。
  • 查詢的結果是一個虛擬表。

3.1.3 範例

  • 查詢單個欄位
select 欄位名 from 表名;
  • 查詢多個欄位
select 欄位1,欄位2... from 表名;
  • 查詢所有欄位
select * from 表名;
  • 查詢常數
# 注意字元型和日期型的常數值必須用單引號擴起來,數值型不需要
select 常數值; 
  • 查詢函數
select 函數名(實參列表);
  • 查詢表達式
select 表達式;
  • 起別名
select 欄位 as 別名 from 表 as 別名;
或
select 欄位 別名 from 表 別名;
  • 去重
select distinct 欄位 from 表名;
  • '+':做加法運算
select 數值+數值;  # 直接運算
select 字元+數值;  # 先試圖將字元轉換爲數值,如果轉換成功,則繼續進行運算;否則轉換成0,再做運算
select null+值;   # 結果都爲NULL

3.1.4 程式碼演示

# 進階1:基礎查詢
/*
語法:
select 查詢列表 from 表名;

特點:
	1、查詢列表可以是:表中的欄位、常數值、表達式、函數
	2、查詢的結果式一個虛擬的表格
*/

# 細節一、在每次使用數據庫的時候應該用該語句指明要使用那個數據庫
USE myemployees;

# 細節二、當表中的欄位名和關鍵子重名的時候可以使用着重號來區分類似於`name`表示一個欄位

# 1、查詢表中的單個欄位
SELECT last_name FROM employees;

# 2、查詢表中的多個欄位
SELECT last_name,salary,email FROM employees;

# 3、查詢表中的所有欄位
SELECT  * FROM employees;

# 4、查詢常數值
SELECT 100;
SELECT 'john';

# 5、查詢表達式
SELECT 100*98;

# 6、查詢函數
SELECT VERSION();

# 7、起別名
/*
①便於理解
②如果要查詢的欄位有重名的情況,使用別名可以區分開來
③如果別名中有特殊字元可以用雙引號將別名包裹起來
*/
# 方式一
SELECT 100*98 AS 結果;
SELECT last_name AS 姓, first_name AS 名 FROM employees;

# 方式二
SELECT last_name 姓, first_name 名 FROM employees;

# 案例:查詢salary,顯示的結果偉out put
SELECT salary AS "out put" FROM employees;


# 8、去重
/*
在欄位名前面加上distinct關鍵字
*/
# 案例:查詢員工表中涉及到的所有的部門編號
SELECT DISTINCT department_id FROM employees; 

# 9、+號的作用
/*
mysql中的+號只能作爲運算子

select 100+90; 兩個運算元都爲數值型,則做加法運算
select '100'+90; 其中一方爲數值型,試圖將字元型數值轉換成數值型。
			如果轉換成功繼續做加法運算
			如果轉換失敗,則將字元型數值轉換成0
			
select 'jhon'+90;

select null+90; 只要其中一方爲null,則結果肯定爲null
*/
# 案例、查詢員工名和姓連線成一個欄位,並顯示偉姓名
/*
concat:用於連線多個字串
*/
SELECT CONCAT(last_name, first_name) AS 姓名 FROM employees;

3.2 條件查詢

3.2.1 語法

select 查詢列表 from 表名 where 篩選條件;

3.2.2 篩選條件的分類

  • 簡單條件運算子
    • >  <  =  <>  !=  >=  <=  <=>
  • 邏輯運算子
    • &&  AND
    • || OR
    • ! NOT
  • 模糊查詢
    • like:一般搭配萬用字元使用,可以判斷字元型或數值型(%表示任意多個字元,_表示任意單個字元)
    • between:效果等同於 >= and <= 
    • in
    • is null或is not null:用於判斷null值
is null 與 <=>對比
  普通型別的數值 null值 可讀性
is null 不支援 支援
<=> 支援 支援 不好

3.2.3 程式碼演示

# 進階2:條件查詢
/*
語法:
select
	查詢列表
from
	表名
where
	篩選條件;
	
分類:
	1、按條件表達式篩選
	條件運算子:> < = != <> >= <=
	
	2、按邏輯表達式篩選
	邏輯運算子:
	作用:用於連線條件表達式
		    && || !
		    and or not
	
	3、模糊查詢
		like
		between and
		in
		is null
*/
#一、按條件表達式篩選
# 案例一、查詢工資>12000的員工的資訊
SELECT 
  * 
FROM
  employees 
WHERE salary > 12000 ;

# 案例二、查詢部門編號不等於90號的員工名和部門編號
SELECT last_name, department_id FROM employees WHERE department_id <> 90;
 
# 二、按邏輯表達式篩選
# 案例一、查詢工資在10000到20000之間的員工名、工資以及獎金
SELECT last_name, salary, commission_pct FROM employees WHERE salary > 10000 AND salary < 20000;

# 查詢部門編號不是在90到110之間,或者工資高於15000的員工
SELECT * FROM employees WHERE NOT(department_id >= 90 AND department_id <= 110) OR salary > 15000;


# 三、模糊查詢
/*
like
特點:
①一般和萬用字元搭配使用
	萬用字元:
		% 任意多個字元,包含0個字元
		_ 任意單個字元

between and
in
is null | is not null

*/
# 1、like
# 案例一、查詢員工名中包含字元a的員工資訊
SELECT * FROM employees WHERE last_name LIKE '%a%';

# 案例二、查詢員工名中第三個字元爲n,第五個字元爲l的員工名和工資
SELECT last_name,salary FROM employees WHERE last_name LIKE '__n_l%';

# 案例三、查詢員工名中第二個字元爲_的員工名,
# 可以使用跳脫字元:\
# 或者可以使用escape指定跳脫字元
SELECT last_name FROM employees WHERE last_name LIKE '_$_%' ESCAPE '$';

# 2、between and
/*
①使用between and可以提高語句的簡潔度
②包含臨界值
③兩個臨界值不能換順序

*/

# 案例一、查詢員工編號在100到120之間的員工資訊
SELECT * FROM employees WHERE employee_id BETWEEN 100 AND 120;

# 3、in
/*
含義:判斷某欄位的值是否屬於in列表中的某一項
特點:
	①使用in提高語句的簡潔度
	②in列表的值型別必須一致或者相容


*/
# 案例一、查詢員工的工種編號是 IT_PROG、AD_VD、AD_PRES中的一個員工名和工種編號
SELECT last_name,job_id FROM employees WHERE job_id IN('IT_prot', 'AD_YP', 'AD_PRES');

# 4、is null
/*
is null或is not null 可以判斷null值

*/
# 案例1:查詢沒有獎金的員工名和獎金率
SELECT last_name,commission_pct FROM employees WHERE commission_pct IS NULL;

# 案例1:查詢有獎金的員工名和獎金率
SELECT last_name,commission_pct FROM employees WHERE commission_pct IS NOT NULL;


# 安全等於<=>
# 案例一:查詢沒有獎金的員工名和獎金率
SELECT last_name,commission_pct FROM employees WHERE commission_pct <=> NULL;

# 案例二:查詢工資爲12000的員工資訊
SELECT last_name, commission_pct FROM employees WHERE salary <=> 12000;


# is null pk <=>
/*
is null:僅僅可以判斷null值,可讀性較高,建議使用
<=>:既可以判斷null值,又可以判斷普通的數值

*/

3.3 排序查詢

3.3.1 語法

select 查詢列表 from 表名 order by 排序列表 【asc|desc】;

3.3.2 特點

  • asc表示升序,不寫預設爲升序,desc:爲降序
  • 排序列表支援單個欄位、多個欄位、函數、表達式、別名
  • order by位置一般放在查詢語句的最後(除了limit語句外)

3.3.3 程式碼演示

# 進階3、排序查詢
/*
語法:
	select 查詢列表 from 表名 【where 篩選條件】 order by 排序列表 【asc|desc】;
	
特點:
	1、asc代表升序,desc代表降序,不寫預設升序
	2、order by 子句中可以支援單個欄位,多個欄位、表達式、函數、別名
	3、order by子句一般是放在查詢語句的最後,limit子句除外
*/

# 案例一:查詢員工資訊,要求工資從高到低排序
SELECT * FROM employees ORDER BY salary DESC;

# 案例二、查詢部門編號>=90的員工資訊,按入職時間的先後 先後進行排序[新增篩選條件]
SELECT * FROM employees WHERE department_id >= 90 ORDER BY hiredate ASC;

# 案例三、按年薪的高低顯示員工的資訊和年薪【按表達式排序】
SELECT *, salary*12*(1+IFNULL(commission_pct, 0)) AS 年薪 FROM employees ORDER BY salary*12*(1+IFNULL(commission_pct, 0));

# 案例四、按年薪的高低顯示員工的資訊和年薪【按別名排序】
SELECT *, salary*12*(1+IFNULL(commission_pct, 0)) AS 年薪 FROM employees ORDER BY 年薪;

# 案例5、按員工姓名的長度顯示員工的姓名和工資【按函數排序】
SELECT LENGTH(last_name) AS 位元組長度,last_name,salary FROM employees ORDER BY LENGTH(last_name);

# 案例6、查詢員工資訊,要求先按照工資排序,再按照員工編號排序【按多個欄位排序】
SELECT * FROM employees ORDER BY salary ASC, employee_id DESC;

 

3.4 常見函數

3.4.1 函數的概述

  • 功能:類似於java中的方法
  • 好處:提高程式碼的重用性且隱藏了實現細節
  • 呼叫:select 函數名(實參列表);

3.4.2 單行函數

  • 字元函數
    • concat:拼接字串
    • substr:擷取子串
    • upper:變大寫
    • lower:變小寫
    • repalce:替換
    • length:獲取位元組長度
    • trim:去前後空格
    • lpad:左填充
    • rpad:右填充
    • instr:獲取子串第一次出現的索引
    • ifnull:判斷某欄位或表達式是否爲null,如果爲null 返回指定的值,否則返回原本的值
    • isnull:判斷某欄位或表達式是否爲null,如果是,則返回1,否則返回0;
  • 數學函數
    • ceil:向上取整
    • floor:向下取整
    • round:四捨五入
    • mod:取模
    • truncate:截斷
    • rand:獲取亂數,返回0-1之間的小數
  • 日期函數
    • now:返回當前日期+時間
    • year:返回年
    • month:返回月
    • day:返回日
    • date_format:將日期轉換成字元
    • curdate:返回當前日期
    • str_to_date:將字元轉換成日期
    • curtime:返回當前時間
    • hour:小時
    • minute:分鐘
    • second:秒
    • datediff:返回兩個日期相差的天數
    • monthname:以英文形式返回月
  • 其他函數
    • version:檢視當前數據庫伺服器的版本
    • database:當前開啓的數據庫
    • user:當前使用者
    • password('字元'):返回該字元的密碼形式
    • md5('字元'):返回該字元的md5加密形式
  • 流程控制函數
    • if(條件表達式,表達式1,表達式2):如果條件表達式成立,返回表達式1,否則返回表達式2
    • case
# 情況一
case 變數或表達式或欄位
when 常數1 then 值1
when 常數2 then 值2
...
else 值n
end

# 情況二
case 
when 條件1 then 值1
when 條件2 then 值2
...
else 值n
end
  • 分組函數
    • max:最大值
    • min:最小值
    • sum:和
    • avg:平均數
    • count:計算個數
/*
分組函數的特點:
1、語法
select 函數名(欄位名) from 表名;
2、支援的型別
    sum和avg一般用於處理數值型
    max、min、count可以處理任何型別
3、以上的分組函數都忽略null值
4、都可以搭配distinct使用,實現去重的統計
    select 函數名(distinct 欄位) from 表;
5、count函數
    count(欄位):統計該欄位非空值的個數
    count(*):統計結果集的行數



*/

 3.4.3 程式碼演示

# 進階4:常見函數
/*
功能:類似於java中的方法,將一組邏輯語句封裝再方法體中,對外暴露方法名
好處:1、隱藏了實現細節  2、提高了程式碼的重用性

呼叫:select 函數名(參數列表) 【from 表】;

特點:
	①叫什麼(函數名)
	②幹什麼(函數的功能)

分類:
	1、單行函數
	如:concat、length、ifnull等
	2、分組函數
	功能:做統計使用,又稱爲統計函數、聚合函數、組函數
	
常見的單行函數:
	字元函數
		length
		concat
		substr/substring
		instr
		upper
		lower
		lpad
		rpad
		replace
	
	數學函數
		round
		ceil
		floor
		truncate
		mod
		
	日期函數
		now
		curdate
		curtime
		year
		month
		monthname
		day
		hour
		minute
		second
		str_to_date
		date_format
	
	其他函數:
		version
		database
		ueser
	
	控制函數
		if
		case
		
*/

# 一、字元函數
# 1、length:獲取參數值的位元組個數
SELECT LENGTH('jhon');
SELECT LENGTH('張三豐hahaha');

# 2、concat:拼接字串
SELECT CONCAT(last_name,'_', first_name) FROM employees;

# 3、upper、lower
SELECT UPPER('john');
SELECT LOWER('FJDH');

# 範例:將姓變大寫,名變小寫,然後拼接。
SELECT CONCAT(UPPER(first_name), LOWER(last_name)) AS 姓名 FROM employees;

# substr、substring:擷取字元,注意索引從1開始
# 擷取從指定索引出後面所有字元
SELECT SUBSTR('李莫愁愛上了陸展元', 7) out_put; 

# 擷取從指定索引出指定長度的字元
SELECT SUBSTR('李莫愁愛上了陸展元', 1, 3);

# 案例:姓名中首字母大寫,其他字元小寫然後用_拼接,顯示出來
SELECT 
  CONCAT(
    UPPER(SUBSTR(last_name, 1, 1)),
    '_',
    LOWER(SUBSTR(last_name, 2))
  ) 
FROM
  employees ;
  
# 5、instr:返回子串第一次出現的索引,如果找不到返回0
SELECT INSTR('楊不悔愛上了殷六俠', '殷六俠') AS out_put; 

# 6、trim:去掉字串兩端的指定字元,預設爲空格
SELECT TRIM('  張翠山    ') AS out_put;
SELECT TRIM('a' FROM 'aaaaa張aaa翠山aaaaa') AS out_put;


# lpad:用指定的字元實現左填充指定長度,如果超過了就擷取指定長度
SELECT LPAD('殷素素', 10, '*') AS out_put;

# rpad:用指定的字元實現右填充指定長度
SELECT RPAD('殷素素', 12, 'ab') AS out_put;

# replace:替換,如果右多個就都替換
SELECT REPLACE('周芷若周芷若周芷若張無忌愛上了周芷若','周芷若','趙敏') AS out_put;

# 二、數學函數
# round 四捨五入,第二個參數表示小數點後保留幾位
SELECT ROUND(1.65);
SELECT ROUND(1.567, 2);

# ceil:向上取整,返回>=該參數的最小整數
SELECT CEIL(1.90);

# floor:向下取整,返回<=該參數的最大整數
SELECT FLOOR(9.99);
 
# truncate:截斷,擷取小數點後的指定位數
SELECT TRUNCATE(1.65, 1);
 
# mod取餘:公式:mod(a, b) a-a/b*b
SELECT MOD(-10, 3);
SELECT 10%3;


# 三、日期函數

# now:返回當前系統日期+時間
SELECT NOW();

# curdate:返回當前系統的日期,不包含時間
SELECT CURDATE();

# curtime:返回當前的時間,不包含日期
SELECT CURTIME();

# 可以獲取指定的部分:年、月、日、時、分、秒
SELECT YEAR(NOW()) 年;
SELECT YEAR('1998-1-1') 年;
SELECT YEAR(hiredate) 年 FROM employees;
SELECT MONTH(NOW()) 月;
SELECT MONTHNAME(NOW()); #英文

# str_to_date 將字元通過指定的格式轉換成日期
SELECT STR_TO_DATE('1998-3-2', '%Y-%c-%d') AS out_put;

# 查詢入職日期爲1992-4-3的員工資訊
SELECT * FROM employees WHERE hiredate = STR_TO_DATE('4-3 1992', '%c-%d %Y');

# date_format:將日期轉換成字元
SELECT DATE_FORMAT(NOW(), '%y年%m月%d日') AS out_put;

# 查詢有獎金的員工名和入職日期(xx月/xx日 xx年)
SELECT last_name, DATE_FORMAT(hiredate, "%m月/%d日 %y年") 入職日期 FROM employees WHERE commission_pct IS NOT NULL;

# 四、其他函數

# 檢視當前數據庫版本
SELECT VERSION();

# 檢視當前的數據庫
SELECT DATABASE();

# 檢視當前的使用者
SELECT USER();

# 五、流程控制函數
# if函數:if else 的效果,類似於三目運算子
SELECT IF(10>5, '大', '小');

SELECT last_name, commission_pct, IF(commission_pct IS NULL, '沒獎金,哈哈', '有獎金,嘻嘻') 備註 FROM employees;

# 2、case函數
# 使用一、類似於switch case效果
/*
case 要判斷的欄位或表達式
when 常數1 then 要顯示的值1或語句1;
when 常數2 then 要顯示的值2或語句1;
when 常數3 then 要顯示的值3或語句1;
...
else 預設的情況,要顯示的值或語句
end
*/
/*
案例:查詢員工的工資,要求
部門號=30,顯示的工資爲1.1倍
部門號=40,顯示的工資爲1.2倍
部門號=50,顯示的工資爲1.3倍
其他部門,顯示的工資爲原工資
*/
SELECT 
  salary 原始工資,
  department_id,
  CASE
    department_id 
    WHEN 30 
    THEN salary * 1.1 
    WHEN 40 
    THEN salary * 1.2 
    WHEN 50 
    THEN salary * 1.3 
    ELSE salary 
  END AS 新工資 
FROM
  employees ;

# case函數的使用二、類似於多重if
/*
case
when 條件1 then 要顯示的值1或語句1
when 條件2 then 要顯示的值2或語句2
when 條件3 then 要顯示的值3或語句3
...
else 要顯示的值n或語句n
end
*/
# 案例:查詢員工的工資情況
/*
如果工資>20000,顯示A級別
如果工資>15000,顯示B級別
如果工作>10000,顯示C級別
否則,顯示D級別
*/
SELECT 
  salary,
  CASE
    WHEN salary > 20000 
    THEN 'A' 
    WHEN salary > 15000  
    THEN 'B' 
    WHEN salary > 10000 
    THEN 'C' 
    ELSE 'D' 
  END AS 工資級別 
FROM
  employees ;


# 二、分組函數
/*
功能:用作統計使用,又稱爲聚合函數或統計函數或組函數

分類:
sum 求和
avg 平均值
max 最大值
min 最小值
count 計算個數

特點:
	1、sum和avg一般用於處理數值型
	   max和min支援字元型,日期,數值型
	   count支援任意型別,只計算非空的值的個數
	2、是否忽略null值,以上分組函數都忽略null值
	3、可以和distinct搭配使用,實現去重的運算

4、count函數的單獨介紹
一般使用count(*)來統計行數

5、和分組函數一同查詢的欄位要求是group by後的欄位

*/
# 1、簡單使用
SELECT SUM(salary) FROM employees;
SELECT AVG(salary) FROM employees;
SELECT MIN(salary) FROM employees;
SELECT MAX(salary) FROM employees;
SELECT COUNT(salary) FROM employees;

SELECT 
  SUM(salary) 和,
  AVG(salary) 平均數,
  MIN(salary) 最小值,
  MAX(salary) 最大值,
  COUNT(salary) 個數 
FROM
  employees ;


# 和distinct搭配
SELECT SUM(DISTINCT salary), SUM(salary) FROM employees;
SELECT COUNT(DISTINCT salary), COUNT(salary) FROM employees;

# count函數詳細介紹
SELECT COUNT(salary) FROM employees;

SELECT COUNT(*) FROM employees;
 
# 效率:
# MYISAN儲存引擎下,count(*)的效率高
# INNODB儲存引擎下,count(*) 和count(1)的效率差不多,比count(欄位)要高一些

# 和分組哈數一同查詢的欄位有限制
SELECT AVG(salary), employee_id FROM employees;

3.5 分組查詢

3.5.1 語法

select 分組函數,分組後的欄位
from 表
【where 篩選條件】
group by 分組的欄位
【having 分組後的篩選條件】
【order by 排序列表】;

3.5.2 特點

分組前的篩選和分組後的篩選對比
  使用關鍵字 篩選的表 位置
分組前的篩選 where 原始表 group by的前面
分組後篩選 having 分組後的結果 group by的後面

3.5.3 程式碼演示

# 進階5:分組查詢
/*
語法:
	select 分組函數, 列(要求出現在group by的後面)
	from 表
	【where 篩選條件】
	group by 分組的列表
	【order by 子句】

注意:
	查詢列表必須特殊,要求是分組函數和group by後出現的欄位

特點:
	1、分組查詢中的篩選條件分爲兩類
			數據源		位置			關鍵字
	分組前篩選	原始表		group by子句的前面	where
	分組後篩選	分組後的結果集  group by子句的後面	having
	
	①分組函數左條件肯定是放在having子句中
	②能用分組前篩選的,就優先考慮使用分組前篩選
	
	2、group by子句支援單個欄位分組,多個欄位分組(多個欄位之間用逗號隔開沒有順序要求),表達式或函數(用的較少)
	3、也可以新增排序(排序放在整個分組查詢的最後)
*/
# 簡單的分組查詢
# 案例一、查詢每個工種的最高工資
SELECT job_id,MAX(salary) FROM employees GROUP BY job_id;

# 案例二、查詢每個位置上的部門個數
SELECT location_id,COUNT(*) FROM departments GROUP BY location_id;

# 新增條件篩選
# 案例一:查詢郵箱中包含a字元的,每個部門的平均工資
SELECT AVG(salary),department_id FROM employees WHERE email LIKE '%a%' GROUP BY department_id;

# 案例二、查詢有獎金的每個領導手下員工的最高工資
SELECT MAX(salary),manager_id FROM employees WHERE commission_pct IS NOT NULL GROUP BY manager_id;

# 新增複雜的篩選條件(新增分組後的篩選)
# 案例一、查詢哪個部門的員工個數>2
SELECT COUNT(*),department_id FROM employees GROUP BY department_id HAVING COUNT(*)>2;

# 案例二、查詢每個工種有獎金的員工的最高工資>12000的工種編號和最高工資
SELECT job_id,MAX(salary) FROM employees WHERE commission_pct IS NOT NULL GROUP BY job_id HAVING MAX(salary)>12000;

# 案例三、查詢領導編號>102的每個領導手下的最低工資>5000的領導編號是哪個以及其最低工資
SELECT 
  manager_id,
  MIN(salary) 
FROM
  employees 
WHERE manager_id > 102 
GROUP BY manager_id 
HAVING MIN(salary) > 5000 ;

# 按表達式或函數分組
# 案例:按員工姓名的長度分組,查詢每一組的員工個數,篩選員工個數>5的有哪些
SELECT COUNT(*) 個數,LENGTH(last_name) 名字長度 FROM employees GROUP BY LENGTH(last_name) HAVING COUNT(*)>5;

# 按多個欄位分組
# 案例:查詢每個部門每個工種的員工的平均工資
SELECT AVG(salary),department_id,job_id FROM employees GROUP BY department_id,job_id;

# 新增排序
# 案例:查詢每個部門每個工種的員工的平均工資,並且按照平均工資的高低排序且部門編號不爲null,平均工資大於10000
SELECT 
  AVG(salary),
  department_id,
  job_id 
FROM
  employees 
WHERE department_id IS NOT NULL 
GROUP BY department_id,
  job_id 
HAVING AVG(salary) > 10000 
ORDER BY AVG(salary) ;

3.6 連線查詢 

3.6.1 含義

  • 當查詢中涉及到了多個表的欄位,需要使用多表連線
  • 笛卡爾乘積現象:當查詢多個表時,沒有新增有效的連線條件,導致多個表所有行實現完全連線,可以通過新增有效的連線條件來解決。

3.6.2 分類

  • 按年代分類
    • sql92語法:
      • 等值連線
      • 非等值連線
      • 自連線
      • 也支援部分外連線(用於oracle,sqlserver,mysql不支援)
    • sql99語法
      • 內連線
        • 等值連線
        • 非等值連線
        • 自連線
      • 外連線
        • 左外連線
        • 右外連線
        • 全外連線(mysql不支援)
      • 交叉連線

3.6.3 sql92語法

  • 等值連線
select 查詢列表
from 表1 別名,表2 別名
where 表1.key=表2.key
【and 篩選條件】
【group by 分組欄位】
【having 分組後的篩選】
【order by 排序欄位】;
  • 特點
    • 一般爲表起別名
    • 多表的順序可以調換
    • n表連線至少需要n-1個連線條件
    • 等值連線的結果是多表的交集部分
  • 非等值連線
select 查詢列表
from 表1 別名1,表2 別名2
where 非等值連線的條件
【and 篩選條件】
【group by 分組欄位】
【having 分組後的篩選】
【order by 排序欄位】;
  • 自連線
select 查詢列表
from 表 別名1,表 別名2
where 等值連線條件
【and 篩選條件】
【group by 分組欄位】
【having 分組後的篩選】
【order by 排序欄位】;
  •  程式碼演示
# 進階六、連線查詢
/*
含義:又稱爲多表查詢,當查詢的欄位來自於多個表時,就會用到連線查詢

笛卡爾乘積現象:表一有m行,表二有n行,結果m*n行
發生原因:沒有有效的連線條件
解決原因:提供有效的連線

分類:
	按年代分類:
		sql92標準:支支援內鏈接
		sql99標準【推薦】:支援內連線+外連線(左外和右外)+交叉連線
	
	按功能分類
		內連線:
			等值連線
			非等值連線
			自連線
		外連線
			左外連線
			右外連線
			全外連線
		交叉連線
*/
# 一、sql92標準
# 1、等值連線
/*
特點:
①多表等值連線爲多表的交集部分
②n表連線,至少需要有n-1個連線條件
③多表的順序沒有要求
④一般需要爲表起別名
⑤可以搭配前面介紹的所有子句使用,比如排序、分組、篩選
*/
# 案例1、查詢女神名和對應的男神名
SELECT 
  NAME,
  boyname 
FROM
  boys,
  beauty 
WHERE beauty.`boyfriend_id` = boys.`id` ;

# 案例2:查詢員工名和對應的部門名
SELECT last_name,department_name FROM employees,departments WHERE employees.`department_id`=departments.`department_id`;

# 2、爲表其別名
/*
提高語句的簡潔度
區分多個重名的欄位

注意:
1、如果爲表起了別名,則查詢的欄位就不能使用原來的表名去限定
2、查詢的表名可以順序可以調
*/
# 查詢員工名、工種號、工種名
SELECT last_name,employees.job_id,job_title FROM employees,jobs WHERE employees.`job_id`=jobs.`job_id`;
SELECT last_name,e.job_id,job_title FROM employees AS e,jobs AS j WHERE e.`job_id`=j.`job_id`;

# 案例:查詢有獎金的員工名、部門名
SELECT e.last_name,d.department_name FROM employees AS e,departments AS d WHERE e.`department_id`=d.`department_id` AND e.`commission_pct` IS NOT NULL;

# 案例2、查詢城市名中第二個字元爲o的部門名和城市名【加篩選條件】
SELECT d.department_name, l.city FROM departments AS d, locations AS l WHERE d.`location_id`=l.`location_id` AND l.`city` LIKE '_o%';

# 查詢每個城市的部門個數【加上分組】
SELECT COUNT(*) 個數,city
FROM departments d, locations l 
WHERE d.`location_id`=l.`location_id`
GROUP BY l.`city`;

# 案例2:查詢出有獎金的每個部門的部門名和部門的領導編號和該部門的最低工資【新增分組】
SELECT d.department_name AS 部門名, d.manager_id AS 領導編號, MIN(e.salary)
FROM departments AS d, employees AS e
WHERE d.`department_id`=e.`department_id`
AND commission_pct IS NOT NULL
GROUP BY d.`department_name`,d.`manager_id`;

# 案例:查詢每個工種的工種名和員工的個數,並且按員工的個數降序
SELECT j.job_title AS 工種名,COUNT(*) AS 員工個數
FROM jobs AS j, employees AS e
WHERE e.`job_id`=j.`job_id`;
GROUP BY j.job_title
ORDER BY COUNT(*) DESC;

# 案例:查詢員工名、部門名和所在的城市【三表連線】
SELECT last_name,department_name,city 
FROM employees AS e, departments AS d, locations AS l
WHERE e.`department_id`=d.`department_id`
AND d.`location_id`=l.`location_id`
AND city LIKE 's%'
ORDER BY department_name DESC; 


# 2、非等值連線
# 案例一、查詢員工的工資和工資級別
SELECT salary,grade_level
FROM employees e, job_grades g
WHERE salary BETWEEN g.`lowest_sal` AND g.`highest_sal`
AND g.`grade_level`='A';

# 3、自連線

# 案例:查詢員工名和上級的名字
SELECT e.employee_id,e.last_name,m.employee_id,m.last_name
FROM employees e,employees m
WHERE e.`employee_id`=m.`employee_id`;

3.6.4 sql99語法

  • 內連線
select 查詢列表
from 表1 別名
【inner】join 表2 別名 on 連線條件
where 篩選條件
group by 分組列表
having 分組後的篩選
order by 排序列表
limit 子句;
  • 特點
    • 表的順序可以調換
    • 內連線的結果=多表的交集
    • n表連線至少需要n-1個連線條件
  • 分類
    • 等值連線
    • 非等值連線
    • 自連線
  • 外連線
select 查詢列表
from 表1 別名
left|right|full【outer】join 表2 別名 on 連線條件
where 篩選條件
group by 分組列表
having 分組後的篩選
order by 排序列表
limit 子句;
  • 特點:
    • 查詢的結果=主表中所有的行,如果從表和它匹配的將顯示匹配行,如果從表沒有匹配的則顯示null
    • left join 左邊的就是主表,right join 右邊的就是主表,full join兩邊都是主表
    • 一般用於查詢除了交集部分的剩餘的不匹配的行
  • 交叉連線(類似於笛卡爾乘積)
select 查詢列表
from 表1 別名
cross join 表2 別名;
  • 程式碼演示
# 二、sql99語法
/*
語法:
	select 查詢列表
	from 表1 別名【連線型別】
	join 表2 別名
	on 連線條件
	【where 篩選條件】
	【group by 分組】
	【having 篩選條件】
	【order by 排序列表】
	

內連線:inner
外連線
	左外:left 【outer】 
	右外:right 【outer】
	全外:full 【outer】
交叉連線:cross
*/
# 一)內連線
/*
語法:
	select 查詢列表
	from 表1 別名
	inner join 表2 別名
	on 連線條件;

分類:
等值連線
非等值連線
自連線

特點:
	①新增排序,分組,篩選
	②inner可以省略
	③篩選條件放在where後面,連線條件放在on的後面,提高分離性,便於閱讀
	④inner join連線和sql92語法中的等值連線效果是一樣的,都是查詢多表的交集
	

*/

# 1、等值連線
# 查詢員工名,部門名
SELECT last_name,department_name
FROM employees e
INNER JOIN departments d
ON e.`department_id`=d.`department_id`;

# 查詢名字中包含e的員工名和工種名(篩選)
SELECT last_name,job_title
FROM employees e
INNER JOIN jobs j
ON e.`job_id`=j.`job_id`
WHERE e.`last_name` LIKE '%e%';

# 查尋部門個數>3的城市名和部門個數(分組+篩選)
SELECT city,COUNT(*)
FROM locations l
INNER JOIN departments d
ON l.`location_id`=d.`location_id`
GROUP BY l.`city`
HAVING COUNT(*)>3;

# 查詢哪個部門的部門員工個數>3的部門名和員工個數,並按個數降序(排序)
SELECT department_name, COUNT(*) 員工個數
FROM departments d
INNER JOIN employees e
ON d.`department_id`=e.`department_id`
GROUP BY d.`department_id`
HAVING COUNT(*)>3
ORDER BY COUNT(*) DESC;

# 查詢員工名,部門名,工種名,並按部門名降序
SELECT last_name,department_name,job_title
FROM employees e
INNER JOIN departments d
ON e.`department_id`=d.`department_id`
INNER JOIN jobs j
ON e.`job_id`=j.`job_id`
ORDER BY d.`department_name` DESC;

# 二)非等值連線
# 查詢員工的工資級別
SELECT last_name,salary,grade_level
FROM employees e
INNER JOIN job_grades j
ON e.`salary` BETWEEN j.lowest_sal AND j.highest_sal;

# 查詢工資級別的個數>20的個數,並且按工資級別降序
SELECT grade_level,COUNT(*) 個數
FROM employees e
INNER JOIN job_grades j
ON e.`salary` BETWEEN j.`lowest_sal` AND j.`highest_sal`
GROUP BY j.`grade_level`
HAVING COUNT(*)>20
ORDER BY j.`grade_level` DESC;
 

# 三)自連線
# 查詢員工的名字、上級的名字
SELECT e.`last_name`,m.`last_name`
FROM employees e
INNER JOIN employees m
ON e.`manager_id`=m.`employee_id`;

# 查詢姓名中包含字元'k'員工的名字、上級的名字
SELECT e.`last_name`,m.`last_name`
FROM employees e
INNER JOIN employees m
ON e.`manager_id`=m.`employee_id`
WHERE e.`last_name` LIKE '%k%';


# 外連線
/*
應用場景:用於查詢一個表中有,另一個表中沒有的記錄

特點:
	1、外連線的查詢結果爲主表中的所有記錄
		如果從表中有和他匹配的,則顯示匹配的值
		如果從表中沒有和他匹配的,則顯示null
		外連線的查詢結果=內鏈接的結果+主表中有而從表中沒有的記錄
	2、左外連線:left join左邊的是主表
	   右外連線:right join 右邊的是主表
	3、左外和右外交換兩個表的順序,可以實現同樣的效果
	4、一般來說要查詢的資訊主要來自於誰誰就是主表
	5、全外連線=內連線的結果+表一中有但是表二中沒有的+表二中有但是表一中沒有的
	

*/

# 引入:查詢男朋友不再男生表的女神名
# 左外連線
SELECT b.name
FROM beauty b
LEFT OUTER JOIN boys bo
ON b.`boyfriend_id`=bo.`id`
WHERE bo.`id` IS NULL;
# 右外連線
SELECT b.name
FROM boys bo
RIGHT OUTER JOIN beauty b
ON b.`boyfriend_id`=bo.`id`
WHERE bo.`id` IS NULL;

# 案例一、查詢哪個部門沒有員工
# 左外連線
SELECT department_name
FROM departments d
LEFT OUTER JOIN employees e
ON d.`department_id`=e.`department_id`
WHERE e.employee_id IS NULL;
# 右外連線
SELECT department_name
FROM employees e
RIGHT OUTER JOIN departments d
ON e.`department_id`=d.`department_id`
WHERE e.`employee_id` IS NULL;


# 全外
SELECT b.*,bo.*
FROM beauty b
FULL OUTER JOIN boys bo
ON b.boyfriend_id=bo.id; 


# 交叉連線
/*
笛卡爾乘積
*/
SELECT b.*,bo.*
FROM beauty b
CROSS JOIN boys bo;



# sql92和sql99pk
/*
功能:sql99支援的較多
可讀性:sql實現了連線條件和篩選條件分離,可讀性較高
*/

3.7 子查詢

3.7.1 含義

  • 巢狀在其他語句內部的select語句稱爲子查詢或內查詢,外面的語句可以是insert、update、delete、select等,一般select作爲外面語句較多,外面如果爲select語句,則此語句稱爲外查詢或主查詢。

3.7.2 分類

  • 按出現位置
    • select後面
      • 僅僅支援標量子查詢
    • from後面
      • 表子查詢
    • where或having後面
      • 標量子查詢
      • 列子查詢
      • 行子查詢
    • exists後面
      • 標量子查詢
      • 列子查詢
      • 行子查詢
      • 表子查詢
  • 按結果集的行列
    • 標量子查詢(單行子查詢):結果集爲一行一列
    • 列子查詢(多行子查詢):結果集爲多行一列
    • 行子查詢:結果集爲多行多列
    • 表子查詢:結果集爲多行多列

3.7.3 程式碼演示

# 進階7:子查詢
/*
含義:
出現在其他語句中的select語句,稱爲子查詢或內查詢
外部的查詢語句,稱爲主查詢或外查詢

分類:
按子查詢出現的位置:
	select後面
		僅僅支援標量子查詢
	from後面
		支援表子查詢
	
	where或having後面 ★
		標量子查詢(單行)
		列子查詢(多行)
		
		行子查詢
		
	exists後面(相關子查詢)
		表子查詢

按結果集的行列數不同:
	標量子查詢(結果集只有一行一列)
	列子查詢(結果集只有一行多列)
	行子查詢(結果集有一行多列)
	表子查詢(結果集一般爲多行多列)

*/


# 一、where或having後面
/*
特點:
	1、子查詢房放在小括號內
	2、子查詢一般放在條件的右側
	3、標量子查詢,一般搭配着單行操作符使用
			< > >= <= <>
	
	4、列子查詢:一般搭配多行操作符使用
		IN、ANY/SOME、ALL
	5、子查詢的執行優先於主查詢的執行,主查詢的條件用到了子查詢的結果

*/

# 1、標量子查詢(單行子查詢)
/*
非法使用標量子查詢:子查詢的結果不是一行一列

*/
# 案例一:誰的工資比Abel高
# ①查詢Abel的工資
SELECT salary
FROM employees 
WHERE last_name = 'Abel';
# ②查詢員工的資訊,滿足salary>①的結果
SELECT 
  * 
FROM
  employees 
WHERE salary > 
  (SELECT 
    salary 
  FROM
    employees 
  WHERE last_name = 'Abel') ;
  
# 案例二、返回job_id與141號員工相同,salary比143號員工多的員工的姓名、job_id和工資
SELECT last_name,job_id,salary
FROM employees
WHERE job_id = (
	SELECT job_id
	FROM employees 
	WHERE employee_id=141
) AND salary > (
	SELECT salary
	FROM employees
	WHERE employee_id=143
);

# 案例三、返回公司工資最少的員工的last_name,job_id和salary
SELECT last_name,job_id,salary
FROM employees
WHERE salary = (
	SELECT MIN(salary)
	FROM employees
)

# 案例四、查詢最低工資大於50號部門最低工資的部門id和其最低工資
SELECT department_id,MIN(salary)
FROM employees
GROUP BY department_id
HAVING MIN(salary) > (
	SELECT MIN(salary)
	FROM employees
	WHERE department_id=50
);




# 2、列子查詢(多行子查詢)
# 案例一、返回location_id是1400或1700的部門中的所有員工姓名
SELECT last_name
FROM employees
WHERE department_id IN (
	SELECT DISTINCT department_id
	FROM departments
	WHERE location_id IN (1400,1700)
);

# 案例二、返回其它工種中比job_id爲'IT_PROG'工種任意工資低的員工的:工號、姓名、job_id以及salary
SELECT employee_id,last_name,job_id,salary
FROM employees
WHERE salary < ANY(
	SELECT DISTINCT salary
	FROM employees
	WHERE job_id='IT_PROG'
) AND job_id <> 'IT_PEOG';

# 或者
SELECT employee_id,last_name,job_id,salary
FROM employees
WHERE salary<(
	SELECT MAX(salary)
	FROM employees
	WHERE job_id='IT_PROG'
) AND job_id <> 'IT_PEOG';

# 案例三、返回其他工種中比job_id爲'IT_PROG'部門所有工資都低的員工的員工號、姓名、job_id以及salary
SELECT employee_id,last_name,job_id,salary
FROM employees
WHERE salary < ALL(
	SELECT salary
	FROM employees
	WHERE job_id='IT_PROG'
) AND job_id <> 'IT_PROG';

# 3、行子查詢(多列多行)
# 案例:查詢員工編號最小並且工資最高的員工的資訊
SELECT *
FROM employees
WHERE (employee_id,salary)=(
	SELECT MIN(employee_id),MAX(salary)
	FROM employees
);

# 二、放在select後面的子查詢
/*
只支援標量子查詢
*/
# 案例:查詢每個部門的員工個數
SELECT d.*,(
	SELECT COUNT(*)
	FROM employees e
	WHERE e.department_id = d.department_id
) 個數
FROM departments d;

# 案例2:查詢員工號=102的部門名
SELECT department_name
FROM departments d
INNER JOIN employees e
ON d.`department_id`=e.`department_id`
WHERE e.`employee_id`=102;

SELECT (
	SELECT department_name
	FROM departments d
	WHERE e.`department_id`=d.department_id
	
) 部門名
FROM employees e
WHERE e.`employee_id`=102;


# 三、from後面
/*
將我們的子查詢結果充當一張表,這張表必須起別名

*/
# 案例:查詢每個部門的平均工資的工資等級 
# ①查詢每個部門的平均工資
SELECT AVG(salary)
FROM employees
GROUP BY department_id;

# ②連線①的結果集和job_grade表,篩選條件平均工資between lowest_sal and`highest_sal`
SELECT ag_dep.*,g.`grade_level`
FROM (
	SELECT AVG(salary) ag,department_id
	FROM employees
	GROUP BY department_id
) ag_dep
INNER JOIN job_grades g
ON ag_dep.ag BETWEEN lowest_sal AND highest_sal;



# 四、exists後面(相關子查詢)
/*
語法:
exists(完整的查詢語句)
結果:0或1

*/
SELECT EXISTS (SELECT employee_id FROM employees);

# 案例一、查詢有員工的部門名
SELECT department_name
FROM departments d
WHERE d.`department_id` IN (
	SELECT department_id
	FROM employees
);

SELECT department_name
FROM departments d
WHERE EXISTS (
	SELECT *
	FROM employees e
	WHERE d.`department_id`=e.`department_id`
);

# 案例二、查詢沒有女朋友的男神資訊
SELECT *
FROM boys bo 
WHERE bo.`id` NOT IN (
	SELECT b.`boyfriend_id`
	FROM beauty b
);

SELECT * 
FROM boys bo
WHERE NOT EXISTS (
	SELECT *
	FROM beauty b
	WHERE b.`boyfriend_id`=bo.`id`
);

3.8 分頁查詢

3.8.1 應用場景

  • 當要查詢的條目數太多,一頁顯示不全的時候使用。

3.8.2 語法

select 查詢列表
from 表
limit offset,size;

3.8.3 程式碼演示

# 進階8:分頁查詢 
/*
應用場景:當要顯示的數據,一頁顯示不全,需要分頁提交sql請求

語法:
	select 查詢列表
	from 表
	【join type join 表2
	on 連線條件
	where 篩選條件
	group by 分組欄位
	having 分組後的篩選
	order by 排序的欄位】
	limit offset,size;
	
	offset:要顯示的條目的起始索引(起始索引從0開始),當索引從0開始的時候offset可以省略
	size:要顯示的條目個數

特點:
①limit語句放在查詢語句的最後
②公式
	要顯示的頁數page,每頁的條目數size
	select 查詢列表
	from 表
	limit (page-1)*size,size;

*/
# 案例一、查詢前五條員工資訊
SELECT *
FROM employees
LIMIT 0,5;

# 案例二、查詢第11條到第25條
SELECT * FROM employees LIMIT 10,15;

# 案例三、有獎金的員工資訊,並且工資較高的前10名顯示出來
SELECT * 
FROM employees
WHERE commission_pct IS NOT NULL
ORDER BY salary DESC
LIMIT 0,10;

3.9 聯合查詢

3.9.1 含義

  • union:合併、聯合,將多次查詢的結果合併成一個結果

3.9.2 語法

查詢語句1
union 【all】
查詢語句2
union 【all】
...

3.9.3 意義

  • 將一條比較複雜的查詢語句拆分成多條語句
  • 適用於查詢多個表的時候,查詢的列是一致的

3.9.4 特點

  • 要求多條查詢語句的查詢列數必須一致
  • 要求多條查詢語句的查詢的各列型別、順序最好一致
  • union 去重,union all包含重複項
# 進階9:聯合查詢
/*
union 聯合 合併:將多條查詢語句得結果合併成一個結果

語法:
查詢語句1
union 
查詢語句2
union
...

應用場景:
當要查詢得結果來自於多個表,且多個表沒有直接得連線關係,但查詢得資訊一致時

特點:
1、要求多條查詢語句得查詢列數是一致的
2、要求多條查詢語句得查詢得每一列得型別和順序是最好一致的
3、union關鍵字預設去重,如果使用union all可以包含重複項
*/
# 引入得案例:查詢部門標號>90或郵箱中包含a得員工資訊
SELECT * 
FROM employees
WHERE department_id>90 
OR email LIKE '%a%';

SELECT * FROM employees WHERE email LIKE '%a%'
UNION 
SELECT * FROM employees WHERE department_id>90;

3.10 查詢總結

select 查詢列表  
from 表1 別名
連線型別 join 表2
on 連線條件
where 篩選
group by 分組列表
having 篩選
order by 排序列表
limit 其實條目索引,條目數;

第四章 DML語言

4.1 插入

  • 方式一
insert into 表名(欄位名...) values(值...);
  • 特點
    • 要求值的型別和欄位的型別要一致或相容
    • 欄位的個數和順序不一定與原始表中的欄位個數和順序一致,但必須保證值和欄位一一對應
    • 假如表中有可以爲null的欄位,可以通過以下兩種方式插入null值
      • 欄位和值的個數必須一致
      • 欄位寫上,值使用null
    • 欄位和值的個數必須一致
    • 欄位名可以省略,預設所有列
  • 方式二
insert into 表名 set 欄位=值,欄位=值...
  • 兩種方式的區別:
    • 方式一支援一次插入多行
    • 方式一支援子查詢
# 插入多行
insert into 表名【(欄位名...)】values(值...),(值...),...;

# 支援子查詢
insert into 表名 查詢語句;

 4.2 刪除

4.2.1 刪除單表的記錄

update 表名 set 欄位=值,欄位=值【where 篩選條件】;

4.2.2 修改多表的記錄

update 表1 別名
left|right|inner join 表2 別名
on 連線條件
set 欄位=值,欄位=值
【where 篩選條件】;

4.3 刪除

4.3.1 使用delete

  • 刪除單表記錄
delete from 表名 【where 篩選條件】【limit 條目數】;
  • 級聯刪除
delete 別名1,別名2 from 表1 別名
inner|left|right join 表2 別名
on 連線條件
【where 篩選條件】;

4.3.2 使用truncate

truncate table 表名;

4.3.3 兩種方式的區別

  • truncate刪除後,如果再插入,標識列從1開始,delete刪除後,如果再插入,標識列從斷點開始
  • delete可以新增篩選條件,truncate不可以新增篩選條件
  • truncate效率較高
  • truncate沒有返回值,delete可以返回受影響的行數
  • truncate不可以回滾

4.4 程式碼演示

# DML語言
/*
數據操作語言:
插入:insert
修改:update
刪除:delete

*/

# 一、插入語句
# 方式一、經典的插入
/*
語法:
insert into 表名(列名、...) values(值1、...);
*/

SELECT * FROM beauty;
# 1、插入得值的型別要與列的型別一致或者相容
INSERT INTO beauty(id,NAME,sex,borndate,phone,photo,boyfriend_id)
VALUES(13,'mary','女','1995-09-29','13977875663',NULL,2);

# 2、不可以爲null的列必須插入值,可以爲null的列是如何插入值得?
/*
要麼列名寫了值用null來填充,要門列名和值都不寫
*/
# 方式一、
INSERT INTO beauty(id,NAME,sex,borndate,phone,photo,boyfriend_id)
VALUES(13,'mary','女','1995-09-29','13977875663',NULL,2);

# 方式二、
INSERT INTO beauty(id,NAME,sex,borndate,phone,boyfriend_id)
VALUES(14,'Susan','女','1993-02-29','13977875663',2);

# 3、列的順序是否可以調換
INSERT INTO beauty(NAME,sex,id,phone)
VALUES('翠花','女',15,'182990233882');

# 4、列和值必須要匹配

# 5、可以省略列名,預設所有列,而且列的順序和表中列的順序是一致的
INSERT INTO beauty
VALUES(16,'鳳凰','女',NULL,'1333',NULL,NULL);

# 方式二、
/*
語法:
insert into 表名
set 列名1=值1,列明2=值2...;

*/
INSERT INTO beauty
SET id=19,NAME='大黃',phone='8888';

# 兩種方式大pk
# 方式一、支援插入多行,方式二不支援
/*
insert into beauty
values(插入的值的列表),
(插入的值的列表),
...;
*/
# 方式一支援子查詢,方式二不支援
INSERT INTO beauty(id,NAME,phone)
SELECT 26,'宋希','3280843';

# 二、修改語句
/*
1、修改單表的記錄
update 表名
set 列=新值,列=新值,....
where 篩選條件

2、修改多表的記錄

語法:
sql92語法:
update 表1 別名,表2 別名
set 列=值,...
where 連線條件
and 篩選條件;

sql99語法:
update 表1 別名
inner|left|right join 表2 別名
on 連線條件
set 列=值,...
where 篩選條件;

*/
# 1、修改單表的記錄
# 案例一、修改beuty表中的姓唐的女神的電話爲13899989234
UPDATE beauty
SET phone='13899989234'
WHERE NAME LIKE '唐%';

# 案例二、修改boys表中id爲2的男生名爲張飛,魅力值10
UPDATE boys 
SET boyName='張飛',userCP='10'
WHERE id=2;

# 2、修改多表的記錄
# 案例一、修改張無忌的女朋友的手機號爲114

UPDATE boys bo
INNER JOIN beauty b
ON bo.`id`=b.`boyfriend_id`
SET phone='114'
WHERE bo.`boyName`='張無忌';

# 案例二、修改沒有男朋友的女神的男朋友編號爲2
UPDATE beauty b
LEFT OUTER JOIN boys bo
ON b.`boyfriend_id`=bo.`id`
SET b.`boyfriend_id`=2
WHERE bo.`id` IS NULL;

# 三、刪除語句
/*
方式一:delete
語法:
1、單表的刪除
delete from 表名 where 篩選條件

2、多表的刪除
sql92語法:
delete 表1的別名,表2的別名  (這裏要刪除哪個表中的記錄就寫哪個表,都刪除就都寫)
from 表1 別名,表2 別名
where 連線條件
and 篩選條件;

sql99語法:
delete 表1的別名,表2的別名  (這裏要刪除哪個表中的記錄就寫哪個表,都刪除就都寫)
from 表1 別名
inner|left|right join 表2 別名 on 連線條件
where 篩選條件;



方式二、truncate
語法:truncate table 表名;

*/
# 案例一、 刪除手機號以9結尾的女神資訊
DELETE FROM beauty
WHERE phone LIKE '%9';

# 2、多表的刪除
# 案例一、刪除張無忌的女朋友的資訊
DELETE b
FROM boys bo
INNER JOIN beauty b
ON bo.`id`=b.`boyfriend_id`
WHERE bo.`boyName`='張無忌';

# 案例二、刪除黃曉明的資訊以及他女朋友的資訊
DELETE b,bo
FROM boys bo
INNER JOIN beauty b
ON bo.`id`=b.`boyfriend_id`
WHERE bo.`boyName`='黃曉明';

# 方式二、truncate語句
# 清空男生表
TRUNCATE TABLE boys;

# delete pk truncate
/*
1、delete 可以加where條件,truncate不能加
2、truncate刪除,效率高一點
3、假如要刪除的表中有自增長列
   如果用delete刪除後,再插入數據,自增長列的值從斷點開始
   用truncate刪除後,再插入數據,自增長列的值從1開始
4、truncate刪除沒有返回值,delete刪除有返回值
5、truncates刪除不能回滾,delete刪除可以回滾

*/

第五章 DDL語言

5.1 庫的管理

5.1.1 建立庫

create data 【if not exists】庫名【character set 字元集名】;

5.1.2 修改庫

alter database 庫名 character set 字元集名;

5.1.3 刪除庫

drop database 【if exists】庫名;

5.2 表的管理

5.2.1 建立表

create table【if not exists】表名(
    欄位名 欄位型別【列級約束】,
    欄位名 欄位型別【列級約束】,
    ...
    表級約束
);

5.2.2 修改表

  • 新增列
alter table 表名 add column 列名 型別【first|after 欄位名】;
  • 修改列的型別或約束
alter table 表名 modify column 列名 新型別【新約束】;
  • 修改列名
alter table 表名 change column 舊列名 新列名 型別;
  • 刪除列
alter table 表名 drop column 列名;
  • 修改表名
alter table 表名 rename【to】新表名;

5.2.3 刪除表

drop table【if exists】表名;

5.2.4 複製表

  • 複製表的結構
create table 表名 like 舊錶;
  • 複製表的結構和數據
create table 表名
select 查詢列表 from 舊錶【where 篩選】;

5.2.5 程式碼演示 
 

# DDL
/*

數據定義語言

庫和表的管理

一、庫的管理
建立、修改、刪除

二、表的管理
建立、修改、刪除

建立:create
修改:alter
刪除:drop
*/

# 一、庫的管理
# 1、庫的建立
/*
語法:create database [if not exists] 庫名;

中間的可選欄位是一種容錯性的處理,表示如果庫存在就不再建立了
*/
# 案例一:建立庫Books
CREATE DATABASE books;

# 2、庫的修改
# 更改庫的字元集
ALTER DATABASE books CHARACTER SET gbk;

# 3、庫的刪除
# if exists 和上面一樣是一種容錯處理,表示如果數據庫不存在就不做處理
DROP DATABASE IF EXISTS books;


# 二、表的管理
# 1、表的建立
/*
create table 表名(
	列名 列的型別【長度】【約束】,
	列名 列的型別【長度】【約束】,
	列名 列的型別【長度】【約束】,
	...
	列名 列的型別【長度】【約束】
)

*/
# 案例:建立表Books
CREATE TABLE books(
	id INT,  # 編號
	bname VARCHAR(20),  # 書名
	price DOUBLE,  # 價格
	authorId INT,  # 作者編號,
	publishDate DATETIME  # 出版日期
	
); 

DESC books;

# 案例:建立表author
CREATE TABLE IF NOT EXISTS author(
	id INT,
	au_name VARCHAR(20),
	nation VARCHAR(10)
);
DESC author;

# 2、表的修改
/*
語法:
alter table 表名 add|drop|modify|change column 列名 【列型別 約束】;

*/
# ①修改列名
ALTER TABLE books CHANGE COLUMN publishdate pubDate DATETIME;


# ②修改列的型別或約束
ALTER TABLE books MODIFY COLUMN pubdate TIMESTAMP;

# ③新增列
ALTER TABLE author ADD COLUMN annual DOUBLE;

# ④刪除列
ALTER TABLE author DROP COLUMN annual;

# ⑤修改表名
ALTER TABLE author RENAME TO book_author;

# 3、表的刪除
/*
drop table 【if exists】 表名;
*/
DROP TABLE IF EXISTS book_author;
SHOW TABLES;


# 通用的寫法
DROP DATABASE IF EXISTS 舊庫名;
CREATE DATABASE 新庫名;

DROP TABLE IF EXISTS 舊錶名;
CREATE TABLE 表名();


# 4、表的複製
# 僅僅複製表的結構
/*
create table 新表名 like 要複製的表的名字;
*/

# 複製表的結構+數據
/*
create table 新表名 select * from 要複製的表的名字;
*/

# 只複製部分數據
/*
create table 新表名 select 列名1,列名2...
from 要複製的表的名字
where 篩選條件
*/

# 僅僅複製某些欄位
/*
create table 新表明
select 列名1,列名2...
from 要複製的表的名字
where 不可能成立的條件(如:1=2,0等)
*/

5.3 數值型別

5.3.1 整型

  • 分類
    • tinyint
    • smallint
    • mediumint
    • int/integer
    • bigint
  • 特點
    • 都可以設定無符號和有符號,預設爲有符號,通過unsigned設定無符號
    • 如果超出了範圍,會報out or range異常,插入臨界值
    • 長度可以不指定,預設會有一個長度,長度代表顯示的最大寬度,如果不夠則左邊用0填充,但需要搭配zerofill,並且預設變爲無符號整型

5.3.2 小數

  • 定點數
    • decimal(M,D)
  • 浮點數
    • float(M,D)
    • double(M,D)
  • 特點
    • M代表整數部位+小數部位的個數,D代表小數部位
    • 如果超出範圍,則報out or range異常,並且插入臨界值
    • M和D都可以省略,但對於定點數來說,M預設爲10,D預設爲0
    • 如果精度要求較高,則優先使用定點數

5.3.3 字元型

  • 分類
    • char:固定長度的字元,寫法爲char(M),最大長度不能超過M,其中M可以省略預設爲1
    • varchar:可變長度的字元,寫法爲varchar(M),最大長度不能超過M,其中M不可以省略
    • binary
    • varbinary
    • enum
    • set
    • text
    • blob

5.3.4 日期型

  • year:年
  • date:日期
  • time:時間
  • datetime:時間+日期
  • timestamp:時間+日期

5.3.5 程式碼演示

# 常見的數據型別
/*
數值型:
	整型
	小數
		定點數
		浮點數
字元型:
	較短的文字:char、varchar
	較長的文字:text、blob(較長的二進制數據)

日期型
*/

# 一、整型
/*
分類
tinyint、smallint、mediumint、int/integer、bight
1	 2	   3	      4		   5


特點:
① 如果不設定無符號還是有符號,預設是有符號,如果想設定無符號,需要新增unsigned關鍵字
②如果插入的數值超過了整型的範圍,會報out of range異常,並且插入臨界值
③如果不設定長度,會有預設長度
長度代表了顯示的最大寬度,如果不夠會用0在左邊填充,但必須搭配zerofill來使用
*/
# 案例一、如何設定無符號和有符號
CREATE TABLE tab_int (
	t1 INT, # 有符號
	t2 INT UNSIGNED,  # 無符號
	t3 INT ZEROFILL  # 使用0填充,預設爲無符號
);

# 小數
/*
分類:
1、浮點型
float(M, D)
double(M, D)

2、定點型
dec(M, D)
deciaml(M, D)

特點:
①
M:整數部位長度+小數部位長度
D:小數部位長度
如果超過範圍,則插入臨界值

② M和D都可以省略
如果是deciaml,則M預設爲10,D預設爲0
如果是float和double,則會根據插入的數值的精度來決定精度

③定點型的精度較高,如果要求插入數值的精度較高如貨幣運算等則考慮使用
*/

CREATE TABLE tab_float (
	f1 FLOAT(5, 2),
	f2 DOUBLE(5, 2),
	f3 DECIMAL(5, 2)

);

# 原則
/*
所選擇的型別越簡單越好,能儲存數值的型別越小越好
*/

# 三、字元型
/*
較短的文字:
		寫法		M的意思				特點			空間的耗費	效率
char		char(M)		最大的字元數,可以省略預設爲1	固定長度的字元		比較耗費	高
varchar		varchar(M)	最大的字元數,不可以省略	可變長度的字元		比較節省	低

binary和varbinary用於儲存較短的二進制
enum用於儲存列舉
set用於儲存集合

*/

# 四、日期型
/*
分類:
date:只儲存日期
time:只儲存時間
year:只儲存年

datetime:儲存日期+時間
timestamp:儲存日期+時間

特點:
		位元組		範圍		時區等影響
datetime	8		1000-9999	不受
timestamp	4		1970-2038	受

*/
CREATE TABLE tab_date (
	t1 DATETIME,
	t2 TIMESTAMP
);

INSERT INTO tab_date VALUES(NOW(),NOW());
SELECT * FROM tab_date;

5.4 約束

5.4.1 常見的約束

  • NOT NULL:非空,該欄位的值必填
  • UNIQUE:唯一,該欄位的值不可重複
  • DEFAULT:預設,該欄位的值有一個預設值
  • CHECK:檢查,mysql不支援
  • PRIMARY KEY:主鍵,該欄位的值不可重複並且非空
  • FOREIGN KEY:外來鍵,該欄位的值參照了另外的表的欄位

5.4.2 主鍵和唯一比較

  • 區別
    • 一個表至多有一個主鍵,但可以有多個唯一
    • 主鍵不允許爲空,唯一可以爲空
  • 相同點
    • 都具有唯一性
    • 都支援組合鍵,但不推薦

5.4.3 外來鍵

  • 特點
    • 用於限制兩個表的關係,從表的欄位值參照了主表的某欄位值
    • 外來鍵列和主表的被參照列要求型別一致,意義一樣,名稱無要求
    • 主表的被參照列要求是一個key(一般爲主鍵)
    • 插入數據,先插入主表,刪除數據,先刪除從表
  • 兩種刪除主表記錄的方式
alter table 從表名 add constraint 外來鍵名 foreign key(從表欄位名) references 主表(主表欄位名) on delete cascade;
alter table 從表名 add constraint 外來鍵名 foreign key(從表欄位名) references 主表(主表欄位名) on delete set null;

5.4.4 建立表的時候新增約束

create table 表名(
    欄位名 欄位型別 列級約束,
    欄位名 欄位型別 列級約束,
    欄位名 欄位型別 列級約束,
    ...
    表級約束,
    ...
);
列級約束和表級約束對比
  支援型別 約束名
列級約束 除了外來鍵 不可以起約束名
表級約束 除了非空和預設 可以起約束名,但對主鍵無效

5.4.5 修改表時新增或刪除約束

  • 非空
# 新增非空
alter table 表名 modify column 欄位名 欄位型別 not null;

# 刪除非空
alter table 表名 modify column 欄位名 欄位型別;
  • 預設
# 新增預設
alter table 表名 modify column 欄位名 欄位型別 default 值;
# 刪除預設
alter table 表名 modify column 欄位名 欄位型別;
  • 主鍵
# 新增主鍵
alter table 表名 add【constriaint 約束名】primary key(欄位名);

# 刪除主鍵
alter table 表名 drop primary key;
  • 唯一
# 新增唯一
alter table 表名 add【constraint 約束名】unique(欄位名);

# 刪除唯一
alter table 表名 drop foreign key 約束名;
  • 外來鍵
# 新增外來鍵
alter table 表名 add【constraint 約束名】foreign key(欄位名) references 主表(被參照的欄位名);

# 刪除外來鍵
alter table 表名 drop foreign key 約束名;

5.4.6 程式碼演示

# 常見約束
/*
含義:一種限制,用於限製表中的數據,爲了保證表中的數據的準確性和可靠性

分類:六大約束
	NOT NULL 非空,用於保證該欄位的值不能爲空
	比如姓名、學號等
	DEFAULT:預設,用於保證該欄位有預設值
	比如性別
	PRIMARY KEY:主鍵,用於保證該欄位的值具有唯一性,可以非空
	比如學號、員工編號等
	UNIQUE:唯一,用於保證該欄位的值具有唯一性,可以爲空
	比如座位號
	CHECK:檢查約束【mysql中不支援】
	比如年齡、性別
	FOREING KEY:外來鍵,用於限制兩個表的關係,用於保證該欄位的值必須來自主表的關聯列的值
			   在從表新增外來鍵約束,用於參照主表中某列的值
	比如學生表的專業編號,員工表的部門編號,員工表的工種編號

新增約束的時機:
	1、建立表時
	2、修改表時

約束的新增分類:
	列級約束
		六大約束語法上都支援,但外來鍵約束沒有效果
	表級約束
		除了非空、預設,其他的都支援

create table 表名 (
	欄位名 欄位型別 【列級約束】 【列級約束】 【列級約束】,
	欄位名 欄位型別 【列級約束】 【列級約束】 【列級約束】,
	表級約束
)

主鍵和唯一的大對比:
		保證唯一	是否允許爲空	一個表中可以有多少個	是否允許組合
	主鍵	是		錯		至多有一個		是,但不推薦
	唯一	是		對		可以有多個		是,但不推薦
	

外來鍵:
	1、要求在從表設定外來鍵
	2、從表的外來鍵列的型別和主表的關聯列的型別要求一致或相容,名稱無要求
	3、主表的關聯列必須是一個key(一般是主鍵或唯一)
	4、插入數據的時,先插入主表,再插入從表
	5、刪除數據時,先刪除從表,再刪除主表

*/ 


CREATE DATABASE students;
USE students;
# 一、建立表時新增約束
# 1、新增列級約束
/*
語法:
	直接在欄位名和型別名後面追加,約束型別即可。
	只支援:預設、非空、主鍵、唯一

*/

CREATE TABLE stuinfo (
	id INT PRIMARY KEY,  # 主鍵
	stuName VARCHAR(20) NOT NULL,  # 非空
	gender CHAR(1) CHECK (gender='男' OR gender='女'),  # 檢查約束
	seat INT UNIQUE,  # 唯一
	age INT DEFAULT 18,  # 預設約束
	majorId INT REFERENCES major(id)  # 外來鍵
);

DESC stuinfo;

CREATE TABLE major(
	id INT PRIMARY KEY,
	majorName VARCHAR(20)
);

# 檢視stuinfo表中所有的索引,包括主鍵、外來鍵、唯一
SHOW INDEX FROM stuinfo;


# 2、新增表級約束
/*
語法:在各個欄位的最下面 下麪
【constraint 約束名】 約束型別(欄位名)
*/
DROP TABLES IF EXISTS stuinfo;

CREATE TABLE stuinfo (
	id INT,
	stuname VARCHAR(20),
	gender CHAR(1),
	seat INT,
	age INT,
	majorid INT,
	CONSTRAINT pk PRIMARY KEY(id),  # 主鍵
	CONSTRAINT uq UNIQUE(seat),  # 唯一鍵
	CONSTRAINT ck CHECK(gender='男' OR gender='女'),  # 檢查
	CONSTRAINT fk_stuinfo_major FOREIGN KEY(majorid) REFERENCES major(id)  # 外來鍵
);

SHOW INDEX FROM stuinfo;

/*
通用的寫法
CREATE TABLE stuinfo (
	id INT PRIMARY KEY,  # 主鍵
	stuName VARCHAR(20) NOT NULL,  # 非空
	gender CHAR(1),
	seat INT UNIQUE,  # 唯一
	age INT DEFAULT 18,  # 預設約束
	majorId INT,
	CONSTRAINT fk_stu_major FOREIGN KEY(majorid) REFERENCES major(id)
);


*/


# 二、修改表時新增約束
/*
1、新增列級約束
alter table 表名 modify column 欄位名 欄位型別 新約束;

2、新增表級約束
alter table 表名 add 【constraint 約束名】 約束型別(欄位名) 【外來鍵的參照】;
*/

DROP TABLES IF EXISTS stuinfo;

CREATE TABLE stuinfo (
	id INT,
	stuname VARCHAR(20),
	gender CHAR(1),
	seat INT,
	age INT,
	majorid INT
);
DESC stuinfo;
# 1、新增非空約束
ALTER TABLE stuinfo MODIFY COLUMN stuname VARCHAR(20) NOT NULL;

# 2、新增預設約束
ALTER TABLE stuinfo MODIFY COLUMN age INT DEFAULT 18;

# 3、新增主鍵
# 列級約束
ALTER TABLE stuinfo MODIFY COLUMN id INT PRIMARY KEY;
# 表級約束
ALTER TABLE stuinfo ADD PRIMARY KEY(id);

# 新增唯一
# 列級約束
ALTER TABLE stuinfo MODIFY COLUMN seat INT UNIQUE;
# 表級約束
ALTER TABLE stuinfo ADD UNIQUE(seat);

# 5、新增外來鍵
ALTER TABLE stuinfo ADD CONSTRAINT fk_stuinfo_major FOREIGN KEY(majorid) REFERENCES major(id);

# 三、修改表時刪除約束
# 1、刪除非空約束
ALTER TABLE stuinfo MODIFY COLUMN stuname VARCHAR(20) NULL;

# 2、刪除預設約束
ALTER TABLE stuinfo MODIFY COLUMN age INT;

# 3、刪除主鍵
ALTER TABLE stuinfo MODIFY COLUMN id INT;
或
ALTER TABLE stuinfo DROP PRIMARY KEY;

# 4、刪除唯一
ALTER TABLE stuinfo DROP INDEX seat;

# 刪除外來鍵
ALTER TABLE stuinfo DROP FOREIGN KEY fk_stuinfo_major;

5.5 自增長列

5.5.1 自增長列的特點

  • 不用手動插入值,可以自動提供序列值,預設從1開始,步長爲1
    • auto_increment
    • 如果要更改起始值,手動插入即可
    • 吐過要更改步長:更改系統變數
      • set auto_increment=值
  • 一個表至多有一個自增長列
  • 自增長列只能支援數值型
  • 自增長列必須爲一個key

5.5.2 相關語法

  • 建立表時設定自增長列
create table 表(
    欄位名 欄位型別 約束 auto_increment
);
  • 修改表時設定自增長列
alter table 表 modify column 欄位名 欄位型別 約束 auto_increment;
  • 刪除自增長列
alter table 表 modify column 欄位名 欄位型別 約束;

5.5.3 程式碼演示

# 標識列
/*
又稱爲自增長列
含義:可以不用手動的插入值,系統提供預設的序列值

特點:
	1、標識列必須和主鍵搭配嗎?不一定,但要求是一個key
	2、一個表中可以有多少個標識列?至多一個
	3、標識列的型別只能是數值型
	4、標識列可以通過:SET AUTO_INCREMENT=3;設定步長
		可以通過手動插入值,設定起始值

*/
# 一、建立表時設定標識列
DROP TABLE IF EXISTS tab_identity;
CREATE TABLE tab_identity(
	id INT,
	NAME VARCHAR(20)

);
INSERT INTO tab_identity VALUES(NULL,'john');
INSERT INTO tab_identity(NAME) VALUES('jhon');

SET AUTO_INCREMENT=3;

# 二、修改表時設定標識列
ALTER TABLE tab_identity MODIFY COLUMN id INT PRIMARY KEY AUTO_INCREMENT;

# 三、修改表的時候刪除標識列
ALTER TABLE tab_identity MODIFY COLUMN id INT;

第六章 TCL語言

6.1 事務

6.1.1 含義

  • 事務:一條或多條sql語句組成一個執行單位,一組sql語句要麼都執行要麼都不執行

6.1.2 特點

  • 原子性:一個事務是不可再分割的整體,要麼都執行要麼都不執行
  • 一致性:一個事務可以使數據從一個一致狀態切換到另一個一致狀態
  • 隔離性:一個事務不受其他事務的幹擾,多個事務相互隔離的
  • 永續性:一個事務一旦提交了,則永久的持久化到本地

6.1.3 事務的使用步驟

  • 事務的分類
    • 隱式事務:沒有明顯的開啓和結束,本身就是一條事務可以自動提交,比如insert、update、delete
    • 顯式事務:具有明顯的開啓和結束
  • 使用顯示事務
# 開啓事務
set autocommit=0;
start transaction;

# 編寫一組邏輯sql語句,sql語句支援insert、update、delete
# 設定回滾點
savepoint 回滾點名;

# 結束事務
commit; # 提交
# 或
rollback; # 回滾
# 或
rollback to 回滾點名;  # 回滾到指定回滾點
  • 併發事務
    • 發生的原因
      • 多個事務同時操作同一個數據庫的相同數據時
    • 存在的問題
      • 贓讀:一個事務讀取了其他事務還沒有提交的數據,讀到的是其他事務"更新"的數據
      • 不可重複讀:一個事務多次讀取結果不一樣
      • 幻讀:一個事務讀取了其他事務還沒有提交的數據,只是讀到的是其他事務「插入」的數據
    • 如何解決
      • 可以通過設定隔離級別來解決併發問題
    • 隔離級別分類
隔離級別的分類
  髒讀 不可重複讀 幻讀
read uncommitted:讀未提交 不能隔離 不能隔離 不能隔離
read committed:讀已提交 能隔離 不能隔離 不能隔離
repeatable read:可重複讀 能隔離 能隔離 不能隔離
serializable:序列化 能隔離 能隔離 能隔離

6.1.4 程式碼演示

# TCL
/*
Transaction Control Language:事務控制語言

事務:
	一個或一組aql語句組成一個執行單元,這個執行單元要麼全部執行,要麼全部不執行

事物的ACID屬性:
	1、原子性:指事務是一個不可分割的工作單位,事務中的操作要麼都發生,要麼都不發生。
	2、一致性:事務必須使數據庫從一個一致性狀態變換到另一個一致性狀態。
	3、隔離性:事務的隔離性是指一個事務的執行不能被其他事務幹擾,即一個事務內部的操作及
		使用的數據對併發的其他事務是隔離的,併發執行的各個事務之間不能相互幹擾。
	4、永續性:永續性是指一個事務一旦被提交,它對數據庫中數據的改變就是永久性的,接下來
		的其他操作和數據庫故障不應該對其有任何影響
	

事務的建立:
	隱式事務:事務沒有明顯的開啓和結束的標記
		比如:inseert、update、delete語句
	顯示事務:事務具有明顯的開啓和結束標記
		前提:必須先設定自動提交功能爲禁用



步驟:
	1、開啓事務
		set autocommit=0;
		start transaction; 可選的
	2、編寫事務中的sql語句(select、insert、update、delete)
		語句1;
		語句2;
		...
	3、結束事務
		commit; 提交事務
		rollback; 回滾事務
		
savepoint 節點名; 設定儲存點
		

		
事務的隔離級別:
			髒讀		不可重複讀	幻讀
read uncommitted	會出現		會出現		會出現
read committed		不會出現	會出現		會出現
repeatable read		不會出現	不會出現	會出現
serializable		不會出現	不會出現	不會出現
mysql中預設 第三個隔離級別 repeatable read
oracle中預設第二個隔離級別 read committed



在Mysql中設定隔離級別:
	1、每啓動一個mysql程式就會獲得一個單獨的數據庫連線每個數據庫連線都有一個全域性變數
	@@tx_isolation,表示當前的事務隔離級別
	
	2、檢視當前事務隔離級別:SELECT@@tx_isolation
	3、設定當前mysql連線的隔離級別
		set transaction isolation level read committed;
	4、設定數據系統的全域性隔離級別
		set global transaction isolation level read committed;
		
 

*/
SHOW ENGINES;

DROP TABLE IF EXISTS account;
CREATE TABLE account (
	id INT PRIMARY KEY AUTO_INCREMENT,
	username VARCHAR(20),
	balance DOUBLE
);
INSERT INTO account(username,balance)
VALUES('張無忌',1000),('趙敏',1000);


# 演示事務的過程
# 開啓事務
SET autocommit=0;
START TRANSACTION;
# 編寫一組事務的語句
UPDATE account SET balance=500 WHERE username='張無忌';
UPDATE account SET balance=1500 WHERE username='趙敏';

# 結束事務
# rollback;
COMMIT;

SELECT * FROM account;

# 3、演示savepoint的使用
SET autocommit=0;
START TRANSACTION;
DELETE FROM account WHERE id=1;
SAVEPOINT a;  # 設定儲存點
DELETE FROM account WHERE id=2;
ROLLBACK TO a;  # 回滾到儲存點

# delete 和truncate在事務使用時的區別

# 演示delete
SET autocommit=0;
START TRANSACTION;
DELETE FROM account;
ROLLBACK;

# 演示truncate
SET autocommit=0;
START TRANSACTION;
TRUNCATE TABLE account;
ROLLBACK;

第七章 其他

7.1 檢視

7.1.1 含義

  • 檢視:其本身是一個虛擬表,它的數據來自於表,通過執行時動態生成。
  • 好處
    • 簡化了sql語句
    • 提高了sql的重用性
    • 保護基表的數據,提高了安全性

7.1.2 建立

create view 檢視名
as
查詢語句;

7.1.3 修改

  • 方式一
create or replace view 檢視名
as
查詢語句;
  • 方式二
alter view 檢視名
as
查詢語句;

7.1.4 刪除

drop view 檢視1,檢視2...;

7.1.5 檢視

desc 檢視名;
show create view 檢視名;

7.1.6 檢視的使用

  • 分類
    • 插入:insert
    • 修改:update
    • 刪除:delete
    • 檢視:select
  • 注意:檢視一般是用於查詢的,而不是更新,所以具備以下特點的檢視都不允許更新
    • 包含分組函數:group by、distinct、having、union
    • join
    • 常數檢視
    • where後的子查詢用到了from中的表
    • 用到了不可更新的檢視

7.1.7 檢視和表的對比

  關鍵字 是否佔用物理空間 使用
檢視 view 佔用較小,只儲存sql邏輯 一般用於查詢
table 儲存實際的數據 增刪改查

7.1.8 程式碼演示

# 檢視
/*
含義:虛擬表,和普通表一樣使用
mysql5.1 版本出現的新特性,是通過表動態生成的

# 應用場景
	多個地方用到同樣的查詢結果
	該查詢結果使用的sql語句較複雜
	
試圖的好處:
	1、實現了sql語句重用
	2、簡化了複雜的sql操作,不必知道它的查詢細節
	3、保護數據,提高安全性

	建立語法的關鍵字	是否實際佔用物理空間	使用
檢視	create view		只是儲存了sql邏輯	增刪改查,只是一般不能增刪改
表	create table		儲存了數據		增刪改查

*/
USE myemployees;
# 一、建立檢視
/*
create view 檢視名
as
查詢語句;

*/
# 案例一、查詢郵箱中包含a字元的員工名,部門名和工種資訊
# ①建立
CREATE VIEW sa
AS
SELECT last_name,department_name,j.titile
FROM employees e
INNER JOIN departments d
ON e.department_id=d.department_id
INNER JOIN jobs j
ON e.job_id=j.job_id;

# 使用
SELECT * FROM sa WHERE last_name LIKE '%a%';

#2、查詢各部門的平均工資級別
CREATE VIEW ag_sal
AS
SELECT AVG(salary) dep_avg,department_id
FROM employees e
GROUP BY department_id;

SELECT * FROM ag_sal;

SELECT department_id,grade_level
FROM ag_sal
INNER JOIN job_grades j
ON dep_avg BETWEEN j.`lowest_sal` AND j.`highest_sal`;

# 查詢平均工資最低的部門資訊
SELECT d.*
FROM ag_sal
INNER JOIN departments d
ON ag_sal.`department_id`=d.`department_id`
WHERE ag_sal.`dep_avg` = (
	SELECT MIN(dep_avg)
	FROM ag_sal
);
 

# 二、檢視的修改
# 方式一
/*
select * from myv3
*/
CREATE OR REPLACE VIEW myv3
AS
SELECT AVG(Salary),job_id
FROM employees
GROUP BY job_id;

# 方式二
/*
語法:
alter view 檢視名
as
查詢語句;
*/
ALTER VIEW myv3
AS
SELECT * FROM employees;


# 三、刪除檢視
/*
語法:drop view 檢視名,檢視名,...;
*/
DROP VIEW myv3;

# 四、檢視檢視
DESC sa;
SHOW CREATE VIEW sa;

# 五、檢視的更新
CREATE OR REPLACE VIEW myv1
AS
SELECT last_name,email
FROM employees;

SELECT * FROM myv1;
# 1、插入
INSERT INTO myv1 VALUES('張飛','[email protected]');

# 修改
UPDATE myv1 SET last_name='張無忌' WHERE Last_name='張飛';

# 刪除
DELETE FROM myv1 WHERE Last_name='張無忌';

# 具備以下特點的檢視是不能更新的
/*
包含以下關鍵字的SQL語句:分組函數、DITINCT、GROUP BY、HAVING、UNION或者UNION ALL
常數檢視
select中包含子查詢
join
from一個不能更新的檢視
where子句的子查詢參照了from子句中的表
*/

# delete 和truncate在事務使用時的區別

7.2 變數

7.2.1 系統變數

  • 說明:變數由系統提供的,不用自定義
  • 分類:
    • 全域性變數:伺服器層面上的,必須擁有super許可權才能 纔能爲系統變數賦值,作用域爲整個伺服器,也就是針對於所有連線(對談)有效
    • 對談變數:伺服器爲每一個連線的用戶端都提供了系統變數,作用域爲當前的連線(對談)
  • 檢視系統變數:如果沒有顯式宣告global還是session,則預設是session
show【global|session】variables like ‘’;
  • 檢視指定的系統變數的值:如果沒有顯式宣告global還是session,則預設是session
select @@[global|session].變數名;
  • 爲系統變數賦值:如果沒有顯式宣告global還是session,則預設是session
set 【global|session】變數名=值;
set @@global.變數名=值;
set @@變數名=值;

7.2.2 自定義變數

  • 使用者變數
    • 作用域:針對當前連線(對談)生效
    • 位置:begin end 裏面或者外面都可以
    • 使用
# 宣告並賦值,三種方式
set @變數名=值;
set @變數名:=值;
select @變數名:=值;

# 更新值,兩種方式
# 方式一,三種方式
set @變數名=值;
set @變數名:=值;
select @變數名:=值;

# 方式二
select xx into @變數名 from 表;

# 使用
select @變數名;

7.2.3 區域性變數

  • 作用域:僅僅在定義它的begin end 中有效
  • 位置:只能放在begin end中,而且只能放在第一句
  • 使用
# 宣告
declare 變數名 型別【default 值】;

# 賦值或更新,兩種方式
# 方式一
set 變數名=值;
set 變數名:=值;
select @變數名:=值

# 方式二
select xx into 變數名 from 表;

# 使用
select 變數名;

7.2.4 程式碼演示

# 變數
/*
系統變數
	全域性變數
	對談變數

自定義變數
	使用者變數
	區域性變數

*/

# 一、系統變數
/*
說明:變數由系統提供,不是使用者定義,屬於伺服器層面
使用的語法:
1、檢視所有的系統變數
SHOW GLOBAL|SESSION VARIABLES;

2、檢視滿足條件的部分系統變數
show global|session variables like '%char%';

3、檢視指定的某個系統變數的值
select @@global|@@session.系統變數名;

4、爲某個系統變數賦值
方式一
set global|session 系統變數名=值;
方式二
set @@global|@@session.系統變數名=值;

注意:
如果是全域性級別,則需要加global,如果是對談級別,則需要加session,如果什麼都不寫預設session

*/
# 1、全域性變數
/*
作用域:伺服器每次啓動將爲所有的全域性變數賦初始值,針對於所有的對談(連線)有效,但不能跨重新啓動

*/
# ①檢視所有的全域性變數
SHOW GLOBAL VARIABLES;

# ②檢視部分的全域性變數
SHOW GLOBAL VARIABLES LIKE '%char%';

# ③檢視指定的全域性變數的值
SELECT @@global.autocommit;
SELECT @@tx_isolation;

# ④爲某個指定的全域性變數賦值
SET @@global.autocommit=0;



# 2、對談變數
/*
作用域:僅僅針對於當前的對談(連線)有效
*/
# ①檢視所有的對談變數
SHOW VARIABLES;
SHOW SESSION VARIABLES;

# ②檢視部分的對談變數
SHOW VARIABLES LIKE '%char%';
SHOW SESSION VARIABLES LIKE '%char%';

# ③檢視指定的某個對談變數
SELECT @@tx_isolation;
SELECT @@session.tx_isolation;

# ④爲某個對談變數賦值
# 方式一
SET @@session.tx_isolation='read-uncommitted';
# 方式二
SET SESSION tx_isolation='read-committed';


# 二、自定義變數
/*
說明:變數是使用者自定義的,不是由系統提供的

使用步驟:
宣告
賦值
使用(檢視、比較、運算等)

*/ 
# 1、使用者變數
/*
作用域:針對於當前對談(連線)有效,同於對談變數的作用域
應用在任何地方,也就是begain end裏面或者begain end外面

*/

賦值的操作符:=或:=
# ①宣告並初始化
SET @使用者變數名=值;
SET @使用者變數名:=值;
SELECT @使用者變數名:=值;

# ②賦值(更新使用者變數的值)
方式一、通過SET或SELECT
	SET @使用者變數名=值;
	SET @使用者變數名:=值;
	SELECT @使用者變數名:=值;
方式二、通過SELECT INTO
	SELECT 欄位 INTO @變數名
	FROM 表;
	

# ③使用(檢視使用者變數的值)
SELECT @使用者變數名;

# 案例
SET @name='john';
SET @name=100;

SELECT COUNT(*) INTO @count
FROM employees;
SELECT @count;

# 2、區域性變數
/*
作用域:僅僅在定義它的begin end中有效
應用位置:
	應用在begin end中的第一句話

*/
# ①宣告
DECLARE 變數名 型別;
DECLARE 變數名 型別 DEFAULT 值;

# ②賦值
方式一、通過SET或SELECT
	SET 區域性變數名=值;
	SET 區域性變數名:=值;
	SELECT @區域性變數名:=值;
方式二、通過SELECT INTO
	SELECT 欄位 INTO 區域性變數名
	FROM 表;

# ③使用
SELECT 區域性變數名;


/*
對比使用者變數和區域性變數
		作用域		定義和使用的位置			語法
使用者變數	當前對談	對談中的任何地方			必須加@符號,不用限定型別
		
區域性變數	degin end中	只能在degin end中,且爲第一句話		一般不用加@符號,需要限定型別


*/

# 案例:宣告兩個變數並賦初始值,求和,並列印

# 1、使用者變數
SET @m=1;
SET @n=2;
SET @sum = @m + @n;
SELECT @sum;


@ 2、區域性變數
# 下面 下麪不對
DECLARE m INT DEFAULT 1;
DECLARE n INT DEFAULT 2;
DECLARE SUM INT;
SET SUM=m+n;
SELECT SUM;

7.3儲存過程和函數

  • 都類似於java中的方法,將一組完成特定功能的邏輯語句包裝起來,對外暴露名字
  • 好處
    • 提高重用性
    • sql語句簡單
    • 減少了和數據庫伺服器連線的次數,提高了效率

7.3.1 儲存過程

  • 建立
create procedure 儲存過程名(參數模式 參數名 參數型別)
begin
    儲存過程體
end
  • 注意
    • 參數模式:in、out、inout,其中in可以省略
    • 儲存過程體的每一條語句都要以分號結尾
    • 可以使用:DELIMITER來指定其他的語句的結束標誌符
  • 呼叫
call 儲存過程名(實參列表);
  • 刪除
drop procedure 儲存過程名;
  • 程式碼演示
# 儲存過程和函數
/*
儲存過程和函數:類似於java中的方法
好處:
	1、提高程式碼的重用性
	2、簡化操作
*/

# 儲存過程
/*
含義:一組預先編譯好的SQL語句的集合,理解成爲批次處理語句
1、提高程式碼的重用性
2、簡化操作
3、減少了編譯次數並且減少了和數據庫伺服器的連線次數,提高了效率


*/
# 一、建立語法
CREATE PROCEDURE 儲存過程名(參數列表)
BEGIN
	儲存過程體(一組合法有效的SQL語句)
END

注意:
1、參數列表包含三部分
參數模式 參數名 參數型別
舉例:
IN stuname VARCHAR(20)
參數模式:
IN:該參數可以作爲輸入,也就是說該參數需要呼叫方傳入值
OUT:該參數可以作爲輸出、也就是該參數可以作爲返回值
INOUT:該參數既可以作爲輸入又可以作爲輸出,也就是該參數既需要傳入值,又可以返回值

2、如果儲存過程體僅僅只有一句話,BEGIN END可以省略
儲存過程體中的每條SQL語句的結尾要求必須加分號。
儲存過程的結尾可以使用DELIMITER重新設定
語法:
DELIMITER 結束標記

# 二、呼叫語法
CALL 儲存過程名(實參列表);

#1、空參列表
# 案例:插入到admin表中的五條記錄
DELIMITER $
CREATE PROCEDURE myp1()
BEGIN
	INSERT INTO admin(username,`password`) 
	VALUES('john1','0000'),('lily','0000'),('rom','0000'),('jack','0000'),('tom','0000');
END $

# 呼叫
CALL myp1()$

# 2、建立帶in模式參數的儲存過程
# 案例一、建立儲存過程實現:根據女神名,查詢對應的男生資訊
CREATE PROCEDURE myp2(IN beautyName VARCHAR(20))
BEGIN
	SELECT bo.*
	FROM boys bo
	RIGHT JOIN beauty b ON bo.id = b.boyfriend_id
	WHERE b.name=beautyName;
END $

# 呼叫
CALL myp2('柳岩')$


# 案例二、建立儲存過程實現,使用者是否登錄成功
CREATE PROCEDURE myp4(IN username VARCHAR(20), IN PASSWORD VARCHAR(20))
BEGIN
	DECLARE result INT DEFAULT 0;  # 宣告變數並初始化
	SELECT COUNT(*) INTO result
	FROM admin
	WHERE admin.`username`=username
	AND admin.`password`=PASSWORD;
	
	SELECT IF(result>0,'成功','失敗');  # 使用
END $

# 呼叫
CALL myp4('張飛','8888')$


# 3、建立帶out模式的儲存過程

# 案例一、根據女神名,返回對應的男神名
CREATE PROCEDURE myp5(IN beautyName VARCHAR(20),OUT boyName VARCHAR(20))
BEGIN
	SELECT bo.boyName INTO boyName
	FROM beauty b
	INNER JOIN boys bo
	ON b.boyfriend_id = bo.id
	WHERE b.name=beautyName;

END $

# 呼叫
SET @bname$
CALL myp5('小昭',@bname)$
SELECT @bname$


# 案例二、根據女神名,返回對應的男神名和男神魅力值
CREATE PROCEDURE myp6(IN beautyName VARCHAR(20),OUT boyName VARCHAR(20),OUT userCP INT)
BEGIN
	SELECT bo.boyName,bo.userCP INTO boyName,userCP
	FROM beauty b
	INNER JOIN boys bo
	ON b.boyfriend_id = bo.id
	WHERE b.name=beautyName;
END $

# 呼叫
CALL myp6('柳岩',@name,@usercp)$
SELECT @name,@usercp$ 


# 4、建立帶inout模式參數的儲存過程
# 案例一、傳入a和b兩個值,最終a和b都翻倍並返回
CREATE PROCEDURE myp8(INOUT a INT,INOUT b INT)
BEGIN
	SET a=a*2;
	SET b=b*2;
END $

# 呼叫
SET @m=10$
SET @n=20$
CALL myp8(@m,@n)$
SELECT @m,@n$


# 二、儲存過程的刪除
/*
語法:drop procedure 儲存過程名;
*/
DROP PROCEDURE myp1;

# 三、檢視儲存過程的資訊
/*
show create procedure 儲存過程名;
*/

7.3.2 函數

  • 建立
create function 函數名(參數名 參數型別) returns 返回型別
begin
    函數體
end
  • 注意:函數體中肯定需要有return語句
  • 呼叫
select 函數名(實參列表);
  • 檢視
show create function 函數名;
  • 刪除
drop function 函數名;
  • 程式碼演示

# 函數
/*
含義:一組預先編譯好的SQL語句的集合,理解成批次處理語句
好處:
	1、提高程式碼的重用性
	2、簡化操作
	3、減少了編譯次數並且減少了和數據庫伺服器的連線次數
	
區別:
儲存過程:可以有0個返回,也可以有多個返回,適合做批次插入,批次更新
函數:有且僅有1個返回,適合做處理數據後返回一個結果

*/
# 一、建立語法
CREATE FUNCTION 函數名(參數列表) RETURNS 返回型別
BEGIN
	函數體
END
/*
注意:
參數列表 包含兩部分
參數名 參數型別

函數體:肯定會有return語句,如果沒有會報錯
如果return語句沒有放在函數體的最後也不會報錯,但不建議

函數體中僅有一句話,則可以省略begin and

使用delimiter語句設定結束標記
delimiter $

*/
# 二、呼叫函數
SELECT 函數名(參數列表)

# ------------------------------案例演示-----------------------------------------#
# 1、無參有返回
# 案例:返回公司的員工個數
DELIMITER $
CREATE FUNCTION myf1() RETURNS INT
BEGIN 
	DECLARE c INT DEFAULT 0;  # 定義區域性變數
	SELECT COUNT(*) INTO c
	FROM employees;
	RETURN c;
END $

SELECT myf1() $

# 2、有參數返回
# 案例一、根據員工名,返回它的工資
CREATE FUNCTION myf2(empName VARCHAR(20)) RETURNS DOUBLE
BEGIN
	SET @sal=0;  # 定義使用者變數
	SELECT salary INTO @sal  # 賦值
	FROM employees
	WHERE last_name=empName;
	
	RETURN @sal;
END $

SELECT myf2('Kochhar') $

# 案例二、根據部門名,返回該部門的平均工資
CREATE FUNCTION myf3(deptName VARCHAR(20)) RETURNS DOUBLE 
BEGIN
	DECLARE ag DOUBLE;
	SELECT AVG(salary) INTO ag
	FROM employees e
	INNER JOIN departments d
	ON e.department_id=d.department_id
	WHERE d.department_name=deptName;
	RETURN ag;
END $

SELECT myf3('IT')$

# 三、檢視函數
SHOW CREATE FUNCTION myf3;

# 四、刪除函數
DROP FUNCTION myf3;

# 案例、建立函數,實現傳入兩個float,返回二者之和
CREATE FUNCTION test_fun1(a FLOAT, b FLOAT) RETURNS FLOAT
BEGIN
	DECLARE s FLOAT;
	SET s=a+b;
	RETURN s;
END $

7.4 流程控制

  • 順序結構:程式從上往下執行
  • 分支結構:程式按條件進行選擇執行,從兩條或多條路徑中選擇一條執行
  • 回圈結構:程式滿足一定條件下,重複執行一組語句
  • 程式碼演示
# 流程控制結構
/*
順序結構:程式從上往下依次執行
分支結構:程式從兩條或多條路徑中選擇一條去執行
回圈結構:程式在滿足一定條件的基礎上,重複執行一段程式碼

*/

# 一、分支結構
/*
1、if函數
功能:實現簡單的雙分支
語法:
select if(表達式1,表達式2,表達式3)
執行順序:
如果說表達式1成立,則if函數返回表達式2的值,否則返回表達式3的值
應用:任何地方
*/

# 2、case結構
/*
情況1:類似於java中的switch語句,一般用於實現等值判斷
語法:
		case 變數|表達式|欄位
		when 要判斷的值 then 返回的值1或語句1; 
		when 要判斷的值 then 返回的值2或語句2;
		...
		else 要返回的值n或語句n;
		end case;

情況2、類似於java中的多重if語句,一般用於實現區間判斷
語法:
	case 
	when 要判斷的條件1 then 返回的值1或語句1
	when 要判斷的條件2 then 返回的值2或語句2
	...
	else 要返回的值n或語句n;
	end case
	
特點:
①
可以作爲表達式,巢狀在其他語句中使用,可以放在任何地方,begin end 中或begin end的外面
可以作爲獨立的語句去使用,只能放在begin end中

②
如果when中的值滿足或條件成立,則執行對應的then後面的語句,並且結束case
如果都不滿足,則執行else中的語句或值

③
else可以省略,如果else省略了,並且所有的when條件都不滿足,則返回NULL
*/
# 案例
# 建立儲存過程,根據傳入的成績,來顯示等級,比如傳入的成績:90-100,顯示A,80-90,顯示B,60-80,顯示C,否則顯示D
CREATE PROCEDURE test_case(IN score INT)
BEGIN
	CASE 
	WHEN score>=90 AND score<=100 THEN SELECT 'A';
	WHEN score>=80 THEN SELECT 'B';
	WHEN score>=60 THEN SELECT 'C';
	ELSE SELECT 'D';
	END CASE;
END$

# 3、if結構
/*
功能:實現多重分支
語法:
if 條件1 then 語句1;
elseif 條件2 then 語句2;
...
【else 語句n;】
end if;

應用場合:應用在begin end中

*/
# 建立儲存過程,根據傳入的成績,來顯示等級,比如傳入的成績:90-100,返回A,80-90,返回B,60-80,返回C,否則返回D
CREATE FUNCTION test_if(score INT) RETURNS CHAR
BEGIN
	IF scoure>=90 AND score<=100 THEN RETURN 'A';
	ELSEIF score>=80 THEN RETURN 'B';
	ELSEIF score>=60 THEN RETURN 'C';
	ELSE RETURN 'D';
	END IF;
END $

# 二、回圈結構
/*
分類:
while、loop、repeat
回圈控制:
	iterate類似於java中continue
	leave 類似於 break 跳出,

*/

# 1、while
/*
語法:
【標籤:】 while 回圈條件 do
	回圈體;
end while【標籤】;

*/

# 2、loop
/*
語法:
【標籤:】loop
	回圈體;
end loop 【標籤】;

可以用來模擬死回圈

*/

# 3、repeat
/*
語法:
【標籤:】repeat
	回圈體;
until 結束回圈的條件
end repeat 【標籤】;

*/

# 沒有新增回圈控制語句
# 案例:批次插入,根據次數插入到admin表中多條記錄
CREATE PROCEDURE pro_while1(IN insertCount INT)
BEGIN
	DECLARE i INT DEFAULT 1;
	WHILE i<=insertCount DO
		INSERT INTO admin(username,`password`) VALUES(CONCAT('Rose',i),'666');
		SET i=i+1;
	END WHILE; 
END $

CALL pro_while1(100)$

# 2、新增leave語句
# 案例:批次插入,根據次數插入到admin表中多條記錄,如果次數大於20停止
CREATE PROCEDURE test_while(IN insertCount INT)
BEGIN
	DECLARE i INT DEFAULT 1;
	a:WHILE i<=insertCount DO
		INSERT INTO admin(username,`password`) VALUES(CONCAT('小花',i),'0000');
		IF i>=20 THEN LEAVE a;
		END IF;
		SET i=i+1;
	END WHILE a;
END $

CALL test_while1(100)$

# 3、新增iterate語句
# 案例:批次插入,根據次數插入到admin表中多條記錄,只插入偶數次
CREATE PROCEDURE test_while(IN insertCount INT)
BEGIN
	DECLARE i INT DEFAULT 0;
	a:WHILE i<=insertCount DO
		INSERT INTO admin(username,`password`) VALUES(CONCAT('小花',i),'0000');
		IF MOD(i,2) <> 0 THEN ITERATE a;
		END IF;
		SET i=i+1;
	END WHILE a;
END $