Mysql5.5筆記大全,b站學習筆記,基礎語法

Mysql5.5版本 基礎語法2020.4.15更新完畢

基礎概念

  1. DB:數據庫
  2. DBMS:數據庫管理系統,管理DB
  3. SQL:結構化查詢語言
  4. 數據存放在表,表存放在庫中。
  5. 表中有一個或多個列,列又稱爲“字段”,相當於java中的屬性。
  6. 表中每行數據,相當於java中對象。
  7. 常見DNMS:mysql、oracle、db2、sqlserver。
  8. mysql被oracle收購

1.mysql的啓動和停止

.計算機管理-服務
.管理員cmd:
net start mysql
net stop mysql

2.mysql的登陸和退出

  • .mysql自帶的客戶端

  • 管理員cmd:mysql -h localhost -P 3306 -u root -p
    mysql (-h 主機名字 -P 端口號)-u用戶名 -p密碼

  • .exit\ctrl+c 退出

3.常見命令

  • 查看所有數據庫 show databases;
  • 打開指定庫 use 庫名字;
  • 查看當前庫的所有表 show tables;
  • 查看其它庫的所有表 show tables from 庫名字;
  • 創建表
creat table 表名(
	列名 列類型,
	列名 列類型,
	。。。
	);
例如 create table stuinfo(
    	id int,
    	 name varchar(20));
  • 查看錶結構 desc 表名

  • 查看錶內容 select * from 表名

  • 查看服務器版本 .
    -mysql服務端 select version()
    .cmd: mysql --version
    .cmd:mysql -V

4.註釋

:#
:-- 註釋(有空格)
:多行:/*註釋 */

5.sqlyog軟件可視化管理數據庫

注SQL語言分類(以下進行展開學習):

  1. DQL(Data Query Language):數據查詢語言 select
  2. DML(Data Manipulate Language):數據操作語言 insert 、update、delete
  3. DDL(Data Define Languge):數據定義語言 create、drop、alter
  4. TCL(Transaction Control Language):事務控制語言 commit、rollback

6.查詢DQL語言

6.1基礎查詢

SELECT * 
FROM `departments`;
#select後面1.* 所有字段2.多個字段逗號間隔3.常量值4.函數名字(實參列表)
#5.表達式100/123 

#concat函數,拼接字符
SELECT 
 CONCAT(`first_name`,',',`last_name`) AS asl
FROM `employees`;

#IFNULL函數,條件判空,查詢是否爲null 則輸出0,AS起別名
SELECT IFNULL(`commission_pct`,0) AS '獎金率' ,
 `commission_pct` 
FROM `employees`;

#distinct 去重複
select distinct 字段 from 表名;
#+運算:
select 字符+數字; #字符轉換數字進行運算,失敗轉換成0
select null+數字;#結果爲null

#isnull函數,真值判空,返回0/1
select isnull(字段) from 表名;

6.2 條件查詢

條件查詢
後加 where 篩選條件;
篩選條件:

  1. 條件運算符:< > != <>(不等) >= <= <=>(安全等於)
  2. 邏輯:&& || !
    and or not
  3. 模糊查詢:like between and in is null

SELECT `first_name` 
FROM `employees`;


SELECT `last_name`, `department_id`
FROM `employees`
WHERE `department_id`!=90;#建議用<>

SELECT * 
FROM `employees`
WHERE `salary`>12000
AND 	`salary`<20000;


#模糊例子
SELECT * 
FROM `employees`
WHERE 
#	`last_name` like '%a%'#通配符%0到多個,含有a的

	`first_name` LIKE '__n_%';#通配符_單個位置查詢,漏空查詢,第三個字母爲n
	
SELECT * 
FROM `employees`
WHERE 
	`first_name` LIKE '__$_%' ESCAPE '$';#escape 指定字符後面的下劃線轉義,通配符當作普通字符,第三個字符華爲_
#除了上述字符查詢,還可以數值查詢,like '1__' 查詢1**型。


SELECT 
	* 
FROM 
	`employees`
WHERE	
/*	`salary`>12000
AND 	
	`salary`<20000;
*/
	`salary` BETWEEN 12000 AND 20000;#等價於上式,簡化

SELECT 
	`last_name`,`job_id`
FROM 
	`employees`
WHERE
#	`job_id`='AD_PRES' or `job_id` = 'AD_VP';
	job_id IN('AD_PRES','AD_VP');#等價於上,在字段`job_id`上查詢屬於in的某幾項

SELECT 
	`last_name`,`commission_pct`
FROM 
	`employees`
WHERE  
	`commission_pct` IS NULL;#解決=不能用於判斷null
	
#安全等於<=>,相比=能判斷null值
SELECT 
	`last_name`,`commission_pct`
FROM 
	`employees`
WHERE  
	`commission_pct` <=> NULL;


	
	

6.3 排序查詢

where 條件後進行排序
order by 排序列表 (DESC/ASC)

  1. DESC 降序
    ASC 升序,不寫默認升序
  2. order by 可以放單個字段,多個字段,表達式,函數,別名
  3. 查詢語句最後面,limit字句除外
#進階3:排序查詢

/*引入

*/

#工資從高到低
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)) 年薪
FROM `employees`
ORDER BY `salary`*12*(1+IFNULL(`commission_pct`,0)) DESC;

#顯示信息和年薪(表達式),別名排序
SELECT *,`salary`*12*(1+IFNULL(`commission_pct`,0)) 年薪
FROM `employees`
ORDER BY 年薪 DESC;

#姓名長度排序,函數排序
SELECT LENGTH(`last_name`) 字節長度,`last_name`
FROM `employees`
ORDER BY LENGTH(`last_name`);

#先按照工資升排序,後按照員工編號降排序
SELECT *
FROM `employees`
ORDER BY `salary`DESC,`employee_id` ASC;

#查詢郵箱包含e的員工信息, 郵箱字節數降序,部門號升序
SELECT	*
FROM `employees`
WHERE `email` LIKE '%e%'
ORDER BY LENGTH(`email`) DESC,`department_id` ASC;


6.4常見函數

  1. 調用 select 函數名(實參)(from 表(實參位置))

  2. 分類:
    (1)單行函數 concat length ifnull、
    分類:字符函數,數字函數,日期函數,其他函數,流程控制~

    (2)分組函數(統計函數、聚合函數、組函數)

#進階四 常見函數

##################一 .字符函數########################
#1.length
SELECT LENGTH('張ha');#5
SHOW VARIABLES LIKE '%char%'#utf8 中文三個字符 英文一個

#2.concat 拼接字符串

#3.upper lower 大小寫
SELECT CONCAT(UPPER(`last_name`),LOWER(`first_name`))
FROM `employees`

#4.substr、substring索引從1開始
SELECT SUBSTR('李莫愁愛上了路咱院',7) out_put;
#截取索引,起始2,長度4
SELECT SUBSTR('李莫愁愛上了路咱院',2,4) out_put;
#姓名中首字母大寫,其他字符小寫,用_拼接,顯示出來
SELECT CONCAT(UPPER(SUBSTR(`last_name`,1,1)),'_',LOWER(SUBSTR(`last_name`,2))) out_put
FROM `employees`;

#5.instr 返回第一次出現索引
SELECT INSTR('的手法首發的方法的','方法') AS out_put;#7

#6.trim 默認去前後空格,指定字符去前後
SELECT LENGTH(TRIM('     aaa     ')) AS out_put;#3
SELECT LENGTH('     aaa     ') AS out_put;	#13
SELECT TRIM('b' FROM 'bbbbb1bbbb1bbb') out_put;#1bbbb1

#7.lpad 指定字符左填充長度,*填充zhanggg到10個字符長度
SELECT LPAD('zhanggg',10,'*') AS out_put;	#***zhanggg

#8.rpad 指定字符 右填充
SELECT RPAD('zhanggg',10,'*')			#zhanggg***

#9.replace 替換 (字符,被替換字符,填充字符)
SELECT REPLACE('你是人','人','狗')#你是狗

######################二.數學函數########################
#1.round四捨五入
SELECT ROUND(16.7)	#17
SELECT ROUND(1.564,2)   #1.56 指定位數2位

#2.ceil 向上取整,>=參數最小整數
SELECT CEIL(1.40)       #2

#3.floor 向下取整
SELECT FLOOR(-1.4)	#-2

#4.truncate 截斷
SELECT	TRUNCATE(1.69,1)#1.6,截斷小數點一位

#5.mod取餘 mod(a,b) a-a/b*b
SELECT MOD(10,-3);#1
SELECT 10%3       #1

###################三.日期函數#####################
#1.now
SELECT NOW();	#2020-02-11 15:49:31

#curdate 無時間
SELECT CURDATE();

#3.curtime 無日期
SELECT CURTIME();

#4.指定部分 年月日小時分鐘秒
SELECT YEAR(NOW());
SELECT YEAR('1998-1-1');

SELECT YEAR(`hiredate`)FROM `employees`

SELECT MONTH(NOW())#2
SELECT MONTHNAME(NOW())#February
  
#5.str_to_date 字符轉換日期
/*
%Y四位年
%y兩位年
%m補零月
%c不補零月
%d補零日
%H二十四 小時制
%h十二小時制
%i分鐘
%s秒
*/
SELECT STR_TO_DATE('1997-8-9','%Y-%c-%d') out_put;
#查詢1992-4-3入職員工
SELECT *FROM `employees` WHERE `hiredate`='1992-4-3'
SELECT *FROM `employees` WHERE `hiredate`=STR_TO_DATE('4-3 1992','%c-%d %Y')#規定形式

#6.date_format 將日期轉換成字符

SELECT DATE_FORMAT(NOW(),'%y年%m月%d日')#20年02月11日
#查詢有獎金的員工名和入職日期(月 日 年)
SELECT `last_name`,DATE_FORMAT(`hiredate`,'%m月/%m日 %y年')
FROM `employees`  		#04月/04日 92年、04月/04日 92年...

############################四.其他函數###########################
SELECT	VERSION();
SELECT	DATABASE();
SELECT	USER();

############################五.流程控制函數#######################
#1.if函數:if else 的效果

SELECT IF(10>5,'大','小')

SELECT last_name,commission_pct,IF(commission_pct IS NULL,'hehe','hah ')
FROM `employees`

#2.case函數的使用一: switch case 的效果
/*
switch(變量或表達式){
	case 常量1: 語句1:break;
	....
	
	default:語句n;break;
	}
mysql中
case 要判斷的字段或表達式
when 常量1 then 顯示的值或語句
when 常量1 then 顯示的值或語句
。
。
。
else 語句n
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`

#3.case 函數的使用二 類似於多重if
/*
case
when 條件1 then 值或語句
when 條件2 then 值或語句
.
.
else 條件2 then 值或語句
end
*/
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值	

3. 搭配distinct去重運算

4.一般使用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) 平均 FROM `employees`


SELECT ROUND(AVG(salary),2) FROM `employees`
#保留兩位平均值

#2.參數支持哪些類型
SELECT SUM(last_name),AVG(last_name) FROM `employees`#字符沒有意義,適合數字

SELECT MAX(last_name),MIN(`hiredate`) FROM `employees`#字符、日期有意義

SELECT COUNT(last_name) FROM `employees`#支持

#3.是否忽略null,均忽略
SELECT SUM(`commission_pct`),AVG(`commission_pct`) FROM `employees`

#4.和distinct搭配
SELECT SUM(DISTINCT `salary`),SUM(`salary`) FROM`employees`#去重求和

SELECT COUNT(DISTINCT `salary`) FROM`employees`#計算幾種工資 57 

#5.count函數詳細介紹

SELECT COUNT(`salary`) FROM`employees`

SELECT COUNT(*) FROM`employees`#統計行數 107

SELECT COUNT(1) FROM`employees`#統計1個數, 每行前寫1 107

SELECT COUNT('常量') FROM`employees`#統計常量個數, 每行前寫常量 107

#效率:
/*
MYISAM存儲引擎下,count(*)的效率高
INNODB存儲引擎下,count(*)、count(1)效率差不多,比count(字段)要高一些

*/

#6.和分組函數一同查詢的字段有限制

SELECT AVG(`salary`),`employee_id` FROM `employees`;#查詢字段維度不一樣放一起查詢無意義



#練習
#1.查詢工資最大值最小值平均值和總和
SELECT MAX(`salary`) mx_sal,MIN(`salary`),ROUND(AVG(`salary`),2) ag_sal,SUM(`salary`) sm_sal
FROM `employees`;
#2.查詢員工表中的最大入職時間和最小入職時間的相差天數

SELECT DATEDIFF('2017-10-1','2017-9-29');#查詢數據差值

SELECT DATEDIFF(MAX(`hiredate`),MIN(`hiredate`)) diffrence
FROM `employees`

#3.查詢部門編號爲90的員工個數
SELECT COUNT(*) 個數
FROM `employees`
WHERE `department_id` = 90


6.5 分組查詢

語法:
select 分組函數,列(要求出現在group by的後面)
from 表
【where 篩選條件】
group by 分組的列表
【order by 排序】

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

特點: 1.分組查詢中的篩選條件分爲兩類
數據源 位置
分組前篩選: 原始表 group by 字句的前面
分組後篩選 分組後的結果集 group by 字句的後面

  1. 分組函數做條件肯定是放在having 的後面

  2. 能用分組前篩選的優先考慮分組前篩選

  3. group by 子句支持單個字段分組,多個字段分組,逗號隔開,不分先後

  4. 添加排序放在最後

#進階5:分組查詢
#查詢每個部門的平均工資
SELECT AVG(salary) FROM `employees`;

#查詢每個工種的最高工資
SELECT MAX(`salary`),`job_id`
FROM `employees`
GROUP BY `job_id` #不加相當於查詢所有工種的最高工資

#案例2 每個位置上的部門個數
SELECT COUNT(*),`location_id`
FROM `departments`
GROUP BY `location_id`#組內查詢

#添加篩選條件
#案例1 查詢郵箱中包含a字符,並且每個部門的平均工資
SELECT AVG(`salary`),`department_id`,`email`
FROM `employees`
WHERE `email` LIKE '%a%'
GROUP BY `department_id`

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

#複雜的篩選條件
 
#案例1 查詢哪個部門的員工數>2

#查詢每個部門的員工個數
SELECT COUNT(*),`department_id`
FROM `employees` 
GROUP BY `department_id`
#對上面結果,進行篩選,查詢哪個部門的員工個數大於2
HAVING COUNT(*)>2      #having分組後的篩選

#案例2 查詢每個工種有獎金的員工的最高工資>12000的工種編號和最高工資
#1.查詢每個工種有獎金的員工的最高高工資
SELECT MAX(`salary`),`job_id`
FROM `employees`
GROUP BY `job_id`
#2.對上述結果進行篩選,having 挑選上述篩選的字段
HAVING MAX(`salary`)>12000


#案例3 查詢領導編號>102的每個領導下的最低工資》5000的領導編號
SELECT `manager_id`,MIN(`salary`)
FROM `employees`
#where `manager_id`>102  #都行
GROUP BY `manager_id`
HAVING MIN(`salary`)>5000 #每個領導下的最低工資篩選
AND `manager_id`>102

#按表達式進行分組
#案例:按員工姓名的長度分組,查詢每一組的員工個數,篩選員工個數>5的有哪些

#1.查詢每個長度的員工個數
SELECT COUNT(*),LENGTH(`last_name`) len_name
FROM `employees`
GROUP BY LENGTH(`last_name`)#len_name也可以
#2.添加篩選條件
HAVING COUNT(*)>5 

#按多個字段分組

#案例:查詢每個部門每個工種的員工的平均工資

SELECT AVG(`salary`),`job_id`,`department_id`
FROM `employees`
GROUP BY `department_id`,`job_id`#兩個組 相對於一個組來說,更細,分完一組的基礎上再分組

#添加排序,最後加
##案例:查詢每個部門的每個工種的員工的平均工資>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`) DESC;

6.6連接查詢

含義:又稱多表查詢,當查詢的字段來自於多個表時,就會用到連接查詢

笛卡爾乘積現象:表1 有m行,表2有n行,結果=m*n行

發生原因:沒有有效的連接條件
如何避免:添加有效的連接條件

分類:

按年代分類:
sql92標準:僅僅支持內連接
sql99標準【推薦】:支持內連接+外連接(左外和右外)+交叉連接

按功能分類:
	內連接:
		等值連接
		非等值連接
		自連接
	外連接:
		左外連接
		右外連接
		全外連接
	
	交叉連接

1. sql92

#進階6:連接查詢
SELECT * FROM beauty;

SELECT * FROM boys;
#一、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、爲表起別名
/*
①提高語句的簡潔度
②區分多個重名的字段

注意:如果爲表起了別名,則查詢的字段就不能使用原來的表名去限定

*/
#查詢員工名、工種號、工種名

SELECT e.last_name,e.job_id,j.job_title
FROM employees  e,jobs j
WHERE e.`job_id`=j.`job_id`;

#3、兩個表的順序是否可以調換

#查詢員工名、工種號、工種名

SELECT e.last_name,e.job_id,j.job_title
FROM jobs j,employees e
WHERE e.`job_id`=j.`job_id`;


#4、可以加篩選


#案例:查詢有獎金的員工名、部門名

SELECT last_name,department_name,commission_pct

FROM employees e,departments d
WHERE e.`department_id`=d.`department_id`
AND e.`commission_pct` IS NOT NULL;

#案例2:查詢城市名中第二個字符爲o的部門名和城市名

SELECT department_name,city
FROM departments d,locations l
WHERE d.`location_id` = l.`location_id`
AND city LIKE '_o%';

#5、可以加分組


#案例1:查詢每個城市的部門個數

SELECT COUNT(*) 個數,city
FROM departments d,locations l
WHERE d.`location_id`=l.`location_id`
GROUP BY city;


#案例2:查詢有獎金的每個部門的部門名和部門的領導編號和該部門的最低工資
SELECT department_name,d.`manager_id`,MIN(salary)
FROM departments d,employees e
WHERE d.`department_id`=e.`department_id`
AND commission_pct IS NOT NULL
GROUP BY department_name,d.`manager_id`;
#6、可以加排序


#案例:查詢每個工種的工種名和員工的個數,並且按員工個數降序

SELECT job_title,COUNT(*)
FROM employees e,jobs j
WHERE e.`job_id`=j.`job_id`
GROUP BY job_title
ORDER BY COUNT(*) DESC;



#7、可以實現三表連接?

#案例:查詢員工名、部門名和所在的城市

SELECT last_name,department_name,city
FROM employees e,departments d,locations 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、非等值連接


#案例1:查詢員工的工資和工資級別


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';

/*
select salary,employee_id from employees;
select * from job_grades;
CREATE TABLE job_grades
(grade_level VARCHAR(3),
 lowest_sal  int,
 highest_sal int);

INSERT INTO job_grades
VALUES ('A', 1000, 2999);

INSERT INTO job_grades
VALUES ('B', 3000, 5999);

INSERT INTO job_grades
VALUES('C', 6000, 9999);

INSERT INTO job_grades
VALUES('D', 10000, 14999);

INSERT INTO job_grades
VALUES('E', 15000, 24999);

INSERT INTO job_grades
VALUES('F', 25000, 40000);

*/

#3、自連接
#案例:查詢 員工名和上級的名稱

SELECT e.employee_id,e.last_name,m.employee_id,m.last_name
FROM employees e,employees m
WHERE e.`manager_id`=m.`employee_id`;

#練習
#員工表的最大工資,平均工資
SELECT MAX(`salary`),AVG(`salary`) FROM `employees`

#二。查詢員工表的。。。。
SELECT `employee_id`,`job_id`,`last_name`
FROM `employees`
ORDER BY `department_id` DESC, `salary` ASC

#三 查詢`job_id`中包含a e 並且a在e的前面
SELECT `job_id` 
FROM `employees`
WHERE `job_id` LIKE '%a%b%'


#四
SELECT s.name,g.name,score
FROM student s , grade g, result r
WHERE s.id=r.studentNo
AND s.gradeId=g.id
#五
SELECT NOW();

SELECT TRIM(‘a’ FROM'aaabs')#trim去字符

SELECT SUBSTR('dafd',2,2) #截取 指定起始位置和長度



2. sql99

#二、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、等值連接
#案例1.查詢員工名、部門名

SELECT last_name,department_name
FROM departments d
 JOIN  employees e
ON e.`department_id` = d.`department_id`;



#案例2.查詢名字中包含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. 查詢部門個數>3的城市名和部門個數,(添加分組+篩選)

#①查詢每個城市的部門個數
#②在①結果上篩選滿足條件的
SELECT city,COUNT(*) 部門個數
FROM departments d
INNER JOIN locations l
ON d.`location_id`=l.`location_id`
GROUP BY city
HAVING COUNT(*)>3;


#案例4.查詢哪個部門的員工個數>3的部門名和員工個數,並按個數降序(添加排序)

#①查詢每個部門的員工個數
SELECT COUNT(*),department_name
FROM employees e
INNER JOIN departments d
ON e.`department_id`=d.`department_id`
GROUP BY department_name

#② 在①結果上篩選員工個數>3的記錄,並排序

SELECT COUNT(*) 個數,department_name
FROM employees e
INNER JOIN departments d
ON e.`department_id`=d.`department_id`
GROUP BY department_name
HAVING COUNT(*)>3
ORDER BY COUNT(*) DESC;

#5.查詢員工名、部門名、工種名,並按部門名降序(添加三表連接)

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 department_name DESC;

#二)非等值連接

#查詢員工的工資級別

SELECT salary,grade_level
FROM employees e
 JOIN job_grades g
 ON e.`salary` BETWEEN g.`lowest_sal` AND g.`highest_sal`;
 
 
 #查詢工資級別的個數>20的個數,並且按工資級別降序
 SELECT COUNT(*),grade_level
FROM employees e
 JOIN job_grades g
 ON e.`salary` BETWEEN g.`lowest_sal` AND g.`highest_sal`
 GROUP BY grade_level
 HAVING COUNT(*)>20
 ORDER BY grade_level DESC;
 
 
 #三)自連接
 
 #查詢員工的名字、上級的名字
 SELECT e.last_name,m.last_name
 FROM employees e
 JOIN employees m
 ON e.`manager_id`= m.`employee_id`;
 
  #查詢姓名中包含字符k的員工的名字、上級的名字
 SELECT e.last_name,m.last_name
 FROM employees e
 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、全外連接=內連接的結果+表1中有但表2沒有的+表2中有但表1沒有的
 */
 #引入:查詢男朋友 不在男神表的的女神名
 
 SELECT * FROM beauty;
 SELECT * FROM boys;
 
 #左外連接
 SELECT b.*,bo.*
 FROM boys bo
 LEFT OUTER JOIN beauty b
 ON b.`boyfriend_id` = bo.`id`
 WHERE b.`id` IS NULL;
 
 
 #案例1:查詢哪個部門沒有員工
 #左外
 SELECT d.*,e.employee_id
 FROM departments d
 LEFT OUTER JOIN employees e
 ON d.`department_id` = e.`department_id`
 WHERE e.`employee_id` IS NULL;
 
 
 #右外
 
  SELECT d.*,e.employee_id
 FROM employees e
 RIGHT OUTER JOIN departments d
 ON d.`department_id` = e.`department_id`
 WHERE e.`employee_id` IS NULL;
 
 
 #全外
 #互爲從表 沒有的都用null補充
 
 
 USE girls;
 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支持的較多
可讀性:sql99實現連接條件和篩選條件的分離,可讀性較高

6.6.1 練習

#一,查詢編號》3的女神的男朋友的信息,如果有則列出詳細,如果沒有用null填充
 SELECT b.`id`,b.`name`,bo.*
 FROM `beauty` b
 LEFT OUTER JOIN `boys` bo  #左右自動填充null
 ON b.`boyfriend_id`=bo.`id`
 WHERE b.`id`>2
 
 #二。查詢哪個城市沒有部門
 SELECT l.city,d.*
 FROM `locations` l
 LEFT OUTER JOIN `departments` d
 ON l.location_id = d.location_id
 WHERE d.department_name IS NULL
 
 #三。查詢部門名爲sal或it的員工信息
 SELECT e.*,d.`department_name`,d.`department_id`
 FROM `departments` d
 LEFT OUTER JOIN `employees` e
 ON d.`department_id`=e.`department_id`
 #where `department_name` ='SAL'
 #or `department_name` = 'IT'    #一樣
 WHERE`department_name` IN('SAL','IT')

6.7 子查詢

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

分類:
按子查詢出現的位置:
select後面:
僅僅支持標量子查詢

from後面:
	支持表子查詢
where或having後面:★
	標量子查詢(單行) √
	列子查詢  (多行) √
	
	行子查詢
	
exists後面(相關子查詢)
	表子查詢

按結果集的行列數不同:

  • 標量子查詢(結果集只有一行一列)

  • 列子查詢(結果集只有一列多行)

  • 行子查詢(結果集有一行多列)

  • 表子查詢(結果集一般爲多行多列)

#一、where或having後面
/*
1、標量子查詢(單行子查詢)
2、列子查詢(多行子查詢)
3、行子查詢(多列多行)



特點:
①子查詢放在小括號內
②子查詢一般放在條件的右側
③標量子查詢,一般搭配着單行操作符使用
> < >= <= = <>

列子查詢,一般搭配着多行操作符使用
in、any/some、all

④子查詢的執行優先於主查詢執行,主查詢的條件用到了子查詢的結果

*/
#1.標量子查詢★

#案例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'

);

#案例2:返回job_id與141號員工相同,salary比143號員工多的員工 姓名,job_id 和工資

#①查詢141號員工的job_id
SELECT job_id
FROM employees
WHERE employee_id = 141

#②查詢143號員工的salary
SELECT salary
FROM employees
WHERE employee_id = 143

#③查詢員工的姓名,job_id 和工資,要求job_id=①並且salary>②

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

);


#案例3:返回公司工資最少的員工的last_name,job_id和salary

#①查詢公司的 最低工資
SELECT MIN(salary)
FROM employees

#②查詢last_name,job_id和salary,要求salary=①
SELECT last_name,job_id,salary
FROM employees
WHERE salary=(
	SELECT MIN(salary)
	FROM employees
);


#案例4:查詢最低工資大於50號部門最低工資的部門id和其最低工資

#①查詢50號部門的最低工資
SELECT  MIN(salary)
FROM employees
WHERE department_id = 50

#②查詢每個部門的最低工資

SELECT MIN(salary),department_id
FROM employees
GROUP BY department_id

#③ 在②基礎上篩選,滿足min(salary)>①
SELECT MIN(salary),department_id
FROM employees
GROUP BY department_id
HAVING MIN(salary)>(
	SELECT  MIN(salary)
	FROM employees
	WHERE department_id = 50


);

#非法使用標量子查詢

SELECT MIN(salary),department_id
FROM employees
GROUP BY department_id
HAVING MIN(salary)>(
	SELECT  salary  #好多值,維度對不上
	FROM employees
	WHERE department_id = 250


);



#2.列子查詢(多行子查詢)★
#案例1:返回location_id是1400或1700的部門中的所有員工姓名

#①查詢location_id是1400或1700的部門編號
SELECT DISTINCT department_id
FROM departments
WHERE location_id IN(1400,1700)

#②查詢員工姓名,要求部門號是①列表中的某一個

SELECT last_name
FROM employees
WHERE department_id  <>ALL(
	SELECT DISTINCT department_id
	FROM departments
	WHERE location_id IN(1400,1700)


);


#案例2:返回其它工種中比job_id爲‘IT_PROG’工種任一工資低的員工的員工號、姓名、job_id 以及salary

#①查詢job_id爲‘IT_PROG’部門任一工資

SELECT DISTINCT salary
FROM employees
WHERE job_id = 'IT_PROG'

#②查詢員工號、姓名、job_id 以及salary,salary<(①)的任意一個
SELECT last_name,employee_id,job_id,salary
FROM employees
WHERE salary<ANY(
	SELECT DISTINCT salary
	FROM employees
	WHERE job_id = 'IT_PROG'

) AND job_id<>'IT_PROG';

#或
SELECT last_name,employee_id,job_id,salary
FROM employees
WHERE salary<(
	SELECT MAX(salary)
	FROM employees
	WHERE job_id = 'IT_PROG'

) AND job_id<>'IT_PROG';


#案例3:返回其它部門中比job_id爲‘IT_PROG’部門所有工資都低的員工   的員工號、姓名、job_id 以及salary

SELECT last_name,employee_id,job_id,salary
FROM employees
WHERE salary<ALL(
	SELECT DISTINCT salary
	FROM employees
	WHERE job_id = 'IT_PROG'

) AND job_id<>'IT_PROG';

#或

SELECT last_name,employee_id,job_id,salary
FROM employees
WHERE salary<(
	SELECT MIN( 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 MIN(employee_id)
FROM employees


#②查詢最高工資
SELECT MAX(salary)
FROM employees


#③查詢員工信息
SELECT *
FROM employees
WHERE employee_id=(
	SELECT MIN(employee_id)
	FROM employees


)AND salary=(
	SELECT 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 (
	SELECT department_name,e.department_id
	FROM departments d
	INNER JOIN employees e
	ON d.department_id=e.department_id
	WHERE e.employee_id=102
	
) 部門名;



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

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


SELECT * FROM job_grades;


#②連接①的結果集和job_grades表,篩選條件平均工資 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(完整的查詢語句)
結果:
1或0



*/

SELECT EXISTS(SELECT employee_id FROM employees WHERE salary=300000);

#案例1:查詢有員工的部門名

#in
SELECT department_name
FROM departments d
WHERE d.`department_id` IN(
	SELECT department_id
	FROM employees

)

#exists

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


);


#案例2:查詢沒有女朋友的男神信息

#in

SELECT bo.*
FROM boys bo
WHERE bo.id NOT IN(
	SELECT boyfriend_id
	FROM beauty
)

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

);

6.7.1 練習

#1.查詢和zlotkey相同部門的員工姓名和工資


SELECT `department_id`
FROM `employees`
WHERE `last_name`= 'Zlotkey'

SELECT `last_name`,`salary`
FROM `employees`
WHERE `department_id`=(
	SELECT `department_id`
	FROM `employees`
	WHERE `last_name`= 'Zlotkey'
)

#2 查詢工資比平均工資高的員工的員工號,姓名和工資

SELECT AVG(`salary`)
FROM `employees`

SELECT `employee_id`,`last_name`,`salary`
FROM `employees`
WHERE `salary`>(
	SELECT AVG(`salary`)
	FROM `employees`
)

#3 查詢各個部門中工資比本部門平均工資高的員工號,姓名和工資
#***************************重要**************************
SELECT AVG(`salary`),`department_id`
FROM `employees`
GROUP BY`department_id`

SELECT `employee_id`,`last_name`,`salary`,e.`department_id`
FROM `employees` e
INNER JOIN(
	SELECT AVG(`salary`)ag,`department_id`
	FROM `employees`
	GROUP BY`department_id`
) ag_dep
ON e.`department_id` = ag_dep.`department_id`
WHERE salary>ag_dep.ag;

#4.查詢姓名中包含字母u的員工在相同部門的員工的員工號和姓名

SELECT DISTINCT `department_id`
FROM `employees`
WHERE `last_name` LIKE '%u%'

SELECT `last_name`,`employee_id`
FROM `employees`
WHERE `employee_id` IN(
	SELECT DISTINCT `department_id`
	FROM `employees`
	WHERE `last_name` LIKE '%u%'
)

#5查詢在部門的location——id爲1700的部門工作的員工和員工號
SELECT `department_id`,`location_id`
FROM `departments`
WHERE `location_id` = 1700

SELECT `employee_id`,`last_name`
FROM `employees`
WHERE `department_id` IN(  #=any 也可
	SELECT `department_id`
	FROM `departments`
	WHERE `location_id` = 1700

) 

#6查詢管理者是king的員工姓名和工資
SELECT `employee_id`
FROM `employees`
WHERE `last_name`= 'K_ing'

SELECT `last_name`,`salary`,`manager_id`
FROM `employees`
WHERE `manager_id` IN(  #多行in 單行=
	SELECT `employee_id`
	FROM `employees`
	WHERE `last_name`= 'K_ing'
)

#7查詢工資最高的員工的姓名,要求first和lastname 顯示爲一列
#列名爲姓.名

SELECT MAX(`salary`)
FROM `employees`


SELECT CONCAT(`first_name`,'.',`last_name`) "姓.名"
FROM `employees`
WHERE salary = (
	SELECT MAX(`salary`)
	FROM `employees`

)

6.8 分頁查詢

應用場景:當要顯示的數據,一頁顯示不全,需要分頁提交sql請求
語法:

select 查詢列表
fromjoin type join2
on 連接條件
where 篩選條件
group by 分組字段
having 分組後的篩選
order by 排序的字段】
limitoffset,】size;

offset要顯示條目的起始索引(起始索引從0開始)
size 要顯示的條目個數

特點:
①limit語句放在查詢語句的最後
②公式
要顯示的頁數 page,每頁的條目數size

select 查詢列表
from 表
limit (page-1)*size,size;

size=10
page  
1	0
2  	10
3	20
#進階8:分頁查詢 ★
#案例1:查詢前五條員工信息


SELECT * FROM  employees LIMIT 0,5;
SELECT * FROM  employees LIMIT 5;


#案例2:查詢第11條——第25條
SELECT * FROM  employees LIMIT 10,15;#11到25


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


6.9 聯合查詢

union 聯合 合併:將多條查詢語句的結果合併成一個結果

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

應用場景:
要查詢的結果來自於多個表,且多個表沒有直接的連接關係,但查詢的信息一致時

特點:★
1、要求多條查詢語句的查詢列數是一致的!
2、要求多條查詢語句的查詢的每一列的類型和順序最好一致
3、union關鍵字默認去重,如果使用union all 可以包含重複項

#進階9:聯合查詢
#引入的案例:查詢部門編號>90或郵箱包含a的員工信息

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

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


#案例:查詢中國用戶中男性的信息以及外國用戶中年男性的用戶信息

SELECT id,cname FROM t_ca WHERE csex='男'
UNION ALL
SELECT t_id,tname FROM t_ua WHERE tGender='male';

7.DML語言

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

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

*/
SELECT * FROM beauty;
#1.插入的值的類型要與列的類型一致或兼容
INSERT INTO beauty(id,NAME,sex,borndate,phone,photo,boyfriend_id)
VALUES(14,'唐藝昕2','女','1990-4-23','1898888888',NULL,2);

#2.不可以爲null的列必須插入值。可以爲null的列如何插入值?
#方式一:
INSERT INTO beauty(id,NAME,sex,borndate,phone,photo,boyfriend_id)
VALUES(13,'唐藝昕','女','1990-4-23','1898888888',NULL,2);

#方式二:

INSERT INTO beauty(id,NAME,sex,phone)
VALUES(15,'娜扎','女','1388888888');


#3.列的順序是否可以調換
INSERT INTO beauty(NAME,sex,id,phone)
VALUES('蔣欣','女',16,'110');


#4.列數和值的個數必須一致

INSERT INTO beauty(NAME,sex,id,phone)
VALUES('關曉彤','女',17,'110');

#5.可以省略列名,默認所有列,而且列的順序和表中列的順序一致

INSERT INTO beauty
VALUES(18,'張飛','男',NULL,'119',NULL,NULL);

#方式二:
/*

語法:
insert into 表名
set 列名=值,列名=值,...
*/


INSERT INTO beauty
SET id=19,NAME='劉濤',phone='999';


#兩種方式大pk ★


#1、方式一支持插入多行,方式二不支持

INSERT INTO beauty
VALUES(23,'唐藝昕1','女','1990-4-23','1898888888',NULL,2)
,(24,'唐藝昕2','女','1990-4-23','1898888888',NULL,2)
,(25,'唐藝昕3','女','1990-4-23','1898888888',NULL,2);

#2、方式一支持子查詢,方式二不支持

INSERT INTO beauty(id,NAME,phone)
SELECT 26,'宋茜','11809866';

INSERT INTO beauty(id,NAME,phone)
SELECT id,boyname,'1234567'
FROM boys WHERE id<3;

#二、修改語句

/*

1.修改單表的記錄★

語法:
update 表名
set 列=新值,列=新值,...
where 篩選條件;

2.修改多表的記錄【補充】

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

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


*/


#1.修改單表的記錄
#案例1:修改beauty表中姓唐的女神的電話爲13899888899

UPDATE beauty SET phone = '13899888899'
WHERE NAME LIKE '唐%';

#案例2:修改boys表中id好爲2的名稱爲張飛,魅力值 10
UPDATE boys SET boyname='張飛',usercp=10
WHERE id=2;



#2.修改多表的記錄

#案例 1:修改張無忌的女朋友的手機號爲114

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



#案例2:修改沒有男朋友的女神的男朋友編號都爲2號

UPDATE boys bo
RIGHT JOIN beauty b ON bo.`id`=b.`boyfriend_id`
SET b.`boyfriend_id`=2
WHERE bo.`id` IS NULL;

SELECT * FROM boys;


#三、刪除語句
/*

方式一: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 表名;

*/

#方式一:delete
#1.單表的刪除
#案例:刪除手機號以9結尾的女神信息

DELETE FROM beauty WHERE `name` LIKE "柳巖";
SELECT * FROM beauty;


#2.多表的刪除

#案例:刪除張無忌的女朋友的信息

DELETE b   #只刪除beauty表
FROM beauty b
INNER JOIN boys bo ON b.`boyfriend_id` = bo.`id`
WHERE bo.`boyName`='張無忌';


#案例:刪除黃曉明的信息以及他女朋友的信息
DELETE b,bo   #兩個表都刪
FROM beauty b
INNER JOIN boys bo ON b.`boyfriend_id`=bo.`id`
WHERE bo.`boyName`='黃曉明';



#方式二:truncate語句

#案例:將魅力值>100的男神信息刪除
TRUNCATE TABLE boys ;



#delete pk truncate【面試題★】

/*

1.delete 可以加where 條件,truncate不能加

2.truncate刪除,效率高一丟丟
3.假如要刪除的表中有自增長列,
如果用delete刪除後,再插入數據,自增長列的值從斷點開始,
而truncate刪除後,再插入數據,自增長列的值從1開始。
4.truncate刪除沒有返回值,delete刪除有返回值

5.truncate刪除不能回滾,delete刪除可以回滾.

*/

SELECT * FROM boys;

DELETE FROM boys;
TRUNCATE TABLE boys;
INSERT INTO boys (boyname,usercp)
VALUES('張飛',100),('劉備',100),('關雲長',100);


8.DDL語言

數據定義語言

8.1 庫和表的管理

一、庫的管理
創建、修改、刪除
二、表的管理
創建、修改、刪除

創建: create
修改: alter
刪除: drop

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


#案例:創建庫Books

CREATE DATABASE IF NOT EXISTS books ;


#2、庫的修改

RENAME DATABASE books TO 新庫名;

#更改庫的字符集

ALTER DATABASE books CHARACTER SET gbk;


#3、庫的刪除

DROP DATABASE IF EXISTS books;




#二、表的管理
#1.表的創建 ★

/*
語法:
create table 表名(
	列名 列的類型【(長度) 約束】,
	列名 列的類型【(長度) 約束】,
	列名 列的類型【(長度) 約束】,
	...
	列名 列的類型【(長度) 約束】


)


*/
#案例:創建表Book

CREATE TABLE book(
	id INT,#編號
	bName VARCHAR(20),#圖書名
	price DOUBLE,#價格
	authorId  INT,#作者編號
	publishDate DATETIME#出版日期



);


DESC book;

#案例:創建表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 book CHANGE COLUMN publishdate pubDate DATETIME;


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

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

#④刪除列

ALTER TABLE book_author DROP COLUMN  annual;
#⑤修改表名

ALTER TABLE author RENAME TO book_author;

DESC book;




#3.表的刪除

DROP TABLE IF EXISTS book_author;

SHOW TABLES;


#通用的寫法:

DROP DATABASE IF EXISTS 舊庫名;
CREATE DATABASE 新庫名;


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



#4.表的複製

INSERT INTO author VALUES
(1,'村上春樹','日本'),
(2,'莫言','中國'),
(3,'馮唐','中國'),
(4,'金庸','中國');

SELECT * FROM Author;
SELECT * FROM copy2;
#1.僅僅複製表的結構

CREATE TABLE copy LIKE author;

#2.複製表的結構+數據
CREATE TABLE copy2 
SELECT * FROM author;

#只複製部分數據
CREATE TABLE copy3
SELECT id,au_name
FROM author 
WHERE nation='中國';


#僅僅複製某些字段

CREATE TABLE copy4 
SELECT id,au_name
FROM author
WHERE 0;

8.2數據類型

常見的數據類型
數值型:
整型
小數:
定點數
浮點數
字符型:
較短的文本:char、varchar
較長的文本:text、blob(較長的二進制數據)

日期型:

8.2.1 整型

分類:
tinyint、smallint、mediumint、int/integer、bigint
1 2 3 4 8

特點:
① 如果不設置無符號還是有符號,默認是有符號,如果想設置無符號,需要添加unsigned關鍵字
② 如果插入的數值超出了整型的範圍,會報out of range異常,並且插入臨界值
③ 如果不設置長度,會有默認的長度
長度代表了顯示的最大寬度,如果不夠會用0在左邊填充,但必須搭配zerofill使用!


#1.如何設置無符號和有符號

DROP TABLE IF EXISTS tab_int;
CREATE TABLE tab_int(
	t1 INT(7) ZEROFILL,
	t2 INT(7) ZEROFILL 

);

DESC tab_int;


INSERT INTO tab_int VALUES(-123456);
INSERT INTO tab_int VALUES(-123456,-123456);
INSERT INTO tab_int VALUES(2147483648,4294967296);

INSERT INTO tab_int VALUES(123,123);


SELECT * FROM tab_int;

8.2.2 小數

分類:
1.浮點型
float(M,D)
double(M,D)
2.定點型
dec(M,D)
decimal(M,D)

特點:


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


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

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

#測試M和D

DROP TABLE tab_float;
CREATE TABLE tab_float(
	f1 FLOAT,
	f2 DOUBLE,
	f3 DECIMAL
);
SELECT * FROM tab_float;
DESC tab_float;

INSERT INTO tab_float VALUES(123.4523,123.4523,123.4523);
INSERT INTO tab_float VALUES(123.456,123.456,123.456);
INSERT INTO tab_float VALUES(123.4,123.4,123.4);
INSERT INTO tab_float VALUES(1523.4,1523.4,1523.4);



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

*/

8.2.3 字符型

較短的文本:

char
varchar

其他:

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

較長的文本:
text
blob(較大的二進制)

特點:

寫法

M的意思 特點 空間的耗費 效率
char char(M) 最大的字符數,可以省略,默認爲1 固定長度的字符 比較耗費 高
varchar varchar(M) 最大的字符數,不可以省略 可變長度的字符 比較節省 低

CREATE TABLE tab_char(
	c1 ENUM('a','b','c')


);


INSERT INTO tab_char VALUES('a');
INSERT INTO tab_char VALUES('b');
INSERT INTO tab_char VALUES('c');
INSERT INTO tab_char VALUES('m');
INSERT INTO tab_char VALUES('A');

SELECT * FROM tab_set;



CREATE TABLE tab_set(

	s1 SET('a','b','c','d')



);
INSERT INTO tab_set VALUES('a');
INSERT INTO tab_set VALUES('A,B');
INSERT INTO tab_set VALUES('a,c,d');

8.2.4 日期型

分類:
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;


SHOW VARIABLES LIKE 'time_zone';

SET time_zone='+9:00';


8.3 常見約束

含義:一種限制,用於限制表中的數據,爲了保證表中的數據的準確和可靠性

分類:六大約束

  • NOT NULL:非空,用於保證該字段的值不能爲空 比如姓名、學號等

  • DEFAULT:默認,用於保證該字段有默認值 比如性別

  • PRIMARY KEY:主鍵,用於保證該字段的值具有唯一性,並且非空比如學號、員工編號等

  • UNIQUE:唯一,用於保證該字段的值具有唯一性,可以爲空 比如座位號

  • CHECK:檢查約束【mysql中不支持】 比如年齡、性別

  • FOREIGN KEY:外鍵,用於限制兩個表的關係,用於保證該字段的值必須來自於主表的關聯列的值在從表添加外鍵約束,用於引用主表中某列的值
    比如學生表的專業編號,員工表的部門編號,員工表的工種編號

添加約束的時機:

  • 1.創建表時

  • 2.修改表時

約束的添加分類:

  1. 列級約束:

    六大約束語法上都支持,但外鍵約束沒有效果
    
  2. 表級約束:

    除了非空、默認,其他的都支持
    

主鍵和唯一的大對比:

保證唯一性 是否允許爲空 一個表中可以有多少個 是否允許組合
主鍵 × 至多有1個 √,但不推薦
唯一 可以有多個 √,但不推薦

外鍵:

  • 1、要求在從表設置外鍵關係

  • 2、從表的外鍵列的類型和主表的關聯列的類型要求一致或兼容,名稱無要求

  • 3、主表的關聯列必須是一個key(一般是主鍵或唯一)

  • 4、插入數據時,先插入主表,再插入從表 刪除數據時,先刪除從表,再刪除主表

#常見約束



CREATE TABLE 表名(
	字段名 字段類型 列級約束,
	字段名 字段類型,
	表級約束

)
CREATE DATABASE students;
#一、創建表時添加約束

#1.添加列級約束
/*
語法:

直接在字段名和類型後面追加 約束類型即可。

只支持:默認、非空、主鍵、唯一



*/

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

);


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

#查看stuinfo中的所有索引,包括主鍵、外鍵、唯一
SHOW INDEX FROM stuinfo;


#2.添加表級約束
/*

語法:在各個字段的最下面
 【constraint 約束名】 約束類型(字段名) 
*/

DROP TABLE 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 IF NOT EXISTS stuinfo(
	id INT PRIMARY KEY,
	stuname VARCHAR(20),
	sex CHAR(1),
	age INT DEFAULT 18,
	seat INT UNIQUE,
	majorid INT,
	CONSTRAINT fk_stuinfo_major FOREIGN KEY(majorid) REFERENCES major(id)

);



#二、修改表時添加約束

/*
1、添加列級約束
alter table 表名 modify column 字段名 字段類型 新約束;

2、添加表級約束
alter table 表名 add 【constraint 約束名】 約束類型(字段名) 【外鍵的引用】;


*/
DROP TABLE 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);

#4.添加唯一

#①列級約束
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 DROP PRIMARY KEY;

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

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

SHOW INDEX FROM stuinfo;


案例:

#1.向表emp2的id列中添加PRIMARY KEY約束(my_emp_id_pk)

ALTER TABLE emp2 MODIFY COLUMN id INT PRIMARY KEY;
ALTER TABLE emp2 ADD CONSTRAINT my_emp_id_pk PRIMARY KEY(id);

#2.	向表dept2的id列中添加PRIMARY KEY約束(my_dept_id_pk)

#3.	向表emp2中添加列dept_id,並在其中定義FOREIGN KEY約束,與之相關聯的列是dept2表中的id列。
ALTER TABLE emp2 ADD COLUMN dept_id INT;
ALTER TABLE emp2 ADD CONSTRAINT fk_emp2_dept2 FOREIGN KEY(dept_id) REFERENCES dept2(id);

		          位置		  支持的約束類型			  是否可以起約束名
列級約束:	    列的後面	  	語法都支持,但外鍵沒有效果		不可以
表級約束:	  所有列的下面	默認和非空不支持,其他支持		可以(主鍵沒有效果)

8.4 標識列

又稱爲自增長列
含義:可以不用手動的插入值,系統提供默認的序列值

特點:

  1. 標識列必須和主鍵搭配嗎?不一定,但要求是一個key
  2. 一個表可以有幾個標識列?至多一個!
  3. 標識列的類型只能是數值型
  4. 標識列可以通過 SET auto_increment_increment=3;設置步長 可以通過 手動插入值,設置起始值
#標識列

#一、創建表時設置標識列


DROP TABLE IF EXISTS tab_identity;
CREATE TABLE tab_identity(
	id INT  ,
	NAME FLOAT UNIQUE AUTO_INCREMENT,
	seat INT 


);
TRUNCATE TABLE tab_identity;


INSERT INTO tab_identity(id,NAME) VALUES(NULL,'john');
INSERT INTO tab_identity(NAME) VALUES('lucy');
SELECT * FROM tab_identity;


SHOW VARIABLES LIKE '%auto_increment%';


SET auto_increment_increment=3;

9.TCL語言

Transaction Control Language 事務控制語言

事務

事務:

一個或一組sql語句組成一個執行單元,這個執行單元要麼全部執行,要麼全部不執行。

案例:轉賬

張三丰 1000 郭襄 1000

update 表 set 張三丰的餘額=500 where name=‘張三丰’ 意外 update 表 set 郭襄的餘額=1500
where name=‘郭襄’

事務的特性:
ACID

  • 原子性:一個事務不可再分割,要麼都執行要麼都不執行
  • 一致性:一個事務執行會使數據從一個一致狀態切換到另外一個一致狀態
  • 隔離性:一個事務的執行不受其他事務的干擾
  • 持久性:一個事務一旦提交,則會永久的改變數據庫的數據.

事務的創建

  • 隱式事務:事務沒有明顯的開啓和結束的標記 比如insert、update、delete語句

    delete from 表 where id =1;

  • 顯式事務:事務具有明顯的開啓和結束的標記 前提:必須先設置自動提交功能爲禁用

    set autocommit=0;

    步驟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

查看隔離級別 select @@tx_isolation;
設置隔離級別 set session|global transaction
isolation level 隔離級別;

開啓事務的語句;
update 表 set 張三丰的餘額=500 where name=‘張三丰’

update 表 set 郭襄的餘額=1500 where name=‘郭襄’
結束事務的語句;

#TCL

SHOW VARIABLES LIKE 'autocommit';
SHOW ENGINES;

#1.演示事務的使用步驟

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

#結束事務
ROLLBACK;
#commit;

SELECT * FROM account;

#2.演示事務對於delete和truncate的處理的區別

SET autocommit=0;
START TRANSACTION;

DELETE FROM account;
ROLLBACK;


#3.演示savepoint 的使用
SET autocommit=0;
START TRANSACTION;
DELETE FROM account WHERE id=25;
SAVEPOINT a;#設置保存點
DELETE FROM account WHERE id=28;
ROLLBACK TO a;#回滾到保存點

SELECT * FROM account;

10.視圖

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

比如:舞蹈班和普通班級的對比
創建語法的關鍵字 是否實際佔用物理空間 使用

視圖 create view 只是保存了sql邏輯 增刪改查,只是一般不能增刪改
create table 保存了數據 增刪改查

#案例:查詢姓張的學生名和專業名
SELECT stuname,majorname
FROM stuinfo s
INNER JOIN major m ON s.`majorid`= m.`id`
WHERE s.`stuname` LIKE '張%';

CREATE VIEW v1
AS
SELECT stuname,majorname
FROM stuinfo s
INNER JOIN major m ON s.`majorid`= m.`id`;

SELECT * FROM v1 WHERE stuname LIKE '張%';


#一、創建視圖
/*
語法:
create view 視圖名
as
查詢語句;

*/
USE myemployees;

#1.查詢姓名中包含a字符的員工名、部門名和工種信息
#①創建
CREATE VIEW myv1
AS

SELECT last_name,department_name,job_title
FROM employees e
JOIN departments d ON e.department_id  = d.department_id
JOIN jobs j ON j.job_id  = e.job_id;


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






#2.查詢各部門的平均工資級別

#①創建視圖查看每個部門的平均工資
CREATE VIEW myv2
AS
SELECT AVG(salary) ag,department_id
FROM employees
GROUP BY department_id;

#②使用
SELECT myv2.`ag`,g.grade_level
FROM myv2
JOIN job_grades g
ON myv2.`ag` BETWEEN g.`lowest_sal` AND g.`highest_sal`;



#3.查詢平均工資最低的部門信息

SELECT * FROM myv2 ORDER BY ag LIMIT 1;

#4.查詢平均工資最低的部門名和工資

CREATE VIEW myv3
AS
SELECT * FROM myv2 ORDER BY ag LIMIT 1;


SELECT d.*,m.ag
FROM myv3 m
JOIN departments d
ON m.`department_id`=d.`department_id`;




#二、視圖的修改

#方式一:
/*
create or replace view  視圖名
as
查詢語句;

*/
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 emp_v1,emp_v2,myv3;


#四、查看視圖

DESC myv3;

SHOW CREATE VIEW myv3;


#五、視圖的更新

CREATE OR REPLACE VIEW myv1
AS
SELECT last_name,email,salary*12*(1+IFNULL(commission_pct,0)) "annual salary"
FROM employees;

CREATE OR REPLACE VIEW myv1
AS
SELECT last_name,email
FROM employees;


SELECT * FROM myv1;
SELECT * FROM employees;
#1.插入

INSERT INTO myv1 VALUES('張飛','[email protected]');

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

#3.刪除
DELETE FROM myv1 WHERE last_name = '張無忌';

#具備以下特點的視圖不允許更新


#①包含以下關鍵字的sql語句:分組函數、distinct、group  by、having、union或者union all

CREATE OR REPLACE VIEW myv1
AS
SELECT MAX(salary) m,department_id
FROM employees
GROUP BY department_id;

SELECT * FROM myv1;

#更新
UPDATE myv1 SET m=9000 WHERE department_id=10;

#②常量視圖
CREATE OR REPLACE VIEW myv2
AS

SELECT 'john' NAME;

SELECT * FROM myv2;

#更新
UPDATE myv2 SET NAME='lucy';





#③Select中包含子查詢

CREATE OR REPLACE VIEW myv3
AS

SELECT department_id,(SELECT MAX(salary) FROM employees) 最高工資
FROM departments;

#更新
SELECT * FROM myv3;
UPDATE myv3 SET 最高工資=100000;


#④join
CREATE OR REPLACE VIEW myv4
AS

SELECT last_name,department_name
FROM employees e
JOIN departments d
ON e.department_id  = d.department_id;

#更新

SELECT * FROM myv4;
UPDATE myv4 SET last_name  = '張飛' WHERE last_name='Whalen';
INSERT INTO myv4 VALUES('陳真','xxxx');



#⑤from一個不能更新的視圖
CREATE OR REPLACE VIEW myv5
AS

SELECT * FROM myv3;

#更新

SELECT * FROM myv5;

UPDATE myv5 SET 最高工資=10000 WHERE department_id=60;



#⑥where子句的子查詢引用了from子句中的表

CREATE OR REPLACE VIEW myv6
AS

SELECT last_name,email,salary
FROM employees
WHERE employee_id IN(
	SELECT  manager_id
	FROM employees
	WHERE manager_id IS NOT NULL
);

#更新
SELECT * FROM myv6;
UPDATE myv6 SET salary=10000 WHERE last_name = 'k_ing';


視圖案例

#一、創建視圖emp_v1,要求查詢電話號碼以‘011’開頭的員工姓名和工資、郵箱

CREATE OR REPLACE VIEW emp_v1
AS
SELECT last_name,salary,email
FROM employees
WHERE phone_number LIKE '011%';

#二、創建視圖emp_v2,要求查詢部門的最高工資高於12000的部門信息

CREATE OR REPLACE VIEW emp_v2
AS
SELECT MAX(salary) mx_dep,department_id
FROM employees
GROUP BY department_id
HAVING MAX(salary)>12000;


SELECT d.*,m.mx_dep
FROM departments d
JOIN emp_v2 m
ON m.department_id = d.`department_id`;

11.變量

分類

  • 系統變量: 全局變量 會話變量
  • 自定義變量: 用戶變量 局部變量

系統變量

說明:變量由系統定義,不是用戶定義,屬於服務器層面
注意:全局變量需要添加global關鍵字,會話變量需要添加session關鍵字,如果不寫,默認會話級別 使用步驟:
1、查看所有系統變量
show global|【session】variables;
2、查看滿足條件的部分系統變量
show global|【session】
variables like '%char%';
3、查看指定的系統變量的值
select @@global|【session】系統變量名;
4、爲某個系統變量賦值
方式一: set global|【session】系統變量名=值;
方式二: set @@global|【session】系統變量名=值;
¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥
分類一全局變量:
作用域:針對於所有會話(連接)有效,但不能跨重啓
分類二局部變量:
作用域:針對於當前會話(連接)有效

自定義變量

說明:變量由用戶自定義,而不是系統提供的
使用步驟:
1、聲明
2、賦值
3、使用(查看、比較、運算等)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
分類一用戶變量
作用域:針對於當前會話(連接)有效,作用域同於會話變量
分類二局部變量
作用域:僅僅在定義它的begin end塊中有效

#一系統變量
#①查看所有全局變量
SHOW GLOBAL VARIABLES;
#②查看滿足條件的部分系統變量
SHOW GLOBAL VARIABLES LIKE '%char%';
#③查看指定的系統變量的值
SELECT @@global.autocommit;
#④爲某個系統變量賦值
SET @@global.autocommit=0;
SET GLOBAL autocommit=0;

#2》會話變量
/*
作用域:針對於當前會話(連接)有效
*/
#①查看所有會話變量
SHOW SESSION VARIABLES;
#②查看滿足條件的部分會話變量
SHOW SESSION VARIABLES LIKE '%char%';
#③查看指定的會話變量的值
SELECT @@autocommit;
SELECT @@session.tx_isolation;
#④爲某個會話變量賦值
SET @@session.tx_isolation='read-uncommitted';
SET SESSION tx_isolation='read-committed';

#二、自定義變量

#1》用戶變量

#賦值操作符:=或:=
#①聲明並初始化
SET @變量名=;
SET @變量名:=;
SELECT @變量名:=;

#②賦值(更新變量的值)
#方式一:
	SET @變量名=;
	SET @變量名:=;
	SELECT @變量名:=;
#方式二:
	SELECT 字段 INTO @變量名
	FROM;
#③使用(查看變量的值)
SELECT @變量名;


#2》局部變量
#①聲明
DECLARE 變量名 類型;
DECLARE 變量名 類型 【DEFAULT 值】;


#②賦值(更新變量的值)

#方式一:
	SET 局部變量名=;
	SET 局部變量名:=;
	SELECT 局部變量名:=;
#方式二:
	SELECT 字段 INTO 具備變量名
	FROM;
#③使用(查看變量的值)
SELECT 局部變量名;


#案例:聲明兩個變量,求和並打印

#用戶變量
SET @m=1;
SET @n=1;
SET @sum=@m+@n;
SELECT @sum;

#局部變量
DECLARE m INT DEFAULT 1;
DECLARE n INT DEFAULT 1;
DECLARE SUM INT;
SET SUM=m+n;
SELECT SUM;


#用戶變量和局部變量的對比

		作用域			定義位置		語法
用戶變量	當前會話		會話的任何地方		加@符號,不用指定類型
局部變量	定義它的BEGIN ENDBEGIN END的第一句話	一般不用加@,需要指定類型
			





12.存儲過程和函數

存儲過程和函數:類似於java中的方法

好處:
1、提高代碼的重用性
2、簡化操作

12.1 存儲過程

含義:一組預先編譯好的SQL語句的集合,理解成批處理語句
1、提高代碼的重用性
2、簡化操作
3、減少了編譯次數並且減少了和數據庫服務器的連接次數,提高了效率
4、創建

CREATE PROCEDURE 存儲過程名(參數列表)
BEGIN

	存儲過程體(一組合法的SQL語句)
END

5、注意

  • 1、參數列表包含三部分 參數模式 參數名 參數類型 舉例: in stuname varchar(20)

    參數模式:
    in:該參數可以作爲輸入,也就是該參數需要調用方傳入值
    out:該參數可以作爲輸出,也就是該參數可以作爲返回值
    inout:該參數既可以作爲輸入又可以作爲輸出,也就是該參數既需要傳入值,又可以返回值

  • 2、如果存儲過程體僅僅只有一句話,begin end可以省略 存儲過程體中的每條sql語句的結尾要求必須加分號。
    存儲過程的結尾可以使用
    delimiter 重新設置 語法: delimiter 結束標記 案例: delimiter $

6、調用

CALL 存儲過程名(實參列表);
#存儲過程和函數

#存儲過程

#一、創建語法

CREATE PROCEDURE 存儲過程名(參數列表)
BEGIN

	存儲過程體(一組合法的SQL語句)
END




#二、調用語法

CALL 存儲過程名(實參列表);

#--------------------------------案例演示-----------------------------------
#1.空參列表
#案例:插入到admin表中五條記錄

SELECT * FROM admin;

DELIMITER $
CREATE PROCEDURE myp1()
BEGIN
	INSERT INTO admin(username,`password`) 
	VALUES('john1','0000'),('lily','0000'),('rose','0000'),('jack','0000'),('tom','0000');
END $


#調用
DELIMITER $
CALL myp1()$

#2.創建帶in模式參數的存儲過程

#案例1:創建存儲過程實現 根據女神名,查詢對應的男神信息

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('柳巖')$

#案例2 :創建存儲過程實現,用戶是否登錄成功

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 myp3('張飛','8888')$


#3.創建out 模式參數的存儲過程
#案例1:根據輸入的女神名,返回對應的男神名

CREATE PROCEDURE myp6(IN beautyName VARCHAR(20),OUT boyName VARCHAR(20))
BEGIN
	SELECT bo.boyname INTO boyname
	FROM boys bo
	RIGHT JOIN
	beauty b ON b.boyfriend_id = bo.id
	WHERE b.name=beautyName ;
	
END $


#案例2:根據輸入的女神名,返回對應的男神名和魅力值

CREATE PROCEDURE myp7(IN beautyName VARCHAR(20),OUT boyName VARCHAR(20),OUT usercp INT) 
BEGIN
	SELECT boys.boyname ,boys.usercp INTO boyname,usercp
	FROM boys 
	RIGHT JOIN
	beauty b ON b.boyfriend_id = boys.id
	WHERE b.name=beautyName ;
	
END $


#調用
CALL myp7('小昭',@name,@cp)$
SELECT @name,@cp$



#4.創建帶inout模式參數的存儲過程
#案例1:傳入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 p1;
DROP PROCEDURE p2,p3;

#四、查看存儲過程的信息
DESC myp2;×
SHOW CREATE PROCEDURE  myp2;
存儲案例:
#一、創建存儲過程實現傳入用戶名和密碼,插入到admin表中

CREATE PROCEDURE test_pro1(IN username VARCHAR(20),IN loginPwd VARCHAR(20))
BEGIN
	INSERT INTO admin(admin.username,PASSWORD)
	VALUES(username,loginpwd);
END $

#二、創建存儲過程實現傳入女神編號,返回女神名稱和女神電話

CREATE PROCEDURE test_pro2(IN id INT,OUT NAME VARCHAR(20),OUT phone VARCHAR(20))

BEGIN
	SELECT b.name ,b.phone INTO NAME,phone
	FROM beauty b
	WHERE b.id = id;

END $
#三、創建存儲存儲過程或函數實現傳入兩個女神生日,返回大小

CREATE PROCEDURE test_pro3(IN birth1 DATETIME,IN birth2 DATETIME,OUT result INT)
BEGIN
	SELECT DATEDIFF(birth1,birth2) INTO result;
END $
#四、創建存儲過程或函數實現傳入一個日期,格式化成xx年xx月xx日並返回
CREATE PROCEDURE test_pro4(IN mydate DATETIME,OUT strDate VARCHAR(50))
BEGIN
	SELECT DATE_FORMAT(mydate,'%y年%m月%d日') INTO strDate;
END $

CALL test_pro4(NOW(),@str)$
SELECT @str $

#五、創建存儲過程或函數實現傳入女神名稱,返回:女神 and 男神  格式的字符串
如 傳入 :小昭
返回: 小昭 AND 張無忌
DROP PROCEDURE test_pro5 $
CREATE PROCEDURE test_pro5(IN beautyName VARCHAR(20),OUT str VARCHAR(50))
BEGIN
	SELECT CONCAT(beautyName,' and ',IFNULL(boyName,'null')) INTO str
	FROM boys bo
	RIGHT JOIN beauty b ON b.boyfriend_id = bo.id
	WHERE b.name=beautyName;
	
	
	SET str=
END $

CALL test_pro5('柳巖',@str)$
SELECT @str $



#六、創建存儲過程或函數,根據傳入的條目數和起始索引,查詢beauty表的記錄
DROP PROCEDURE test_pro6$
CREATE PROCEDURE test_pro6(IN startIndex INT,IN size INT)
BEGIN
	SELECT * FROM beauty LIMIT startIndex,size;
END $

CALL test_pro6(3,5)$

12.2 函數

含義:一組預先編譯好的SQL語句的集合,理解成批處理語句

  1. 提高代碼的重用性
  2. 簡化操作
  3. 減少了編譯次數並且減少了和數據庫服務器的連接次數,提高了效率

區別:

存儲過程:可以有0個返回,也可以有多個返回,適合做批量插入、批量更新
函數:有且僅有1 個返回,適合做處理數據後返回一個結果

創建語法

CREATE FUNCTION 函數名(參數列表) RETURNS 返回類型
BEGIN
	函數體
END

注意:

  1. 參數列表 包含兩部分: 參數名 參數類型
  2. 函數體:肯定會有return語句,如果沒有會報錯。如果return語句沒有放在函數體的最後也不報錯,但不建議
    return 值;
  3. 函數體中僅有一句話,則可以省略begin end
  4. 使用 delimiter語句設置結束標記

調用語法

SELECT 函數名(參數列表)
#函數

#------------------------------案例演示----------------------------
#1.無參有返回
#案例:返回公司的員工個數
CREATE FUNCTION myf1() RETURNS INT
BEGIN

	DECLARE c INT DEFAULT 0;#定義局部變量
	SELECT COUNT(*) INTO c#賦值
	FROM employees;
	RETURN c;
	
END $

SELECT myf1()$


#2.有參有返回
#案例1:根據員工名,返回它的工資

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('k_ing') $

#案例2:根據部門名,返回該部門的平均工資

CREATE FUNCTION myf3(deptName VARCHAR(20)) RETURNS DOUBLE
BEGIN
	DECLARE sal DOUBLE ;
	SELECT AVG(salary) INTO sal
	FROM employees e
	JOIN departments d ON e.department_id = d.department_id
	WHERE d.department_name=deptName;
	RETURN sal;
END $

SELECT myf3('IT')$

#三、查看函數

SHOW CREATE FUNCTION myf3;

#四、刪除函數
DROP FUNCTION myf3;

#案例
#一、創建函數,實現傳入兩個float,返回二者之和

CREATE FUNCTION test_fun1(num1 FLOAT,num2 FLOAT) RETURNS FLOAT
BEGIN
	DECLARE SUM FLOAT DEFAULT 0;
	SET SUM=num1+num2;
	RETURN SUM;
END $

SELECT test_fun1(1,2)$

13.流程控制結構

流程控制結構

順序、分支、循環

一、分支結構
1.if函數

語法:if(條件,值1,值2)
功能:實現雙分支
應用在begin end中或外面

2.case結構

語法:
情況1:

類似於
switch
case 變量或表達式
when1 then 語句1;
when2 then 語句2;
...
else 語句n;
end 

情況2:

case 
when 條件1 then 語句1;
when 條件2 then 語句2;
...
else 語句n;
end 

應用在begin end 中或外面
3.if結構

語法:

if 條件1 then 語句1;
elseif 條件2 then 語句2;
....
else 語句n;
end if;
功能:類似於多重if

只能應用在begin end
二、循環

分類:

while、loop、repeat

循環控制:

iterate類似於 continue,繼續,結束本次循環,繼續下一次
leave 類似於 break,跳出,結束當前所在的循環

1.while

語法:

【標籤:】while 循環條件 do
	循環體;
end while【 標籤】;

聯想:

while(循環條件){

	循環體;
}
2.loop

語法:


【標籤:】loop
	循環體;
end loop 【標籤】;

可以用來模擬簡單的死循環
3.repeat
語法:
【標籤:】repeat
	循環體;
until 結束循環的條件
end repeat 【標籤】;
案例

#案例1:創建函數,實現傳入成績,如果成績>90,返回A,如果成績>80,返回B,如果成績>60,返回C,否則返回D

CREATE FUNCTION test_if(score FLOAT) RETURNS CHAR
BEGIN
	DECLARE ch CHAR DEFAULT 'A';
	IF score>90 THEN SET ch='A';
	ELSEIF score>80 THEN SET ch='B';
	ELSEIF score>60 THEN SET ch='C';
	ELSE SET ch='D';
	END IF;
	RETURN ch;
	
	
END $

SELECT test_if(87)$

#案例2:創建存儲過程,如果工資<2000,則刪除,如果5000>工資>2000,則漲工資1000,否則漲工資500


CREATE PROCEDURE test_if_pro(IN sal DOUBLE)
BEGIN
	IF sal<2000 THEN DELETE FROM employees WHERE employees.salary=sal;
	ELSEIF sal>=2000 AND sal<5000 THEN UPDATE employees SET salary=salary+1000 WHERE employees.`salary`=sal;
	ELSE UPDATE employees SET salary=salary+500 WHERE employees.`salary`=sal;
	END IF;
	
END $

CALL test_if_pro(2100)$

#案例1:創建函數,實現傳入成績,如果成績>90,返回A,如果成績>80,返回B,如果成績>60,返回C,否則返回D

CREATE FUNCTION test_case(score FLOAT) RETURNS CHAR
BEGIN 
	DECLARE ch CHAR DEFAULT 'A';
	
	CASE 
	WHEN score>90 THEN SET ch='A';
	WHEN score>80 THEN SET ch='B';
	WHEN score>60 THEN SET ch='C';
	ELSE SET ch='D';
	END CASE;
	
	RETURN ch;
END $

SELECT test_case(56)$



#二、循環結構


#1.沒有添加循環控制語句
#案例:批量插入,根據次數插入到admin表中多條記錄
DROP PROCEDURE pro_while1$
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)$


/*

int i=1;
while(i<=insertcount){

	//插入
	
	i++;

}

*/


#2.添加leave語句

#案例:批量插入,根據次數插入到admin表中多條記錄,如果次數>20則停止
TRUNCATE TABLE admin$
DROP PROCEDURE test_while1$
CREATE PROCEDURE test_while1(IN insertCount INT)
BEGIN
	DECLARE i INT DEFAULT 1;
	a:WHILE i<=insertCount DO
		INSERT INTO admin(username,`password`) VALUES(CONCAT('xiaohua',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表中多條記錄,只插入偶數次
TRUNCATE TABLE admin$
DROP PROCEDURE test_while1$
CREATE PROCEDURE test_while1(IN insertCount INT)
BEGIN
	DECLARE i INT DEFAULT 0;
	a:WHILE i<=insertCount DO
		SET i=i+1;
		IF MOD(i,2)!=0 THEN ITERATE a;
		END IF;
		
		INSERT INTO admin(username,`password`) VALUES(CONCAT('xiaohua',i),'0000');
		
	END WHILE a;
END $


CALL test_while1(100)$

/*`在這裏插入代碼片`

int i=0;
while(i<=insertCount){
	i++;
	if(i%2==0){
		continue;
	}
	插入
	
}

*/

應用案例
/*一、已知表stringcontent
其中字段:
id 自增長
content varchar(20)

向該表插入指定個數的,隨機的字符串
*/
DROP TABLE IF EXISTS stringcontent;
CREATE TABLE stringcontent(
	id INT PRIMARY KEY AUTO_INCREMENT,
	content VARCHAR(20)
	
);
DELIMITER $
CREATE PROCEDURE test_randstr_insert(IN insertCount INT)
BEGIN
	DECLARE i INT DEFAULT 1;
	DECLARE str VARCHAR(26) DEFAULT 'abcdefghijklmnopqrstuvwxyz';
	DECLARE startIndex INT;#代表初始索引
	DECLARE len INT;#代表截取的字符長度
	WHILE i<=insertcount DO
		SET startIndex=FLOOR(RAND()*26+1);#代表初始索引,隨機範圍1-26
		SET len=FLOOR(RAND()*(20-startIndex+1)+1);#代表截取長度,隨機範圍1-(20-startIndex+1)
		INSERT INTO stringcontent(content) VALUES(SUBSTR(str,startIndex,len));
		SET i=i+1;
	END WHILE;

END $

CALL test_randstr_insert(10)$
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章