MySQL-基礎部分
目錄:
1.相關概念
DB:database資料庫,儲存一系列有組織資料的容器。
DBMS:Database Management System資料庫管理系統,使用DBMS管理和維護DB。
SQL:Structure Query Language結構化查詢語言,程式設計師用於和DBMS通訊互動的語言。
2.MySQL服務的登入和退出
方式一:通過dos命令
mysql -h主機名 -P埠號 -u使用者名稱 -p密碼
注意:
如果是本機,則-h主機名 可以省略
如果埠號是3306,則-P埠號可以省略
方式二:通過圖形化介面客戶端
通過sqlyog,直接輸入使用者名稱、密碼等連線進去即可
3.MySQL的常見命令和語法規範
2.(1)常見命令
show databases 顯示當前連線下所有資料庫
show tables 顯示當前庫中所有表
show tables from 庫名 顯示指定庫中所有表
show columns from 表名 顯示指定表中所有列
use 庫名 開啟/使用指定庫
(2)語法規範
① 不區分大小寫
② 每條命令結尾建議用分號
③Mysql在使用函式查詢時,函式名後面不能加空格
(3)註釋:
# 單行註釋
-- 單行註釋
/*多行註釋
多行註釋
*/
4.資料庫系統表明解名
SELECT 查詢列表
FROM 表名;
特點:
1、查詢的結果集 是一個虛擬表
2、SELECT後面跟的查詢列表,可以有多個部分組成,中間用逗號隔開
例如:SELECT 欄位1,欄位2,表示式
FROM 表;
3.查詢列表可以是:欄位、表示式、常量、函式等
4.執行順序 :
① FROM子句
② SELECT子句
基礎查詢案例:
一、查詢常量 SELECT 100 ; 二、查詢表示式SELECT 100%3; 三、查詢單個欄位 SELECT `last_name` FROM `employees`; 四、查詢多個欄位 SELECT `last_name`,`email`,`employee_id` FROM employees; 五、查詢所有欄位 SELECT * FROM `employees`; 六、查詢函式(呼叫函式,獲取返回值) SELECT DATABASE(); SELECT VERSION(); SELECT USER(); 七、起別名 方式一:使用AS關鍵字 SELECT USER() AS 使用者名稱; SELECT USER() AS "使用者名稱"; SELECT USER() AS '使用者名稱'; SELECT last_name AS "姓 名" FROM employees; 方式二:使用空格 SELECT USER() 使用者名稱; SELECT USER() "使用者名稱"; SELECT USER() '使用者名稱'; SELECT last_name "姓 名" FROM employees; 八、+的作用 mysql中+的作用: 1、加法運算 ①兩個運算元都是數值型 100+1.5 ②其中一個運算元為字元型 將字元型資料強制轉換成數值型,如果無法轉換,則直接當做0處理 '張無忌'+100--->100 ③其中一個運算元為NULL NULL+NULL--->NULL NULL+100--->NULL #需求:查詢 first_name 和last_name 拼接成的全名,最終起別名為:姓 名 使用CONCAT拼接函式 SELECT CONCAT(first_name,last_name) AS "姓 名" FROM employees; 九、DISTINCT的使用(只返回不同的值)
distinct可加多個欄位,只有當多個欄位全部一樣時才會去掉,有一個欄位內容不一樣都會保留 -- 需求:查詢員工涉及到的部門編號有哪些,不重複 SELECT DISTINCT department_id FROM employees; 十、查看錶的結構 ①、DESC employees; ②、SHOW COLUMNS FROM employees; 十一、F12快捷鍵對齊格式 SELECT `last_name`, `first_name`, `last_name`, `commission_pct`, `hiredate`, `salary` FROM employees ;
SELECT 查詢列表
FROM 表名
WHERE 篩選條件;
執行順序:
①FROM子句
②WHERE子句
③SELECT子句
案例:
#查詢工資大於20000的員工姓和名
SELECT last_name,first_name
FROM employees
WHERE salary>20000;
特點:
1.按關係表示式篩選
關係運算符:> 、<、 >=、 <=、 = 、<>(不等於)
#案例1:查詢部門編號不是100的員工資訊
SELECT *
FROM employees
WHERE department_id <> 100;
#案例2:查詢工資<15000的姓名、工資
SELECT last_name,salary
FROM employees
WHERE salary<15000;
2.按邏輯表示式篩選
邏輯運算子:AND 、OR、 NOT
#案例1:查詢部門編號不是 50-100之間員工姓名、部門編號、郵箱
方式1:
SELECT last_name,department_id,email
FROM employees
WHERE department_id <50 OR department_id>100;
方式2:
SELECT last_name,department_id,email
FROM employees
WHERE NOT(department_id>=50 AND department_id<=100);
#案例2:查詢獎金率>0.03 或者 員工編號在60-110之間的員工資訊
SELECT *
FROM employees
WHERE commission_pct>0.03 OR (employee_id >=60 AND employee_id<=110);
3.模糊查詢
LIKE、 IN 、BETWEEN AND、 IS NULL
(1)LIKE
功能:一般和萬用字元搭配使用,對字元型資料進行部分匹配查詢
常見的萬用字元:
_ 任意單個字元
% 任意多個字元,支援0-多個
LIKE / NOT LIKE
#案例1:查詢姓名中包含字元a的員工資訊
SELECT *
FROM employees
WHERE last_name LIKE '%a%';
#案例2:查詢姓名中包含最後一個字元為e的員工資訊
SELECT *
FROM employees
WHERE last_name LIKE '%e';
#案例3:查詢姓名中包含第一個字元為e的員工資訊
SELECT *
FROM employees
WHERE last_name LIKE 'e%';
#案例4:查詢姓名中包含第三個字元為x的員工資訊
SELECT *
FROM employees
WHERE last_name LIKE '__x%';
#案例5:查詢姓名中包含第二個字元為_的員工資訊
SELECT *
FROM employees
WHERE last_name LIKE '_\_%';(這裡的\為轉義符)
SELECT *
FROM employees
WHERE last_name LIKE '_$_%' ESCAPE '$';(ESCAPE表示將$作為轉義符)
(2)IN
功能:查詢某欄位的值是否屬於指定的列表之內
a IN(常量值1,常量值2,常量值3,...)
a NOT IN(常量值1,常量值2,常量值3,...)
IN / NOT IN
#案例1:查詢部門編號是30/50/90的員工名、部門編號
方式1:
SELECT last_name,department_id
FROM employees
WHERE department_id IN(30,50,90);
方式2:
SELECT last_name,department_id
FROM employees
WHERE department_id = 30
OR department_id = 50
OR department_id = 90;
案例2:查詢工種編號不是SH_CLERK或IT_PROG的員工資訊
#方式1:
SELECT *
FROM employees
WHERE job_id NOT IN('SH_CLERK','IT_PROG');
#方式2:
SELECT *
FROM employees
WHERE NOT(job_id ='SH_CLERK'OR job_id = 'IT_PROG');
(3) BETWEEN AND
功能:判斷某個欄位的值是否介於X,X之間
BETWEEN AND / NOT BETWEEN AND
#案例1:查詢部門編號是30-90之間的部門編號、員工姓名
方式1:
SELECT department_id,last_name
FROM employees
WHERE department_id BETWEEN 30 AND 90;
方式2:
SELECT department_id,last_name
FROM employees
WHERE department_id>=30 AND department_id<=90;
#案例2:查詢年薪不是100000-200000之間的員工姓名、工資、年薪
SELECT last_name,salary,salary*12*(1+IFNULL(commission_pct,0)) AS 年薪
#(IFNULL(引數1,引數2)表示如果引數1不是NULL,就顯示引數1,引數1是NULL,就顯示引數2)
FROM employees
WHERE salary*12*(1+IFNULL(commission_pct,0))<100000 OR salary*12*(1+IFNULL(commission_pct,0))>200000;
SELECT last_name,salary,salary*12*(1+IFNULL(commission_pct,0)) 年薪
FROM employees
WHERE salary*12*(1+IFNULL(commission_pct,0)) NOT BETWEEN 100000 AND 200000;
4.IS NULL / IS NOT NULL
功能:判斷欄位是否為空
#案例1:查詢沒有獎金的員工資訊
SELECT *
FROM employees
WHERE commission_pct IS NULL;
#案例2:查詢有獎金的員工資訊
SELECT *
FROM employees
WHERE commission_pct IS NOT NULL;
-------------- = 與 IS 的對比------------
= 只能判斷普通的內容
IS 只能判斷NULL值
<=> 安全等於,既能判斷普通內容,又能判斷NULL值,不建議用,閱讀性差
SELECT *
FROM employees
WHERE salary IS 10000;(報錯)
SELECT 查詢列表
FROM 表名
WHERE 篩選條件
ORDER BY 排序列表
執行順序:
①FROM子句
②WHERE子句
③SELECT子句
④ORDER BY 子句
SELECT last_name,salary
FROM employees
WHERE salary>20000
ORDER BY salary ;
特點:
1、排序列表可以是單個欄位、多個欄位、表示式、函式、列數、以及以上的組合
2、升序 ,通過 ASC (預設行為); 降序 ,通過 DESC。
一、按單個欄位排序
#案例1:將員工編號>120的員工資訊進行工資的降序
SELECT *
FROM employees
WHERE employee_id>120
ORDER BY salary DESC;
二、按表示式排序
#案例1:對有獎金的員工,按年薪降序
SELECT *,salary*12*(1+IFNULL(commission_pct,0)) 年薪
FROM employees
WHERE commission_pct IS NOT NULL
ORDER BY salary*12*(1+IFNULL(commission_pct,0)) DESC;
三、按別名排序
#案例1:對有獎金的員工,按年薪降序
SELECT *,salary*12*(1+commission_pct,0) 年薪
FROM employees
WHERE commission_pct IS NOT NULL
ORDER BY 年薪 DESC;
思考為什麼WHERE不能用別名進行判斷?
因為是程式碼執行順序的問題,where在select執行之前。
四、按函式的結果排序
#案例1:按姓名的字數長度進行升序
SELECT last_name
FROM employees
ORDER BY LENGTH(last_name);
五、按多個欄位排序
#案例1:查詢員工的姓名、工資、部門編號,先按工資升序,再按部門編號降序
SELECT last_name,salary,department_id
FROM employees
ORDER BY salary ASC,department_id DESC;
六、補充選學:按列數排序
SELECT * FROM employees
ORDER BY 2 DESC;
SELECT * FROM employees
ORDER BY first_name;
函式:為了實現某個功能,將編寫的一系列的命令集合封裝在一起,對外僅僅顯示方法名,供外部呼叫
1、自定義方法(函式)
2、呼叫方法(函式)★
函式名 :叫什麼
函式功能:幹什麼
單行函式
字元函式
CONCAT
SUBSTR
LENGTH(str)
CHAR_LENGTH
UPPER LOWER
TRIM
LEFT
RIGHT
LPAD
RPAD
INSTR
STRCMP
#一、字元函式
1、CONCAT 拼接字元
SELECT CONCAT('hello,',first_name,last_name) 備註 FROM employees;
2、LENGTH 獲取位元組長度,位元組長度與數字編碼格式有關
SELECT LENGTH('hello,郭襄');
3、CHAR_LENGTH 獲取字元個數
SELECT CHAR_LENGTH('hello,郭襄');
4、SUBSTR 擷取子串
/*
注意:起始索引從1開始!!!
substr(str,起始索引,擷取的字元長度)
substr(str,起始索引)沒有第三個引數的話就是擷取索引之後所有的值
*/
SELECT SUBSTR('張三丰愛上了郭襄',1,3);--->張三丰
SELECT SUBSTR('張三丰愛上了郭襄',7);--->郭襄
5、INSTR獲取字元第一次出現的索引
SELECT INSTR('三打白骨精aaa白骨精bb白骨精','白骨精');--->3
6、TRIM去前後指定的字元,預設是去空格
SELECT TRIM(' 虛 竹 ') AS a;--->虛 竹
SELECT TRIM('x' FROM 'xxxxxx虛xxx竹xxxxxxxxxxxxxxxxxx') AS a;--->虛xxx竹
7、LPAD/RPAD 左填充/右填充,5代表總共的字元個數
SELECT LPAD('木婉清',5,'a');--->aa木婉清
SELECT RPAD('木婉清',5,'a');--->木婉清aa
8、UPPER/LOWER 變大寫/變小寫
#案例:查詢員工表的姓名,要求格式:姓首字元大寫,其他字元小寫,名所有字元大寫,且姓和名之間用_分割,最後起別名“OUTPUT”
SELECT CONCAT(UPPER(SUBSTR(first_name,1,1)),LOWER(SUBSTR(first_name,2)),'_',UPPER(last_name)) "OUTPUT"
FROM employees;
9、STRCMP 比較兩個字元大小
SELECT STRCMP('aec','aec');
引數1大於引數2顯示1,小於顯示-1,等於顯示0
10、LEFT/RIGHT 擷取子串
SELECT LEFT('鳩摩智',1);--->鳩
SELECT RIGHT('鳩摩智',1);--->智
數學函式
ABS
CEIL
FLOOR
ROUND
TRUNCATE
MOD
#二、數學函式
1、ABS 絕對值
SELECT ABS(-2.4);--->2.4
2、CEIL 向上取整 返回>=該引數的最小整數
SELECT CEIL(-1.09);
SELECT CEIL(0.09);
SELECT CEIL(1.00);
3、FLOOR 向下取整,返回<=該引數的最大整數
SELECT FLOOR(-1.09);
SELECT FLOOR(0.09);
SELECT FLOOR(1.00);
4、ROUND 四捨五入
SELECT ROUND(1.8712345);
SELECT ROUND(1.8712345,2); 2代表小數點後幾位
5、TRUNCATE 截斷
SELECT TRUNCATE(1.8712345,1);引數2表示截斷小數點後幾位
6、MOD 取餘
SELECT MOD(-10,3);
a%b = a-a/b*b
-10%3 = -10 - (-10)/3*3 = -1
SELECT -10%3;
SELECT 10%3;
SELECT -10%-3;
SELECT 10%-3;
日期函式
NOW
CURTIME
CURDATE
DATEDIFF
DATE_FORMAT
STR_TO_DATE
#三、日期函式
1、NOW 當前日期,時間
SELECT NOW();
2、CURDATE 當前日期
SELECT CURDATE();
3、CURTIME 當前時間
SELECT CURTIME();
4、DATEDIFF 兩個日期差值,引數1減引數2
SELECT DATEDIFF('1998-7-16','2019-7-13');
5、DATE_FORMAT 將引數1按照轉換成指定格式
SELECT DATE_FORMAT('1998-7-16','%Y年%m月%d日 %H小時%i分鐘%s秒') 出生日期;
1998年07月16日 00小時00分鐘00秒
6、STR_TO_DATE 按指定格式解析字串為日期型別,這樣字串就能和日期比較
SELECT * FROM employees
WHERE hiredate<STR_TO_DATE('3/15 1998','%m/%d %Y');
流程控制函式
IF
CASE
#四、流程控制函式
1、IF函式
SELECT IF(100>9,'好','壞');
如果 100>9,顯示好,否則顯示壞
#需求:如果有獎金,則顯示最終獎金,如果沒有,則顯示0
SELECT IF(commission_pct IS NULL,0,salary*12*commission_pct) 獎金
FROM employees;
2、CASE函式
情況1 :實現等值判斷
CASE 表示式
WHEN 值1 THEN 結果1
WHEN 值2 THEN 結果2
...
ELSE 結果n
END
案例:
部門編號是30,工資顯示為2倍
部門編號是50,工資顯示為3倍
部門編號是60,工資顯示為4倍
否則不變
顯示 部門編號,新工資,舊工資
SELECT department_id,salary,
CASE department_id
WHEN 30 THEN salary*2
WHEN 50 THEN salary*3
WHEN 60 THEN salary*4
ELSE salary
END newSalary
FROM employees;
②情況2:類似於多重IF語句,實現區間判斷
CASE
WHEN 條件1 THEN 結果1
WHEN 條件2 THEN 結果2
...
ELSE 結果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 :查詢員工資訊表中,所有員工的工資和、工資平均值、最低工資、最高工資、有工資的個數
SELECT SUM(salary),AVG(salary),MIN(salary),MAX(salary),COUNT(salary)
FROM employees;
#案例2:新增篩選條件
①查詢employee_id表中記錄數:
SELECT COUNT(employee_id)
FROM employees;
②查詢employee_id表中有佣金的人數:
SELECT COUNT(salary)
FROM employees;
③查詢employee_id表中月薪大於2500的人數:
SELECT COUNT(salary)
FROM employees
WHERE salary>2500;
④查詢有領導的人數:
SELECT COUNT(manager_id)
FROM employees;
count的補充介紹★
1、統計結果集的行數,推薦使用count(*)
SELECT COUNT(*) FROM employees;
SELECT COUNT(*) FROM employees WHERE department_id = 30;
COUNT(1)表示給資料添加了一列內容為1的資料,然後計算資料為1的行數
SELECT COUNT(1) FROM employees;
SELECT COUNT(1) FROM employees WHERE department_id = 30;
2、搭配distinct實現去重的統計
#需求:查詢有員工的部門個數
SELECT COUNT(DISTINCT department_id) FROM employees;
SELECT 查詢列表
FROM 表名
WHERE 篩選條件
GROUP BY 分組列表
HAVING 分組後篩選
ORDER BY 排序列表;
執行順序:
①FROM子句
②WHERE子句
③GROUP BY 子句
④HAVING子句
⑤SELECT子句
⑥ORDER BY子句
特點:
①分組查詢列表往往是聚合函式和被分組的欄位
②分組查詢中的篩選分為兩類
順序:WHERE——GROUP BY ——HAVING
③聚合函式做條件只可能放在HAVING後面
④只有GROUP BY 後面跟的欄位名完全一致時才能分成一組,不管欄位名有幾個
簡單分組案例:
#案例1:查詢每個工種的員工平均工資
SELECT AVG(salary),job_id
FROM employees
GROUP BY job_id;
#案例2:查詢每個領導的手下人數
SELECT COUNT(*),manager_id
FROM employees
WHERE manager_id IS NOT NULL
GROUP BY manager_id;
可以實現分組前的篩選
#案例1:查詢郵箱中包含a字元的 每個部門的最高工資
SELECT MAX(salary) 最高工資,department_id
FROM employees
WHERE email LIKE '%a%'
GROUP BY department_id;
#案例2:查詢每個領導手下有獎金的員工的平均工資
SELECT AVG(salary) 平均工資,manager_id
FROM employees
WHERE commission_pct IS NOT NULL
GROUP BY manager_id;
分組後的篩選:
#案例1:查詢哪個部門的員工個數>5
SELECT COUNT(*) 員工個數,department_id
FROM employees
GROUP BY department_id
HAVING COUNT(*)>5;
#案例2:每個工種有獎金的員工的最高工資>12000的工種編號和最高工資
SELECT job_id,MAX(salary)
FROM employees
WHERE commission_pct IS NOT NULL
GROUP BY job_id
HAVING MAX(salary)>12000;
#案例3:領導編號>102的每個領導手下的最低工資大於5000的最低工資
SELECT MIN(salary) 最低工資,manager_id
FROM employees
WHERE manager_id>102
GROUP BY manager_id
HAVING MIN(salary)>5000 ;
實現排序:
#案例:查詢沒有獎金的員工的最高工資>6000的工種編號和最高工資,按最高工資升序
SELECT MAX(salary) 最高工資,job_id
FROM employees
WHERE commission_pct IS NULL
GROUP BY job_id
HAVING MAX(salary)>6000
ORDER BY MAX(salary) ASC;
按多個欄位分組:
#案例:查詢每個工種每個部門的最低工資,並按最低工資降序
提示:工種和部門都一樣,才是一組
SELECT MIN(salary) 最低工資,job_id,department_id
FROM employees
GROUP BY job_id,department_id
ORDER BY MIN(salary) DESC;
又稱多表查詢,當查詢語句涉及到的欄位來自於多個表時,就會用到連線查詢
笛卡爾乘積現象:
表1 有m行,表2有n行,
結果=m*n行
SELECT girl_name, boy_name
FROM beauty, boys;
發生原因:沒有有效的連線條件
如何避免:新增有效的連線條件
分類:
按年代分類:
1、sql92標準:僅僅支援內連線
內連線:
等值連線
非等值連線
自連線
2、sql99標準【推薦】:支援內連線+外連線(左外和右外)+交叉連線
按功能分類:
內連線:
等值連線
非等值連線
自連線
外連線:
左外連線
右外連線
全外連線
交叉連線
------------------------------sql92標準--------------------------------
一、內連線
語法:
SELECT 查詢列表
FROM 表1 別名,表2 別名
WHERE 連線條件 AND 篩選條件
GROUP BY 分組列表
HAVING 分組後篩選
ORDER BY 排序列表
執行順序:
1、FROM子句
2、WHERE子句
3、AND子句
4、GROUP BY子句
5、HAVING子句
6、SELECT子句
7、ORDER BY子句
一、等值連線
① 多表等值連線的結果為多表的交集部分
②n表連線,至少需要n-1個連線條件
③ 多表的順序沒有要求
④一般需要為表起別名
⑤可以搭配前面介紹的所有子句使用,比如排序、分組、篩選
1.查詢員工名和對應的部門名
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)裡的d.`manager_id`
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`
ORDER BY department_name DESC;
二、非等值連線
#案例1:查詢員工的工資和工資級別
(找salary對應的級別範圍而已)
#查詢員工級別為A的員工工資
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);工資級別原始碼
三、自連線
#案例:查詢 員工名和上級的名稱
(上級也是員工,所以都在employees表裡面,所以就得自己連線自己。)
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`;
------------------------------sql99標準--------------------------------
一、內連線
SELECT 查詢列表
FROM 表名1 別名
【INNER】 JOIN 表名2 別名 (INNER可省略)
ON 連線條件
WHERE 篩選條件
GROUP BY 分組列表
HAVING 分組後篩選
ORDER BY 排序列表;
SQL92和SQL99的區別:
SQL99,使用JOIN關鍵字代替了之前的逗號,並且將連線條件和篩選條件進行了分離,提高閱讀性!
一、等值連線
①簡單連線
#案例:查詢員工名和部門名
SELECT last_name,department_name
FROM departments d
JOIN employees e
ON e.department_id =d.department_id;
②新增篩選條件
#案例1:查詢部門編號>100的部門名和所在的城市名
SELECT department_name,city
FROM departments d
JOIN locations l
ON d.`location_id` = l.`location_id`
WHERE d.`department_id`>100;
③新增分組+篩選
#案例1:查詢每個城市的部門個數
SELECT COUNT(*) 部門個數,l.`city`
FROM departments d
JOIN locations l
ON d.`location_id`=l.`location_id`
GROUP BY l.`city`;
④新增分組+篩選+排序
#案例1:查詢部門中員工個數>10的部門名,並按員工個數降序
SELECT COUNT(*) 員工個數,d.department_name
FROM employees e
JOIN departments d
ON e.`department_id`=d.`department_id`
GROUP BY d.`department_id`
HAVING 員工個數>10
ORDER BY 員工個數 DESC;
二、非等值連線
#案例:查詢部門編號在10-90之間的員工的工資級別,並按級別進行分組
SELECT COUNT(*) 個數,grade
FROM employees e
JOIN sal_grade g
ON e.`salary` BETWEEN g.`min_salary` AND g.`max_salary`
WHERE e.`department_id` BETWEEN 10 AND 90
GROUP BY g.grade;
三、自連線
#案例:查詢員工名和對應的領導名
SELECT e.`last_name`,m.`last_name`
FROM employees e
JOIN employees m
ON e.`manager_id`=m.`employee_id`;
四、外連線
說明:查詢結果為主表中所有的記錄,如果從表有匹配項,則主表對應列顯示匹配項;如果從表沒有匹配項,則主表對應列顯示NULL。
應用場景:一般用於查詢主表中有但從表沒有的記錄
特點:
1、 外連線分主從表,兩表的順序不能任意調換
2、 左連線的話,LEFT JOIN 左邊為主表
右連線的話,RIGHT JOIN 右邊為主表
SELECT 查詢列表
FROM 表1 別名
LEFT|RIGHT 【OUTER】 JOIN 表2 別名
ON 連線條件 (ON 後面只是連線條件,並不是篩選條件,所以即使主從表中有些值為NUII也不影響)
WHERE 篩選條件;
USE girls;
案例1:查詢所有女神記錄,以及對應的男神名,如果沒有對應的男神,則顯示為null
#左連線
SELECT b.*,bo.*
FROM beauty b
LEFT JOIN boys bo ON b.`boyfriend_id` = bo.`id`;
#右連線
SELECT b.*,bo.*
FROM boys bo
RIGHT JOIN beauty b ON b.`boyfriend_id` = bo.`id`;
案例2:查哪個女神沒有男朋友
#左連線
SELECT b.`name`
FROM beauty b
LEFT JOIN boys bo ON b.`boyfriend_id` = bo.`id`
WHERE bo.`id` IS NULL;
#右連線
SELECT b.*,bo.*
FROM boys bo
RIGHT JOIN beauty b ON b.`boyfriend_id` = bo.`id`
WHERE bo.`id` IS NULL;
案例3:查詢哪個部門沒有員工,並顯示其部門編號和部門名
SELECT department_id, department_nameFROM departments d
LEFT JOIN employees e
ON d.`department_id` = e.`department_id`
WHERE e.`employee_id` IS NULL;
關於連線查詢注意的一個點:連線查詢成功時(除外連線),當初from後列表只保留連線條件符合的資料。
當一個查詢語句中又嵌套了另一個完整的SELECT語句,則被巢狀的SELECT語句稱為子查詢或內查詢 外面的SELECT語句稱為主查詢或外查詢
分類:
按子查詢出現的位置進行分類:
1、SELECT後面 要求:子查詢的結果為單行單列(標量子查詢)
2、FROM後面 要求:子查詢的結果可以為多行多列
3、WHERE或HAVING後面 ★
要求:子查詢的結果必須為單列
單行子查詢
多行子查詢
4、EXISTS後面 要求:子查詢結果必須為單列(相關子查詢)
特點:
1、子查詢放在條件中,要求必須放在條件的右側
2、子查詢一般放在小括號中
3、子查詢的執行優先於主查詢
4、單行子查詢對應了 單行操作符:> < >= <= = <>
多行子查詢對應了 多行操作符:ANY/SOME ALL IN
一、放在WHERE或HAVING後面的單行子查詢
單行子查詢
#案例1:誰的工資比 Abel 高?
①查詢Abel的工資
SELECT salary
FROM employees
WHERE last_name = 'Abel'
②查詢salary>①的員工資訊
SELECT last_name,salary
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=① AND 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
②查詢salary=①的員工的last_name,job_id和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
HAVING MIN(salary)>(
SELECT MIN(salary)
FROM employees
WHERE department_id = 50
);
二、放在WHERE或HAVING後面的多行子查詢
IN:判斷某欄位是否在指定列表內
X IN(10,30,50)
ANY/SOME:判斷某欄位的值是否滿足其中任意一個
X=ANY(10,30,50) 等價於 X IN(10,30,50)
ALL:判斷某欄位的值是否滿足裡面所有的
X >ALL(10,30,50) 等價於 X >MAX(10,30,50)
X <ALL(10,30,50) 等價於 X <MIN(10,30,50)
#案例1:返回location_id是1400或1700的部門中的所有員工姓名
①查詢location_id是1400或1700的部門
SELECT department_id
FROM departments
WHERE location_id IN(1400,1700)
②查詢department_id = ①的姓名
SELECT last_name
FROM employees
WHERE department_id IN(
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'
②查詢其他部門的工資<任意一個①的結果
SELECT employee_id,last_name,job_id,salary
FROM employees
WHERE salary<ANY(
SELECT DISTINCT salary
FROM employees
WHERE job_id = 'IT_PROG'
);
等價於
SELECT employee_id,last_name,job_id,salary
FROM employees
WHERE salary<(
SELECT MAX(salary)
FROM employees
WHERE job_id = 'IT_PROG'
);
#案例3:返回其它部門中比job_id為‘IT_PROG’部門所有工資都低的員工 的員工號、姓名、job_id 以及salary
①查詢job_id為‘IT_PROG’部門的工資
SELECT DISTINCT salary
FROM employees
WHERE job_id = 'IT_PROG'
②查詢其他部門的工資<所有①的結果
SELECT employee_id,last_name,job_id,salary
FROM employees
WHERE salary<ALL(
SELECT DISTINCT salary
FROM employees
WHERE job_id = 'IT_PROG'
);
等價於
SELECT employee_id,last_name,job_id,salary
FROM employees
WHERE salary<(
SELECT MIN(salary)
FROM employees
WHERE job_id = 'IT_PROG'
);
三、放在SELECT後面(相關子查詢)
#案例;查詢部門編號是50的員工個數
SELECT
(
SELECT COUNT(*)
FROM employees
WHERE department_id = 50
) 個數;
四、放在FROM後面(表子查詢)
#案例:查詢每個部門的平均工資的工資級別
①查詢每個部門的平均工資
SELECT AVG(salary),department_id
FROM esemploye
GROUP BY department_id
②將①和sal_grade兩表連線查詢
SELECT dep_ag.department_id, dep_ag.ag, g.grade
FROM sal_grade g
JOIN (
SELECT AVG(salary) ag,department_id
FROM employees
GROUP BY department_id
) dep_ag
ON dep_ag.ag BETWEEN g.min_salary AND g.max_salary;
五、放在EXISTS後面
#案例1 :查詢有無名字叫“Abel”的員工資訊
有 結果為1
無 結果為0
SELECT EXISTS(
SELECT *
FROM employees
WHERE last_name = 'Abel'
) 有無Abel;
六、子查詢中的排序問題
遇到例如 平均工資 最低,最高工資最小 等需求時,解決辦法時先按照平均工資排序,然後用LIMIT選取結果。
例如 求員工平均工資最低的員工號
SELECT employee_id
FROM employees
ORDER BY AVG(salary) ASC
LIMIT 1;
應用場景:當頁面上的資料,一頁顯示不全,則需要分頁顯示
分頁流程:分頁查詢的SQL命令請求資料庫伺服器——>伺服器響應查詢到的多條資料——>前臺頁面
SELECT 查詢列表
FROM 表1 別名
JOIN 表2 別名
ON 連線條件
WHERE 篩選條件
GROUP BY 分組
HAVING 分組後篩選
ORDER BY 排序列表
LIMIT 起始條目索引,顯示的條目數
執行順序:
①FROM子句
②JOIN子句 3
③ON子句 4
④WHERE子句
⑤GROUP BY子句
⑥HAVING子句
⑦SELECT子句
⑧ORDER BY子句
⑨LIMIT子句
特點:
LIMIT(引數1,引數2)
①起始條目索引如果不寫,預設是0
②LIMIT後面支援兩個引數
引數1:顯示的起始條目索引 引數2:條目數
select * from employees limit (page-1)*size,size; page size=10 1 limit 0,10 2 limit 10,10 3 limit 20,10 4 limit 30,10頁數與顯示條目數的關係
#案例1:查詢員工資訊表的前5條
SELECT * FROM employees LIMIT 0,5;
#完全等價於
SELECT * FROM employees LIMIT 5;
#案例2:查詢有獎金的,且工資較高的第11名到第20名
SELECT *
FROM employees
WHERE commission_pct IS NOT NULL
ORDER BY salary DESC
LIMIT 10,10 ;
當查詢結果來自於多張表,但多張表之間沒有關聯,這個時候往往使用聯合查詢,也稱為UNION查詢
SELECT 查詢列表 FROM 表1 WHERE 篩選條件
UNION
SELECT 查詢列表 FROM 表2 WHERE 篩選條件
特點:
1、多條待聯合的查詢語句的查詢列數必須一致,查詢型別、欄位意義最好一致
2、UNION實現去重查詢 ;UNION ALL 實現全部查詢,包含重複項
#案例:查詢所有國家的年齡>20歲的使用者資訊
SELECT * FROM usa WHERE uage >20 UNION
SELECT * FROM chinese WHERE age >20 ;
#案例2:查詢所有國家的使用者姓名和年齡
這樣做語法沒問題,但沒有實際操作意義(兩個查詢的年齡,名字順序相反,所以說沒意義)
SELECT uname,uage FROM usa
UNION
SELECT age,`name` FROM chinese;
#案例3:union自動去重/union all 可以支援重複項
SELECT 1,'范冰冰'
UNION ALL
SELECT 1,'范冰冰'
UNION ALL
SELECT 1,'范冰冰'
UNION ALL
SELECT 1,'范冰冰' ;
DATA Define Language資料定義語言,用於對資料庫和表的管理和操作
--------------------------------------------------庫的管理------------------------------------------------------
一、建立資料庫
CREATE DATABASE stuDB;
CREATE DATABASE IF NOT EXISTS stuDB;
二、刪除資料庫
DROP DATABASE stuDB;
DROP DATABASE IF EXISTS stuDB;
--------------------------------------------------表的管理------------------------------------------------------
建立表 ★
語法:
CREATE TABLE [IF NOT EXISTS] 表名(
欄位名 欄位型別 【欄位約束】,
欄位名 欄位型別 【欄位約束】,
欄位名 欄位型別 【欄位約束】,
欄位名 欄位型別 【欄位約束】,
欄位名 欄位型別 【欄位約束】
);
案例:沒有新增約束
CREATE TABLE IF NOT EXISTS stuinfo(
stuid INT ,
stuname VARCHAR(20),
stugender CHAR(1),
email VARCHAR(20),
borndate DATETIME
);
案例:新增約束
DROP TABLE IF EXISTS stuinfo;
CREATE TABLE IF NOT EXISTS stuinfo(
stuid INT PRIMARY KEY,#添加了主鍵約束
stuname VARCHAR(20) UNIQUE NOT NULL,#添加了唯一約束+非空
stugender CHAR(1) DEFAULT '男',#添加了預設約束
email VARCHAR(20) NOT NULL,
age INT CHECK( age BETWEEN 0 AND 100),#添加了檢查約束,mysql不支援
majorid INT,
CONSTRAINT fk_stuinfo_major FOREIGN KEY (majorid) REFERENCES major(id)#添加了外來鍵約束
);
關於外來鍵:
fk_stuinfo_major 為 外來鍵名字
majorid 為要設定外來鍵的從表字段名
major(id) 為maior表裡的id,即主表中被引用的欄位名
一、資料型別
1、整型 TINYINT SMALLINT INT BIGINT 2、浮點型 FLOAT(m,n) DOUBLE(m,n) DECIMAL(m,n)--定點型 m和n可選 m表示整數位和小數點位之和,n表示小數點後的位數
m和d都可以省略,對於DECIMAL而言,M預設為10,D預設為0
3、字元型 CHAR(n):n可選
VARCHAR(n):n必選
TEXT n表示最多字元個數
4、日期型
DATE 只顯示日期
TIME 只顯示時間
DATETIME 顯示日期和時間
TIMESTAMP 顯示日期和時間(最大值到2038年的某一刻)
5、二進位制型 BLOB 儲存圖片資料
二、常見約束
用於限制表中欄位的資料的,從而進一步保證資料表的資料是一致的、準確的、可靠的。
NOT NULL 非空:用於限制該欄位為必填項
DEFAULT 預設:用於限制該欄位沒有顯式插入值,則直接顯式預設值
PRIMARY KEY 主鍵:用於限制該欄位值不能重複,設定為主鍵列的欄位預設不能為空
一個表只能有一個主鍵,當然可以是組合主鍵
UNIQUE 唯一:用於限制該欄位值不能重複
欄位是否可以為空 一個表可以有幾個 聯合健
主鍵 × 1個 √
唯一 √ n個 √
CHECK檢查:用於限制該欄位值必須滿足指定條件
CHECK(age BETWEEN 1 AND 100)
FOREIGN KEY 外來鍵:用於限制兩個表的關係,要求外來鍵列的值必須來自於主表的關聯列
要求:
①主表的關聯列和從表的關聯列的型別必須一致,意思一樣,名稱無要求
②主表的關聯列要求必須是主鍵
③在那個表新增唯一約束,那個表就是從表,被引用欄位的表為主表
新增外來鍵的幾種方法:
#在sql語句末端新增外來鍵
CREATE TABLE IF NOT EXISTS booktype(
id INT PRIMARY KEY,
NAME VARCHAR(20)
);
CREATE TABLE IF NOT EXISTS book(
bid INT PRIMARY KEY,
bname VARCHAR(20) UNIQUE NOT NULL,
price FLOAT DEFAULT 10,
btypeid INT,
FOREIGN KEY (btypeid) REFERENCES booktype(id)
);
#2fk的使用
CREATE TABLE IF NOT EXISTS booktype(
id INT PRIMARY KEY,
NAME VARCHAR(20)
);
CREATE TABLE IF NOT EXISTS book(
bid INT PRIMARY KEY,
bname VARCHAR(20) UNIQUE NOT NULL,
price FLOAT DEFAULT 10,
btypeid INT,
CONSTRAINT fk_book_booktype FOREIGN KEY (btypeid) REFERENCES booktype(id)
);
#3在建表後新增外來鍵
ALTER TABLE book ADD FOREIGN KEY (btypeid) REFERENCES booktype(id);
在有外來鍵的情況下要刪除引用列的資料,先刪除從表,在刪除主表
可以通過以下兩種方式來刪除主表的記錄
#方式一:級聯刪除
ALTER TABLE stuinfo ADD CONSTRAINT fk_stu_major FOREIGN KEY(majorid) REFERENCES major(id) ON DELETE CASCADE;
#方式二:級聯置空
ALTER TABLE stuinfo ADD CONSTRAINT fk_stu_major FOREIGN KEY(majorid) REFERENCES major(id) ON DELETE SET NULL;
三、修改表
語法:ALTER TABLE 表名 ADD|MODIFY|CHANGE|DROP COLUMN 欄位名 欄位型別 【欄位約束】;
#1.修改表名
ALTER TABLE stuinfo RENAME TO students;
#2.新增欄位
ALTER TABLE students ADD COLUMN borndate TIMESTAMP NOT NULL;
#3.修改欄位名
ALTER TABLE students CHANGE COLUMN borndate birthday DATETIME NULL;
#4.修改欄位型別
ALTER TABLE students MODIFY COLUMN birthday TIMESTAMP ;
#5.刪除欄位
ALTER TABLE students DROP COLUMN birthday;
四、刪除表
DROP TABLE IF EXISTS students;
五、複製表
#僅僅複製表的結構
CREATE TABLE newTable2 LIKE major;
#複製表的結構+資料
CREATE TABLE newTable3 SELECT * FROM girls.`beauty`;
#案例:複製employees表中的last_name,department_id,salary欄位到新表 emp表,但不復制資料
CREATE TABLE emp
SELECT last_name,department_id,salary
FROM myemployees.`employees`
WHERE 1=2;#(這句判斷不成立所以只會複製欄位名,不會複製值)
DML(DATA Manipulation LANGUAGE)資料操縱語言
INSERT UPDATE DELETE 對錶中的資料的增刪改
一、資料的插入
語法:
插入單行:
INSERT INTO 表名(欄位名1,欄位名2 ,...)
VALUES (值1,值2,...);
插入多行:
INSERT INTO 表名(欄位名1,欄位名2 ,...)
VALUES(值1,值2,...),
(值1,值2,...),
(值1,值2,...);
特點:
①欄位和值列表一一對應 包含型別、約束等必須匹配
②數值型的值,不用單引號 非數值型的值,必須使用單引號
③欄位順序無要求
#案例1:要求欄位和值列表一一對應,且遵循型別和約束的限制
INSERT INTO stuinfo(stuid,stuname,stugender,email,age,majorid)
VALUES(1,'吳倩','男','[email protected]',12,1);
INSERT INTO stuinfo(stuid,stuname,stugender,email,age,majorid)
VALUES(2,'李宗盛','男','[email protected]',45,2);
#案例2:可以為空欄位如何插入
方案1:欄位名和值都不寫
INSERT INTO stuinfo(stuid,stuname,email,majorid)
VALUES(5,'齊魚','[email protected]',2);
方案1:欄位名寫上,值使用NULL
INSERT INTO stuinfo(stuid,stuname,email,age,majorid)
VALUES(5,'齊魚','[email protected]',NULL,2);
#案例3:預設欄位如何插入
方案1:欄位名寫上,值使用DEFAULT
INSERT INTO stuinfo(stuid,stuname,email,stugender,majorid)
VALUES(7,'齊小魚','[email protected]',DEFAULT,2);
方案2:欄位名和值都不寫
INSERT INTO stuinfo(stuid,stuname,email,majorid)
VALUES(7,'齊小魚','[email protected]',2);
#案例4:可以省略欄位列表,預設所有欄位
INSERT INTO stuinfo
VALUES(8,'林憶蓮','女','[email protected]',12,3);
INSERT INTO stuinfo
VALUES(NULL,'小黃','男','[email protected]',12,3);
自增長列:
1、自增長列要求必須設定在一個鍵上,比如主鍵或唯一鍵
2、自增長列要求資料型別為數值型
3、一個表至多有一個自增長列
CREATE TABLE gradeinfo(
gradeID INT PRIMARY KEY AUTO_INCREMENT,
gradeName VARCHAR(20)
);
INSERT INTO gradeinfo VALUES(NULL,'一年級'),(NULL,'2年級'),(NULL,'3年級');
或者
INSERT INTO gradeinfo(gradename)VALUES('一年級'),('2年級'),('3年級');
二、資料的修改
修改單表記錄:
UPDATE 表名 SET 欄位名 = 新值,
欄位名=新值,...
WHERE 篩選條件;
修改多表記錄:
sql99語法:
UPDATE 表一, 別名
INNER|LEFT|RIGHT JOIN 表2, 別名
ON 連線條件
SET 欄位名=新值,欄位名=新值
WHERE 篩選條件
UPDATE stuinfo
SET majorid = 3,
email='[email protected]'
WHERE age<20;
#案例2:修改張無忌的女朋友的手機號為114
UPDATE beauty, b
JOIN boys, bo
ON boy.id=b.boyfriend_id
SET b.phone=114
WHERE bo.name='張無忌'
三、資料的刪除
方式1:DELETE語句
語法:DELETE FROM 表名 WHERE 篩選條件;
方式2:TRUNCATE語句
語法:TRUNCATE TABLE 表名;
#案例1:刪除姓李所有資訊
DELETE FROM stuinfo WHERE stuname LIKE '李%';
#案例2:刪除表中所有資料
TRUNCATE TABLE stuinfo ;
#【面試題】delete和truncate的區別 1.delete可以新增WHERE條件 TRUNCATE不能新增WHERE條件,一次性清除所有資料 2.truncate的效率較高 3.如果刪除帶自增長列的表, 使用DELETE刪除後,重新插入資料,記錄從斷點處開始 使用TRUNCATE刪除後,重新插入資料,記錄從1開始 4.delete 刪除資料,會返回受影響的行數 TRUNCATE刪除資料,不返回受影響的行數 5.delete刪除資料,可以支援事務回滾 TRUNCATE刪除資料,不支援事務回滾【面試題】delete和truncate的區別
一、含義
事務:一條或多條sql語句組成一個執行單位,一組sql語句要麼都執行要麼都不執行
二、特點(ACID)
A 原子性:一個事務是不可再分割的整體,要麼都執行要麼都不執行
C 一致性:一個事務可以使資料從一個一致狀態切換到另外一個一致的狀態
I 隔離性:一個事務不受其他事務的干擾,多個事務互相隔離的
D 永續性:一個事務一旦提交了,則永久的持久化到本地
三、事務的使用步驟 ★
隱式(自動)事務:沒有明顯的開啟和結束,本身就是一條事務可以自動提交,比如insert、update、delete
顯式事務:具有明顯的開啟和結束
使用顯式事務:
①開啟事務
set autocommit=0;
start transaction;#可以省略
②編寫一組邏輯sql語句
注意:sql語句支援的是insert、update、delete
設定回滾點:
savepoint 回滾點名;
③結束事務
提交:commit;
回滾:rollback;
回滾到指定的地方:rollback to 回滾點名;
四、併發事務
1、事務的併發問題是如何發生的?
多個事務 同時操作 同一個資料庫的相同資料時
2、併發問題都有哪些?
髒讀:一個事務讀取了其他事務還沒有提交的資料,讀到的是其他事務“更新”的資料
不可重複讀:一個事務多次讀取,結果不一樣
幻讀:一個事務讀取了其他事務還沒有提交的資料,只是讀到的是 其他事務“插入”的資料
3、如何解決併發問題
通過設定隔離級別來解決併發問題
4、隔離級別(√代表可避免,×代表不可避免)
髒讀 不可重複讀 幻讀
read uncommitted:讀未提交 × × ×
read committed:讀已提交 √ × ×
repeatable read:可重複讀 √ √ ×
serializable:序列化 √ √ √
五、事務相關語句
設定隔離級別:
set session|global transaction isolation level 隔離級別名;
檢視隔離級別:
SELECT @@tx_isolation;
檢視支援的儲存引擎:
SHOW ENGINES;
六、注意事項與演示
#1.演示事務對於delete和truncate的處理的區別
SET autocommit=0;
START TRANSACTION;
DELETE FROM account;(資料沒有刪除,支援回滾)
ROLLBACK;
SET autocommit=0;
START TRANSACTION;
TRUNCATE TABLE account;(資料已經刪除了,寫入磁碟了,不支援回滾)
ROLLBACK;
#2.演示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;(所以只會刪除id=25的資料)
含義:虛擬表,和普通表一樣使用
mysql5.1版本出現的新特性,是通過表動態生成的資料
試圖與表的區別:
一、建立檢視
CREATE VIEW 檢視名
AS
查詢語句;
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`;
二、檢視的修改
方式一:
CREATE OR REPLACE VIEW 檢視名
AS
查詢語句;
將myv2的名字改為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 AVG(salary),job_id
FROM employees
GROUP BY job_id;
三、刪除檢視
語法:DROP VIEW 檢視名,檢視名,...;
DROP VIEW emp_v1,emp_v2,myv3;
四、檢視檢視
DESC myv3;
SHOW CREATE VIEW myv3;(查詢結果不太清晰話)
五、檢視的更新
CREATE OR REPLACE VIEW myv1 (如果myv1存在,那就將SQL語句更新,如果不存在,就建立myv1)
AS
SELECT last_name,email
FROM employees;
1.插入(原始資料表employees也會被插入)
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;
#更新
UPDATE myv1 SET m=9000 WHERE department_id=10;(報錯)
②常量檢視
CREATE OR REPLACE VIEW myv2
AS
SELECT 'john' NAME;
#更新
UPDATE myv2 SET NAME='lucy';(報錯)
③SELECT中包含子查詢
CREATE OR REPLACE VIEW myv3
AS
SELECT (SELECT MAX(salary) FROM employees) 最高工資
#更新
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;
#更新
UPDATE myv4 SET last_name = '張飛' WHERE last_name='Whalen';(沒報錯)
INSERT INTO myv4 VALUES('陳真','xxxx');(報錯)
⑤FROM一個不能更新的檢視
CREATE OR REPLACE VIEW myv5
AS
SELECT * FROM myv3;
更新
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';(報錯)
十六、變數、儲存過程、函式
變數分為系統變數和自定義變數
系統變數:
全域性變數
會話變數
自定義變數:
使用者變數
區域性變數
1.系統變數
說明:變數由系統定義,不是使用者定義,屬於伺服器層面
注意:全域性變數需要新增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】系統變數名=值;
①全域性變數
作用域:針對於所有會話(連線)有效,但不能跨重啟
#①檢視所有全域性變數
SHOW GLOBAL VARIABLES;
#②檢視滿足條件的部分系統變數
SHOW GLOBAL VARIABLES LIKE '%char%';
#③檢視指定的系統變數的值
SELECT @@global.autocommit;
#④為某個系統變數賦值
SET @@global.autocommit=0;
SET GLOBAL autocommit=0;
②會話變數
作用域:針對於當前會話(連線)有效
#①檢視所有會話變數
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';
2.自定義變數
說明:變數由使用者自定義,而不是系統提供的
使用步驟:
1、宣告
2、賦值
3、使用(檢視、比較、運算等)
(1).使用者變數
作用域:針對於當前會話(連線)有效,作用域同於會話變數
賦值操作符為 = 或 :=
①宣告並初始化的三種方式
SET @變數名=值;
SET @變數名:=值;
SELECT @變數名:=值;
②賦值(更新變數的值)
方式一:
SET @變數名=值;
SET @變數名:=值;
SELECT @變數名:=值;
方式二:
SELECT 欄位 INTO @變數名
FROM 表;
③使用(檢視變數的值)
SELECT @變數名;
(2).區域性變數
作用域:僅僅在定義它的BEGIN END塊中有效
應用在 BEGIN END中的第一句話
①宣告
DECLARE 變數名 型別;
DECLARE 變數名 型別 【DEFAULT 值】;
②賦值(更新變數的值)
方式一:
SET 區域性變數名=值;
SET 區域性變數名:=值;
SELECT 區域性變數名:=值;
方式二:
SELECT 欄位 INTO 區域性變數名
FROM 表;
③使用(檢視變數的值)
SELECT 區域性變數名;
案例:宣告兩個變數,求和並列印
使用者變數
SET @m=1;
SET @n=1;
SET @sum=@m+@n;
SELECT @sum;
區域性變數(會報錯,沒在BEGIN END中)
DECLARE m INT DEFAULT 1;
DECLARE n INT DEFAULT 1;
DECLARE SUM INT;
SET SUM=m+n;
SELECT SUM;
使用者變數和區域性變數的對比:
儲存過程
含義:一組預先編譯好的SQL語句的集合,理解成批處理語句
1、提高程式碼的重用性
2、簡化操作
3、減少了編譯次數並且減少了和資料庫伺服器的連線次數,提高了效率
①.建立語法
CREATE PROCEDURE 儲存過程名(引數列表)
BEGIN
儲存過程體(一組合法的SQL語句)
END
注意:
1、引數列表包含三部分
引數模式 引數名 引數型別
舉例:
IN stuname VARCHAR(20)
引數模式:
IN:該引數可以作為輸入,也就是該引數需要呼叫方傳入值
OUT:該引數可以作為輸出,也就是該引數可以作為返回值
INOUT:該引數既可以作為輸入又可以作為輸出,也就是該引數既需要傳入值,又可以返回值
2、如果儲存過程體僅僅只有一句話,BEGIN END可以省略
儲存過程體中的每條SQL語句的結尾要求必須加分號。
儲存過程的結尾符號可以使用 DELIMITER 重新設定
語法:
DELIMITER 結束標記
案例:
DELIMITER $
二、呼叫語法
CALL 儲存過程名(實參列表);
1.空參列表
#案例:插入到admin表中五條記錄
DELIMITER $
CREATE PROCEDURE myp1()
BEGIN
INSERT INTO admin(username,`password`)
VALUES('john1','0000'),('lily','0000'),('rose','0000'),('jack','0000'),('tom','0000');
END $
#呼叫
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$
3.刪除儲存過程
#語法:drop procedure 儲存過程名
DROP PROCEDURE p1;
DROP PROCEDURE p2,p3;#×(一次只能刪除一個儲存過程)
4.檢視儲存過程的資訊
DESC myp2;×(報錯)
SHOW CREATE PROCEDURE myp2;
含義:一組預先編譯好的SQL語句的集合,理解成批處理語句
1、提高程式碼的重用性
2、簡化操作
3、減少了編譯次數並且減少了和資料庫伺服器的連線次數,提高了效率
區別:
儲存過程:可以有0個返回,也可以有多個返回,適合做批量插入、批量更新
函式:有且僅有1 個返回,適合做處理資料後返回一個結果
1.建立語法
CREATE FUNCTION 函式名(引數列表) RETURNS 返回型別
BEGIN
函式體
END
注意:
1.引數列表 包含兩部分:引數名,引數型別
2.函式體:肯定會有RETURN語句,如果沒有會報錯
如果RETURN語句沒有放在函式體的最後也不報錯,但不建議
3.函式體中僅有一句話,則可以省略BEGIN END
4.使用 DELIMITER語句設定結束標記
2.呼叫語法
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('kevin') $
#案例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')$
3.檢視函式
SHOW CREATE FUNCTION myf3;
4.刪除函式
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)$
流程控制結構
順序結構:程式從上往下依次執行
分支結構:程式從兩條或多條中選一條執行
迴圈結構:程式在滿足一定的條件基礎上,重複執行一段程式碼
一、分支結構
1.if函式
語法:IF(條件,值1,值2)
功能:實現雙分支
執行順序:如果條件成立,返回值1;條件不成立,返回值2
應用在任何地點(BEGIN END中或外面)
2.case結構
CASE結構作為表示式,可以應用在任何地方;CASE結構作為獨立的語句,只能應用在BEGIN END中
語法:
情況1:
CASE 變數|表示式|欄位
WHEN 值1 THEN 語句1;
WHEN 值2 THEN 語句2;
...
ELSE 語句n;
END CASE;
情況2:
CASE
WHEN 條件1 THEN 語句1;
WHEN 條件2 THEN 語句2;
...
ELSE 語句n;
END CASE;
3.if結構
功能:類似於多重IF
只能應用在BEGIN END 中
語法:
IF 條件1 THEN 語句1;
ELSEIF 條件2 THEN 語句2;
....
ELSE 語句n;
END IF;
#案例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';
ELSET 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)$
二、迴圈結構
分類:
WHILE、LOOP、REPEAT
迴圈控制:
ITERATE類似於 CONTINUE,繼續,結束本次迴圈,繼續下一次
LEAVE 類似於 break,跳出,結束當前所在的迴圈
智只能應用在BEGIN END中
1.while
語法:
【標籤:】WHILE 迴圈條件 DO
迴圈體;
END WHILE【 標籤】;
2.loop
可以用來模擬簡單的死迴圈
語法:
【標籤:】LOOP
迴圈體;
END LOOP 【標籤】;
3.repeat
語法:
【標籤:】REPEAT
迴圈體;
UNTIL 結束迴圈的條件
END REPEAT 【標籤】;
#1.沒有新增迴圈控制語句
#案例:批量插入,根據次數插入到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_while2(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_while2(100)$
3.新增ITERATE語句
#案例:批量插入,根據次數插入到admin表中多條記錄,只插入偶數次
CREATE PROCEDURE test_while3(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_while3(100)$