MySQL筆記

數據庫的好處

  • 實現數據持久化
  • 使用完整的管理系通通一管理,易於查詢

數據庫的概念

DB

數據庫(datebase):存儲數據的「倉庫」。他保存了一系列有組織的數據。java

DBMS

數據庫管理系統(Datebase Management System)。數據庫是經過DBMS建立和操做的容器mysql

常見的數據庫管理系統:MySQL、Oracle(太貴了)、DB2(適合處理海量數據)、SqlServer(微軟的,只能在安裝在Windows)等面試

SQL

結構化查詢語言(Structure Query Language):專門用來與數據庫通訊的語言。sql

SQL的優勢:

一、不是某個特定數據庫供應商專有的語言,幾乎全部DBMS都支持SQL數據庫

二、簡單易學express

三、雖然簡單,但其實是一種強有力的語言,靈活使用其語言元素,能夠進行很是複雜和高級的數據庫操做。windows

數據庫的特色

一、將數據放到表中,表再放到庫中安全

二、一個數據庫中能夠有多個表,每一個表都有一個名字,用來標識本身。表名具備惟一性。服務器

三、表具備一些特性,這些特性定義了數據在表中如何存儲,相似 JAVA 中「類」的設計。session

四、表由列組成,咱們也稱爲字段。全部表都是由一個或多個列組成的,每一列相似 JAVA 中的「屬性」

五、表中的數據是按行存儲的,每一行相似於JAVA中的「對象」

MySQL產品的特色

  • MySQL數據庫隸屬於MySQLAB公司,總部位於瑞典,08年被sun收購,09年sun被oracle收購。
  • 優勢:
    • 成本低:開放源代碼,通常能夠免費試用
    • 性能高:執行很快
    • 簡單:很容易安裝和使用

DBMS分類

  • 基於共享文件系統的DBMS (Access)
  • 基於客戶機——服務器的DBMS(MySQL、Oracle、SqlServer)

MySQL服務的中止與啓動

  • 方法一:計算機 -> 管理 -> 服務與應用程序 -> 服務 -> 找到MySQL ->啓動或中止
  • 方法二:以管理員身份運行cmd -> net stop mysqlxxx中止 -> net start mysqlxxx啓動

進入MySQL方法

方式一 : 經過mysql自帶的客戶端 (只限於root用戶)

方法二 : 經過windows的cmd

完整的輸入爲:mysql -h localhost(主機名) -P3306(端口號) -u(用戶名) root -p(密碼)

簡略的輸入爲:mysql -u root -p

MySQL的常見命令

show databases; 查看當前全部的庫

user 庫名; 打開指定的庫

show tables; 查看當前庫下的表

show tables from 庫名; 顯示指定庫下的表

-- 建立表

create table 表名(
	列名 列類型,
    列名 列類型,
  	列名 列類型
)

select database(); 顯示當前處於哪一個庫

desc 表名; 查看錶格結構

select * from 表名; 查看錶格數據

select version(); 查看MySQL版本

mysql --versionmysql -V cmd下查看MySQL版本

MySQL的語法規範

一、不區分大小寫,但建議關鍵字大寫,表名、列名小寫

二、建議每條命令用 ; 結尾(用\g也能夠)

三、每條命令根據須要,能夠進行縮進或換行

四、註釋

單行註釋:#註釋文字

單行註釋:-- 註釋文字

多行註釋: /* 註釋文字 */

DQL(Data Query Language)

``表明着重號,加不加均可以,當字段和關鍵字混淆時須要爲字段加上着重號

基礎查詢

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

特色:
一、查詢列表能夠是:表中的字段、常量值、表達式、函數
二、查詢的結果是一個虛擬的表格
*/
USE myemployees;

#1.查詢表中的單個字段

SELECT last_name FROM employees;

#2.查詢表中的多個字段
SELECT last_name,salary,email FROM employees;

#3.查詢表中的全部字段
SELECT 
  `employee_id`,
  `first_name`,
  `last_name`,
  `phone_number`,
  `salary` 
FROM
  employees ;
  
#方式二
SELECT * FROM employees;

#4.查詢常量值
#注意:字符型和日期型的常量值必須用單引號引發來,數值型不須要
SELECT 100;
SELECT 'john'; #''和""不加以區分,統一使用''

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

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

#7.起別名
/*
1.便於理解
2.若是要查詢的字段有重名的狀況,使用別名能夠區分開來
*/

#方式一:AS
SELECT 100%98 AS result;
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.去重

#案例:查詢員工表中涉及到的全部的部門編號
SELECT DISTINCT department_id FROM employees;

#9.+的做用
/*
java中的+:
1.運算符,兩個操做數都爲數值型
2.鏈接符,只要有一個操做數爲字符串

mysql中的+:
僅僅只有一個功能:運算符

select 100+90; 兩個操做數都爲數值型,則作加法運算
select '123'+90;	其中一方爲字符型,試圖將字符型數值轉換成數值型
			若是轉換成功,則繼續作加法運算
select 'john'+90;	若是轉換失敗,則將字符型數值轉換爲0

select null+10;	只要其中一方爲null,則結果確定爲null

*/

#案例:查詢員工名和員工姓鏈接成一個字段,並顯示爲 姓名

SELECT CONCAT('a','b','c') AS result;

SELECT 
  CONCAT(last_name,first_name) AS 姓名  
FROM
  employees ;

#題目

#顯示錶dapartments的結構,並查詢其中的所有數據
DESC departments;
SELECT * FROM departments;

#顯示出表employees的所有序列,各個列之間用逗號鏈接,列頭顯示成OUT_PUT
#出現null的解決方法
SELECT 
	IFNULL(commission_pct,0) AS 獎金率,
	commission_pct
FROM
	employees;
	
#---------------------------------------

SELECT
	CONCAT(`first_name`,',',`last_name`,',',`email`,',',`phone_number`,',',`job_id`,',',`salary`,',',IFNULL(commission_pct,0),',',`manager_id`,',',`department_id`,',',`hiredate`) AS out_put
FROM
	employees;

條件查詢

#進階2:條件查詢
/*
語法:
	select 
		查詢列表
	from
		表名
	where
		篩選條件;
分類:
	1、按條件表達式篩選
	簡單條件運算符:> < = <>(和!=同樣) >= <=
	
	2、按邏輯表達式篩選
	邏輯運算符:
	做用:用於鏈接條件表達式
		&&  ||  !
		and or not
	3、模糊查詢
		like
		between and
		in
		is null
	
*/
#1、按條件表達式篩選
#案例1:查詢工資>12000的員工信息

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

#案例2:查詢部門編號不是在90到110之間,或者工資高於15000的員工信息
SELECT
	*
FROM
	employees
WHERE
	NOT(department_id>=90 AND department_id<=110) OR salary>15000;
	
#3、模糊查詢
/*
like
between and
in
is null | is not null 
*/

#1.like
/*
特色:
1.通常和通配符搭配使用
	通配符:
	% 任意多個字符,包含0個字符
	_ 任意單個字符
*/
#案例1:查詢員工名中包含字符a的員工信息
SELECT
	*
FROM
	employees
WHERE
	last_name LIKE '%a%';	# %表示通配符
	
#案例2:查詢員工名中第三個字符爲n,第五個字符爲l的員工名和工資
SELECT
	last_name,
	salary
FROM
	employees
WHERE
	last_name LIKE '__n_l%';
	
#案例3:查詢員工名中第二個字符爲_的員工名
SELECT
	last_name
FROM
	employees
WHERE
	last_name LIKE '_$_%' ESCAPE '$';
	
#2.between and

/*
1.使用between and能夠提升語句的簡潔度
2.包含臨界值
3.兩個臨界值不要調換順序
*/

#案例1: 查詢員工編號在100-120之間的員工信息
SELECT 
	* 
FROM
	employees 
WHERE 
	employee_id BETWEEN 100 AND 120;
	
#3.in
/*
含義:判斷某字段的值是否屬於in列表中的一項
特色:
1.使用in提升語句簡潔度
2.in列表的值類型必須統一或兼容 '123'和123兼容
3.

*/
#案例:查詢員工的工種編號是 IT_PROG、AD_VP、AD_PRES中的一個員工名和工種編號

SELECT
	last_name,
	job_id
FROM
	employees
WHERE
	job_id IN('IT_PROG','AD_VP','AD_PRES');
	
#4.is null

/*
=或<>不能用於判斷null
is null 和 is not 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;
	
#案例2:查詢工資爲12000的員工信息
SELECT
	last_name,
	salary
FROM
	employees
WHERE
	salary <=> 12000;
/*	
is null 與 <=>
is null:僅僅能夠判斷NULL值,可讀性較高,建議使用
  <=>  :既能夠判斷NULL值,又能夠判斷普通的數值,可讀性較低
*/

#題目
#1、查詢沒有獎金,且工資小於18000的salary,last_name
SELECT
	salary,
	last_name
FROM
	employees
WHERE
	commission_pct IS NULL AND salary < 18000;
	
#2、查詢employees表中,job_id不爲'IT'或者工資爲12000的員工信息
SELECT
	*
FROM
	employees
WHERE
	job_id <> 'IT' OR salary = 12000;
#經典面試題
/*
試問:select * from employees;和
select * from employees where commission_pct like '%%' and last_name like '%%';
結果是否同樣?並說明緣由
*/
#不同!若是判斷的字段有null就不同
#select * from employees where commission_pct like '%%' or last_name like '%%';
#將and 改爲 or就同樣了
#拼接字符
concat(String1,String2,Stirng3)

#判斷某字段或表達式是否爲null,若是爲null返回指定的值,不然返回原來的值
ifnull(字段,指定的值)

#判斷某字段或表達式是否爲null,若是是則返回1,不然返回0
isnull(字段)

排序查詢

#進階3:排序查詢
/*
語法:
	select 查詢列表
	from 表
	[where 篩選條件]
	order by 排序列表 [asc | desc]
特色:
	一、asc表明的是升序,desc表明的是降序
	二、若是不寫,默認爲asc升序
	三、order by 字句中能夠支持單個字段、多個字段、表達式、函數、別名
	四、order by 字句通常是放在查詢語句的最後面,limit字句除外
*/
#案例1:查詢員工信息,要求工資從高到低排序
SELECT * FROM employees ORDER BY salary DESC;
SELECT * FROM employees ORDER BY salary ASC;
SELECT * FROM employees ORDER BY salary;

#案例2:查詢部門編號>=90的員工信息,按入職時間前後進行排序
SELECT * 
FROM employees 
WHERE department_id >= 90
ORDER BY hiredate ASC;

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

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

#案例5:按姓名的長度顯示員工的姓名和工資【按函數排序】
SELECT LENGTH(last_name) 字節長度,last_name,salary
FROM employees
ORDER BY LENGTH(last_name) DESC;

#案例6:查詢員工信息,要求先按工資升序,再按員工編號降序【按多個字段排序】
SELECT *
FROM employees
ORDER BY salary ASC,employee_id DESC;

#題目1:查詢員工的姓名和部門號和年薪,按年薪降序 按姓名升序
SELECT last_name,departmeny_id,salary*12*(1+IFNULL(commission_pct,0)) AS 年薪
FROM employees
ORDER BY 年薪 DESC,last_name ASC;

#題目2:查詢工資不在8000到17000的員工的姓名和工資,按工資降序
SELECT last_name,salary
FROM employees
WHERE salary NOT BETWEEN 8000 AND 17000
ORDER BY salary DESC;

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

常見函數

日期函數

str_to_date:將日期格式的字符轉換成指定格式的日期

str_to_date('9-13-1999','%m-%d-%Y')

date_format:將日期轉換成字符

date_format('2018/6/6'),'%Y年%m月%d日'

#進階4:常見函數

/*
概念:相似java中的方法,將一組邏輯語句封裝在方法體中,對外暴露方法名
好處:  一、隱藏了實現細節
	二、提升了代碼的重用性
調用:  select 函數名(實參列表) [from 表];X
特色:  一、叫什麼(函數名)
	二、幹什麼(函數功能)
分類:  一、單行函數
	如concat、length、ifnull等
	二、分組函數
	功能:作統計使用,又稱爲統計函數、聚合函數、組函數
	
常見函數:
	字符函數:
	length 返回字符長度
	concat	拼接字符
	substr	截取字符
	instr	返回字符串第一次出現的索引
	trim	用來移除掉一個字串中的字頭或字尾
	upper	變大寫
	lower	變小寫
	lpad	左填充
	rpad	右填充
	replace	替換
	
	數學函數:
	round	四捨五入
	ceil	向上取整
	floor	向下取整
	truncate 截斷數字
	mod	取餘
	
	日期函數:
	now
	curdate
	curtime
	year
	month
	monthname
	day
	hour
	minute
	second
	str_to_date
	date_formate
	
	其餘函數:
	version() 當前數據庫服務器的版本
	database() 當前打開的數據庫
	user()	當前用戶
	password('字符') 返回該字符的密碼形式
	md5('字符') 返回該字符的md5加密形式
	
	流程控制函數:
	if(條件表達式,表達式1,表達式2):成立返回1,不成立返回2
	case 變量或表達式或字段
	when 常量1 then 值1
	when 常量2 then 值2
	...
	else 值n
	end
*/
#1、字符函數
#length 獲取參數值的字節個數
SELECT LENGTH('john');
SELECT LENGTH('無敵是多麼寂寞'); # utf-8 一個字母佔一個字節 一個漢字三個字節

SHOW VARIABLES LIKE '%char%'

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

#3、upper、lower
SELECT UPPER('john');
SELECT LOWER('john');
#案例:將姓變大寫,名變小寫,而後拼接
SELECT CONCAT(UPPER(last_name), '_', LOWER(first_name)) 姓名 FROM employees;

#4、substr、substring
#注意:索引從1開始
#截取從指定索引處後面全部字符
SELECT SUBSTR('李莫愁愛上了陸展元',1) out_put;
#截取從指定索引處指定字符長度的字符
SELECT SUBSTR('李莫愁愛上了陸展元',1,3) out_put;

#案例:姓名中首字符大寫,其餘字符小寫,而後用_拼接
SELECT CONCAT(UPPER(SUBSTR(last_name,1,1)),'_',LOWER(SUBSTR(last_name,2))) AS out_put
FROM employees;

#5、instr 返回字串第一次出現的索引,若是找不到返回0
SELECT INSTR('楊不悔愛上了殷六俠','殷六俠') AS out_put;

#6、TRIM ( [ [位置] [要移除的字串] FROM ] 字串)
#[位置] 的可能值爲 LEADING (起頭), TRAILING (結尾), or BOTH (起頭及結尾)。 
#這個函數將把 [要移除的字串] 從字串的起頭、結尾,或是起頭及結尾移除。
#若是咱們沒有列出 [要移除的字串] 是什麼的話,那空白就會被移除。
 
SELECT LENGTH(TRIM('  張翠山  ')) AS out_put;

SELECT TRIM('a' FROM 'aaaaaaaaaa張a翠a山aaaaaaaaaaaaaaa') AS out_put;

#7、lpad 用指定的字符實現 左填充 指定長度
SELECT LPAD('殷素素',5,'*') AS out_put;

#8、rpad 用指定的字符實現 右填充 指定長度
SELECT RPAD('殷素素',5,'*') AS out_put;

#9、replace 替換
SELECT REPLACE('張無忌愛上了周芷若周芷若周芷若','周芷若','趙敏') AS out_put;

#2、數學函數

#round 四捨五入
SELECT ROUND(-1.46);
SELECT ROUND(1.567,2);

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

#floor 向下取整,返回<=該參數的最大整數
SELECT FLOOR(-9.99);

#truncate 截斷
SELECT TRUNCATE(0.65321,1);

#mod 取餘
SELECT MOD(-10,3);
SELECT 10%3;

#3、日期函數

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

#curdate 返回當前系統日期
SELECT CURDATE();

#curtime 返回當前時間
SELECT CURTIME();

#能夠獲取指定的部分,年、月、日、小時、分鐘、秒
SELECT YEAR(NOW()) AS 年; 
SELECT YEAR('1998-1-1') AS 年; 

SELECT YEAR(hiredate) AS 年 FROM employees;

SELECT MONTH(NOW()) AS 月;
SELECT MONTHNAME(NOW()) AS 月;

#str_to_date 將字符經過指定的格式轉換成日期

SELECT STR_TO_DATE('1998-3-2','%Y-%c-%d') AS 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');

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

#4、其餘函數
SELECT VERSION();
SELECT DATABASE();
SELECT USER();

#5、流程控制函數
#1. if函數: if else的效果
SELECT IF(10<5,'大','小');

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

#2. case函數的使用一:switch case 的效果

/*
switch(變量或表達式){
	case 常量1: 語句1; break;
	....
	default: 語句n; break;
}

mysql中

case 要判斷的字段或表達式
when 常量一 then 要顯示的值1或語句1;
when 常量二 then 要顯示的值2或語句2;
...
else 要顯示的值n或語句n;
end
*/

/*案例:查詢員工的工資,要求

部門號=30,顯示的工資爲1.1倍
部門號=40,顯示的工資爲1.2倍
部門號=50,顯示的工資爲1.3倍
*/

SELECT salary AS 原始工資,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
    /*
    java中:
    if (條件1) {
        語句1:
    }else if(條件2){
        語句2:
    }else{
        語句n;
    }

    mysql中:
    case
    when 條件1 then 要顯示的值1(或語句1;)
    when 條件2 then 要顯示的值2(或語句2;)
    ...
    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;

#測試
#1.顯示系統時間(注: 日期+時間)
SELECT NOW();

#2.查詢員工號,姓名,工資,以及工資提升20%後的結果(new salary)
SELECT employee_id,last_name,salary,salary*1.2 AS "new salary"
FROM employees;

#3.將員工的姓名按首字母排序,並寫出姓名的長度(length)
SELECT last_name,LENGTH(last_name) AS 長度,SUBSTR(last_name,1,1) AS 首字母
FROM employees
ORDER BY 首字母;

#4.作一個查詢,產生下面的結果
<last_name> earns <salary> monthly but wants <salary*3>
Dream Salary
King earns 24000 monthly but wants 72000

SELECT CONCAT(last_name,' earns ',salary,' monthly  but wants ',salary*3) AS "Dream Salary"
FROM employees
WHERE salary=24000;

#5.使用case-when,按照下面的條件:
job 	grade
AD_PRES A
ST_MAN  B
IT_PROG C
SA_REP  D
ST_CLERK E
產生下面的結果
Last_name  Job_id  Grade
king       AD_PRES A

SELECT last_name,job_id AS job,
CASE job_id 
WHEN 'AD_PRES' THEN 'A'
WHEN 'ST_MAN'  THEN 'B'
WHEN 'IT_PROG' THEN 'C'
WHEN 'SA_REP' THEN 'D'
WHEN 'ST_CLERK' THEN 'E'
END AS Grade
FROM employees
WHERE job_id='AD_PRES';

分組函數

#2、分組函數
/*
功能:用於統計使用,又稱爲聚合函數或統計函數或組函數
分類:
sum 求和、avg 平均值、max 最大值、min 最小值、count 計算個數

特色:
一、sum、avg通常用於處理數值型
   max、min、count能夠處理任何類型
二、以上分組函數都忽略null值
三、能夠和distinct搭配使用,實現去重的統計
四、count函數
   count(字段):統計該字段非空值的個數
   count(*):統計結果集的行數
   count(1)也可用於統計結果集的行數
五、和分組函數一同查詢的字段要求是group by後的字段

*/
#一、簡單的使用
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) AS 和,
  ROUND(AVG(salary),2) AS 平均,
  MAX(salary) AS 最高,
  MIN(salary) AS 最低,
  COUNT(salary) AS 個數 
FROM
  employees ;
 
#二、參數支持哪些類型

SELECT SUM(last_name),AVG(last_name) FROM employees;
SELECT SUM(hiredate), AVG(hiredate) FROM employees;

SELECT MAX(last_name),MIN(last_name),COUNT(last_name) FROM employees;
SELECT MAX(hiredate),MIN(hiredate) FROM employees;

SELECT COUNT(commission_pct) FROM employees;
SELECT COUNT(last_name) FROM employees;

#三、是否忽略null

SELECT SUM(commission_pct), AVG(commission_pct),SUM(commission_pct)/35,SUM(commission_pct)/107 
FROM employees;

SELECT COUNT(commission_pct) FROM employees;
SELECT MAX(commission_pct), MIN(commission_pct) 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; 
SELECT COUNT(1) FROM employees;

效率:
MYISAM 存儲引擎下, COUNT(*)的效率最高
INNODB 存儲引擎下, COUNT(*)和count(1)的效率差很少,比count(字段)要高一些

#六、和分組函數一同查詢的字段有限制,要求是group by後出現的字段

SELECT AVG(salary),employee_id FROM employees;

#測試
#1、查詢公司員工工資的最大值、最小值、平均值、總和
SELECT MAX(salary),MIN(salary),ROUND(AVG(salary),2),SUM(salary)
FROM employees;

#2、查詢員工表中的最大入職時間和最小入職時間的相差天數(difference)
SELECT DATEDIFF('2021-3-18','2000-4-6');

SELECT DATEDIFF(MAX(hiredate),MIN(hiredate)) AS difference
FROM employees;

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

分組查詢

能夠用GROUP BY子句將表中的數據分紅若干組

SELECT column,group_function(colunmn)
from table
[where condition]
[group by group_by_expression]
[order by column];

明確:WHERE必定放在FROM後面

#進階5:分組查詢
/*
語法:
	SELECT 分組函數,列(要求出如今group by的後面)
	FROM 表
	[WHERE 篩選條件]
	[GROUP BY 分組的列表]
	[ORDER BY 子句];
注意:
	查詢列表比較特殊,要求是分組函數和group by後出現的字段
特色:
	一、分組查詢中的篩選條件分爲兩類
			數據源			位置			關鍵字
	分組前篩選	原始表			group by 子句的前面	where
	分組後篩選	分組後的結果集		group by 子句的後面	having
	
	①分組函數作條件確定是放在 having 子句中
	②能用分組前篩選的,就優先考慮使用分組前篩選
	
	二、group by 子句支持單個字段,多個字段分組(用,隔開,無順序要求),表達式或函數
	三、也能夠添加排序,放在整個分組查詢最後
*/
#引入:查詢每一個部門的平均工資
SELECT AVG(salary) FROM employees;

#案例1:查詢每一個工種的最高工資
#簡單的分組查詢
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
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
#1.查詢每一個部門的員工個數
SELECT COUNT(*),department_id
FROM employees
GROUP BY department_id;

#2.根據1的結果進行篩選,查詢哪一個部門的員工個數>2
SELECT COUNT(*),department_id
FROM employees
GROUP BY department_id
HAVING COUNT(*) > 2;

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

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

#按表達式或函數分組

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

#按多個字段分組

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

#添加排序
#案例:查詢每一個部門每一個工種的員工的平均工資,而且按平均工資的高低顯示
SELECT department_id,job_id,AVG(salary)
FROM employees
WHERE department_id IS NOT NULL
GROUP BY department_id,job_id
HAVING AVG(salary)>10000
ORDER BY AVG(salary) DESC;

#測試
#1.查詢各job_id的員工工資的最大值、最小值、平均值、總和,並按job_id升序
SELECT MAX(salary),MIN(salary),AVG(salary),SUM(salary),job_id
FROM employees
GROUP BY job_id
ORDER BY job_id;

#2.查詢員工最高工資和最低工資的差距(difference)
SELECT MAX(salary)-MIN(salary) AS difference
FROM employees;

#3.查詢每一個管理者手下員工的最低工資,其中最低工資不能低於6000,沒有管理者的員工不計算在內
SELECT MIN(salary) AS 最低工資,manager_id
FROM employees
WHERE manager_id IS NOT NULL
GROUP BY manager_id
HAVING 最低工資>=6000;

#4.查詢全部部門的編號,員工數量和工資平均值,並按平均工資降序
SELECT department_id,COUNT(*),AVG(salary)
FROM employees
GROUP BY department_id
ORDER BY AVG(salary) DESC;

#5.查詢各個job_id的員工人數
SELECT COUNT(*) AS 員工個數,job_id
FROM employees
GROUP BY job_id;

鏈接查詢

#進階6:鏈接查詢
/*
含義:又稱多表查詢,當查詢的字段來自多個表時,就會用到鏈接查詢

笛卡爾乘積現象:表1有m行,表2有n行,結果m*n行
發生緣由:沒有有效的鏈接條件,致使多個表全部行實現徹底鏈接
如何避免:添加有效的鏈接條件

分類:
	按年代分類:
	sql92標準:僅僅支持內鏈接(mysql),也支持一部分外鏈接(oracle、sqlserver)
	sql99標準[推薦]:支持內鏈接+外鏈接(左外和右外)+交叉鏈接
	
	按功能分類:
		內鏈接:
			等值鏈接
			非等值鏈接
			自鏈接
		外鏈接:
			左外鏈接
			右外鏈接
			全外鏈接(mysql不支持)
		交叉鏈接
*/
SELECT * FROM beauty;
SELECT * FROM boys;

SELECT NAME,boyName 
FROM boys,beauty
WHERE beauty.boyfriend_id = boys.id;

#1、sql92標準

#一、等值鏈接
/*
	①多表等值鏈接的結果爲多表的交集部分
	②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`;

#二、爲表起別名
/*
①提升語句的簡潔度
②區分多個重名的字段

注意:若是爲表起了別名,則查詢的字段就不能使用原來的表名去限定
*/
#查詢員工名、工種號、工種名
SELECT e.last_name,e.job_id,j.job_title
FROM employees AS e,jobs AS j
WHERE e.`job_id` = j.`job_id`;

#三、兩個表的順序是否能夠調換

#查詢員工名、工種號、工種名
SELECT e.last_name,e.job_id,j.job_title
FROM jobs AS j,employees AS e
WHERE e.`job_id` = j.`job_id`;

#四、能夠加篩選?

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

#案例2:查詢城市名中第二個字符爲o的部門名和城市名
SELECT department_name,city
FROM departments AS d,locations AS l
WHERE d.`location_id` = l.`location_id`
AND city LIKE '_o%';

#五、能夠加分組?

#案例1;查詢每一個城市的部門個數
SELECT COUNT(*) AS 部門個數, city
FROM departments AS d,locations AS l
WHERE d.`location_id`=l.`location_id`
GROUP BY city;

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

#六、能夠加排序

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

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

#七、能夠實現三表鏈接?

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

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;

#二、非等值鏈接

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

SELECT salary,grade_level
FROM employees e,job_grades j
WHERE salary BETWEEN j.`lowest_sal` AND j.`highest_sal`
AND j.`grade_level` = 'A';

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

#三、自鏈接
 
 #案例:查詢 員工名和上級的名稱
 
 SELECT e.employee_id AS 員工編號,e.last_name AS 員工名,m.employee_id AS 領導編號,m.last_name AS 領導名
 FROM employees AS e, employees AS m
 WHERE e.`manager_id`=m.`employee_id`;
 
 #測試1
 
 1、顯示員工表的最大工資,工資平均值
 SELECT MAX(salary),AVG(salary) 
 FROM employees;
 
 2、查詢員工表的employee_id,job_id,last_name,按department_id降序,salary升序
 SELECT employee_id,job_id,last_name,department_id,salary
 FROM employees
 ORDER BY department_id DESC,salary ASC;
 
 3、查詢員工表的job_id中包含a和e的,而且a在e的前面
 SELECT job_id
 FROM employees
 WHERE job_id LIKE '%a%e%' ;
 
 4、已知表student,裏面有id(學號),NAME,gradeId(年級編號)
 已知表grade,裏面有id(年級編號),NAME(年級名)
 已知表result,裏面有id,score,studentNo(學號)
 要求查詢姓名、年級名、成績
 
 SELECT s.name,g.name,r.score
 FROM student AS s,grade AS g,result AS r
 WHERE s.gradeId=g.id
 AND s.id=r.studentNo;
 
 5、顯示當前日期,以及去先後空格,截取子字符串的函數
 
 SELECT NOW();
 SELECT TRIM('a' FROM ' aaa ');
 SELECT SUBSTR(str,startIndex);
 SELECT SUBSTR(str,startIndex,LENGTH);
 
 #測試2
 #1.顯示全部員工的姓名,部門號和部門名稱
 SELECT last_name,d.department_id,department_name
 FROM employees e,departments d
 WHERE e.`department_id` = d.`department_id`;
 
 #2.查詢90號部門員工的job_id和90號部門的location_id
 SELECT e.job_id,d.location_id, d.department_id
 FROM employees e,departments d
 WHERE e.`department_id`=d.`department_id`
 AND e.`department_id`=90;
 
 #3.查詢全部有獎金的員工的last_name,department_name,location_id,city
 SELECT e.last_name,d.department_name,l.location_id,l.city
 FROM employees e,departments d,locations l
 WHERE e.`department_id` = d.`department_id`
 AND d.`location_id`= l.`location_id`
 AND e.`commission_pct`IS NOT NULL;
 
 #4.查詢city在Toronto工做的員工的last_name,job_id,department_id,department_name
 SELECT e.last_name,e.job_id,d.department_id,d.department_name
 FROM employees e,departments d,locations l
 WHERE e.`department_id` = d.`department_id`
 AND d.`location_id` = l.`location_id`
 AND l.`city`='Toronto';
 
 #5.查詢每一個工種、每一個部門的部門名、工種名和最低工資
 SELECT department_name,job_title,MIN(salary)
 FROM employees e,departments d, jobs j
 WHERE e.`department_id` = d.`department_id`
 AND e.`job_id` = j.`job_id`
 GROUP BY department_name,job_title;
 
 #6.查詢每一個國家下的部門個數大於2的國家編號
 SELECT country_id,COUNT(*) AS 部門個數
 FROM departments d,locations l
 WHERE d.`location_id` = l.`location_id`
 GROUP BY country_id
 HAVING 部門個數>2;
 
 #7.查詢指定員工的姓名,員工號,以及他的管理者的姓名和員工號,結果相似於下面的格式
 employees	Emp#	manager  Mgr#
 kochhar 	101     king     100
 
 SELECT e.last_name employees,e.employee_id "Emp#",m.last_name manager,m.employee_id "Mgr#"
 FROM employees e,employees m
 WHERE e.manager_id = m.employee_id
 AND e.last_name = 'kochhar';
                           
#2、sql99語法
 /*
 語法:
	select 查詢列表
	from 表1 別名 [鏈接類型]
	join 表2 別名
	on 鏈接條件
	[where 篩選條件]
	[group by 分組]
	[having 篩選條件]
	[order by 排序列表]
 分類:
 內鏈接:inner
 外鏈接
	左外:left [outer]
	右外:right [outer]
	全外:full[outer]
 交叉鏈接:cross
 */
 
 #1、內鏈接
 /*
語法:
	select 查詢列表
	from 表1 別名
	inner join 表2 別名
	on 鏈接條件
	
分類:
	等值
	非等值
	自鏈接
	
特色:
1.添加排序、分組、篩選
2.inner能夠省略
3.篩選條件放在where後面,鏈接條件放在on後面,提升分離性,便於閱讀
4.inner join鏈接和sql92語法中的等值鏈接效果是同樣的,都是查詢多表的交集
 */
 
 #一、等值鏈接
 #案例1:查詢員工名、部門名(調換位置)
 SELECT last_name,department_name
 FROM employees e
 INNER JOIN departments d
 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 l.`city`,COUNT(*) 部門個數
 FROM locations l
 INNER JOIN departments d
 ON d.`location_id`=l.`location_id`
 GROUP BY l.`city`
 HAVING COUNT(*)>3;
 
 #案例4:查詢部門員工個數>3的部門名和員工個數,並按個數降序(排序)
 SELECT department_name,COUNT(*) AS 員工個數
 FROM departments d
 INNER JOIN employees e
 ON d.`department_id` = e.`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;
 
 #2.非等值鏈接
 
 #查詢員工的工資級別
 SELECT salary,grade_level
 FROM employees e
 JOIN job_grades g
 ON e.`salary` BETWEEN g.lowest_sal AND g.highest_sal;
 
 #查詢人數>20的工資級別,而且按工資級別降序
 SELECT salary,grade_level,COUNT(*)
 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;
 
 #3.自鏈接
 
 #查詢員工的名字和上級的名字
 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%';
 
 #2、外鏈接
 
 /*
 應用場景:用於查詢一個表中有,另外一個表中沒有的記錄
 
 特色:
 一、外鏈接的查詢結果爲主表中全部記錄
	若是從表中有和它匹配的,則顯示匹配的值
	若是從表中沒有和它匹配的,則顯示null
	外鏈接查詢結果=內鏈接結果+主表中有而從表中沒有的記錄
 二、左外鏈接,left join 左邊的是主表
    右外鏈接,right join 右邊的是主表
 三、左外和右外交換兩個表的順序,能夠實現一樣的效果
 四、全外鏈接 = 內鏈接的結果 + 表1中有但表2沒有的 + 表2中有但表1沒有的
 */
 
 #引入:查詢男友不在boys表的女生名
 SELECT * FROM beauty;
 SELECT * FROM boys;
 
 #左外鏈接
 SELECT b.name,bo.`boyName`
 FROM beauty b
 LEFT OUTER JOIN boys bo
 ON b.`boyfriend_id`=bo.`id`
 WHERE bo.`id` IS NULL;
 
 #右外鏈接
 SELECT b.name,bo.`boyName`
 FROM boys bo
 RIGHT OUTER JOIN beauty b
 ON b.`boyfriend_id`=bo.`id`
 WHERE bo.id IS NULL;
 
 #案例1:查詢哪一個部門沒有員工
 #左外 
 SELECT department_name,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 department_name,e.employee_id
 FROM employees e
 RIGHT OUTER JOIN departments d
 ON e.`department_id`=d.`department_id`
 WHERE e.`employee_id` IS 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 vs sql99
 /*
 功能:sql99支持的較多
 可讀性:sql99實現鏈接條件和篩選條件的分離,可讀性較高
 */
                           
 #外鏈接題目
 #1.查詢編號>3的女神的男友信息,若是有則列出詳細,若是沒有,則用null填充
 SELECT  b.`id`,b.`name`,bo.*
 FROM beauty b
 LEFT OUTER JOIN boys bo
 ON b.`boyfriend_id`=bo.`id`
 WHERE b.`id`>3;
 
 #2.查詢哪一個城市沒有部門
 SELECT l.`city`
 FROM locations l
 LEFT OUTER JOIN departments d
 ON l.`location_id`=d.`location_id`
 WHERE d.`department_id` IS NULL;
 
 #3.查詢部門名爲SAL或IT的員工信息
 SELECT d.`department_name`,e.*
 FROM employees e
 RIGHT OUTER JOIN departments d
 ON d.`department_id`=e.`department_id`
 WHERE d.`department_name` IN('SAL','IT');

 #內鏈接查詢,比外鏈接少2條記錄(主表與從表不匹配的項)
 SELECT d.`department_name`,e.*
 FROM employees e
 INNER JOIN departments d
 ON e.`department_id`= d.`department_id`
 WHERE d.`department_name` IN('SAL','IT');

七種鏈接方式

image

image

子查詢

#進階7:子查詢
/*
含義:
出如今其餘語句中的select語句,成爲子查詢或內查詢
內部嵌套其餘select語句的查詢,稱爲主查詢或外查詢

分類:
按子查詢出現的位置:
	select後面:
		僅僅支持標量子查詢
	from後面:
		支持表子查詢
	where或having後面:★
		標量子查詢(單行)√
		列子查詢  (多行)√
		行子查詢
	exists後面(相關子查詢):
		全部子查詢均可以
按結果集的行列數不一樣:
	標量子查詢(結果集只有一行一列)
	列子查詢(結果集只有一列多行)
	行子查詢(結果集能夠有一行多列/多列多行)
	表子查詢(結果集通常爲多行多列)
*/
#1、where或having後面

#特色:
#①子查詢放在小括號內
#②子查詢通常放在條件的右側
#③標量子查詢,通常搭配着單行操做符使用
	單行操做符:> < >= <= = <>
#    列子查詢,通常搭配着多行操做符使用
	多行操做符: IN/NOT IN 等於列表中的任意一個
			     ANY/ SOME  和子查詢返回的某一個值比較
			     ALL 和子查詢返回的全部值比較
#④子查詢的執行優先於主查詢,主查詢的條件用到了子查詢的結果
	
	
#一、標量子查詢(單行子查詢)

#案例1:誰的工資比Abel高
SELECT *
FROM employees
WHERE salary>(
	SELECT salary
	FROM employees
	WHERE last_name = 'Abel'
);

#案例2:題目:返回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
);

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

SELECT last_name, job_id,salary
FROM employees
WHERE salary = (
	SELECT MIN(salary)
	FROM employees
);

#案例4:查詢最低工資>50號部門最低工資的部門id及其最低工資

SELECT MIN(salary),department_id
FROM employees
GROUP BY department_id
HAVING MIN(salary)>(
	SELECT MIN(salary)
	FROM employees
	WHERE department_id = 50
);

#二、列子查詢(多行子查詢)

#案例1:返回 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)
);

#案例2:返回其餘工種中比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_PROG';

#或
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_PROG';


#案例2:返回其餘工種中比job_id爲'IT_PROG'工種全部工資低的員工的:工號、姓名、job_id以及salary

SELECT employee_id,last_name,job_id,salary
FROM employees
WHERE salary < ALL(
	SELECT DISTINCT salary
	FROM employees
	WHERE job_id = 'IT_PROG'
)AND 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'
)AND job_id <> 'IT_PROG';

#三、行子查詢(結果集一行多列或多行多列)用的不多

#案例:查詢員工編號最小而且工資最高的員工信息

SELECT *
FROM employees
WHERE employee_id = (
	SELECT MIN(employee_id)
	FROM employees
)AND salary = (
	SELECT MAX(salary)
	FROM employees
);

SELECT *
FROM employees
WHERE (employee_id,salary) = (
	SELECT MIN(employee_id),MAX(salary)
	FROM employees
);

#2、select 後面

/*
僅僅支持標量子查詢
*/
#案例:查詢每一個部門的員工個數
SELECT d.*,(
	SELECT COUNT(*) 
	FROM employees e
	WHERE e.department_id = d.`department_id`
) AS 員工個數
FROM departments d;

SELECT d.*,COUNT(*)
FROM departments d
INNER JOIN employees e
ON e.`department_id`=d.`department_id`
GROUP BY department_id;

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

#3、from後面
/*
將子查詢結果充當一張表,要求必須起別名
*/
#案例:查詢每一個部門的平均工資的工資等級
#①查詢每一個部門的平均工資
SELECT AVG(salary),department_id
FROM employees
GROUP BY department_id 
#②鏈接①的結果集和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 
) AS ag_dep
INNER JOIN job_grades AS g
ON ag_dep.ag BETWEEN g.lowest_sal AND g.highest_sal;


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

*/
SELECT EXISTS(SELECT employee_id FROM employees WHERE salary=30000);

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

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

SELECT department_name,d.`department_id`
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 b.`boyfriend_id`=bo.`id`
);

#一、查詢和Zlotkey相同部門的員工姓名和工資
SELECT last_name,salary
FROM employees
WHERE department_id=(
	SELECT department_id
	FROM employees
	WHERE last_name='Zlotkey'
);

#二、查詢工資比公司平均工資高的員工的員工號,姓名和工資
SELECT employee_id,last_name,salary
FROM employees
WHERE salary>(
	SELECT AVG(salary)
	FROM employees
);

#三、查詢各部門中工資比本部門平均工資高的員工的員工號,姓名和工資

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

#四、查詢和姓名中包含字母u的員工在相同部門的員工的員工號和姓名
SELECT employee_id,last_name
FROM employees
WHERE department_id IN (
	SELECT DISTINCT department_id
	FROM employees
	WHERE last_name LIKE '%u%'
);

#五、查詢在部門的location_id爲1700的部門工做的員工的員工號
SELECT employee_id
FROM employees
WHERE department_id =ANY(
	SELECT DISTINCT department_id
	FROM departments
	WHERE location_id = 1700
);

#六、查詢管理者是king的員工姓名和工資

SELECT last_name,salary
FROM employees
WHERE manager_id IN (
	SELECT employee_id
	FROM employees
	WHERE last_name = 'K_ing'
);

#七、查詢工資最高的員工的姓名,要求first_name和last_name顯示爲一列,列名爲 姓.名

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

分頁查詢

#進階8:分頁查詢 ★

/*
應用場景:當咱們要顯示的數據 ,一頁顯示不全,須要分頁提交sql請求
語法:
	select 查詢列表
	from 表
	[join type join 表2
	on 鏈接條件
	where 篩選條件
	group by 分組字段
	having 分組後的篩選
	order by 排序的字段]
	limit offset,size;
	
	offset 要顯示條目的起始索引(起始索引從0開始)
	size 要顯示的條目個數
特色:
	①limit語句放在查詢語句的最後
	②公式:
	要顯示的頁數page,每頁的條目數size
	select 查詢列表
	from 表
	limit (page-1)*size,size;
*/
#案例1:查詢前五條員工信息
SELECT *
FROM employees
LIMIT 0,5;

#若是起始索引是0,能夠省略
SELECT *
FROM employees
LIMIT 5;

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

#案例3:有獎金的員工信息,而且工資較高的前10名顯示出來
SELECT *
FROM employees
WHERE commission_pct IS NOT NULL
ORDER BY salary DESC
LIMIT 10;
#複習小測試
/*
已知表stuinfo
id 學號
name 姓名
email 郵箱 john@126.com
gradeId 年級編號
sex 性別 男 女
age 年齡

已知表 grade
id 年級編號
gradeName 年級名稱
*/
#1、查詢全部學員的郵箱的用戶名(注:郵箱中@前面的字符)
SELECT SUBSTR(email,1,INSTR(email,'@')-1) 用戶名
FROM stuinfo;

#2、查詢男生和女生的個數
SELECT COUNT(*) AS 個數,sex
FROM stuinfo
GROUP BY sex;

#3、查詢年齡>18歲的全部學生的姓名和年級名稱
SELECT NAME,gradeName
FROM stuinfo s
INNER JOIN grade g
ON s.gradeId = g.id
WHERE age>18;

#4、查詢哪一個年級的學生最小年齡>20歲
SELECT MIN(age),gradeId
FROM stuinfo
GROUP BY gradeId
HAVING MIN(age)>20;

#5、試說出查詢語句中涉及到的全部關鍵字,以及執行前後順序
SELECT 查詢列表
FROM 表
鏈接類型 JOIN 表2
ON 鏈接條件
WHERE 篩選條件
GROUP BY 分組列表
HAVING 分組後的篩選
ORDER BY 排序列表
LIMIT 起始索引/偏移,條目數;

執行順序: FROM->JOIN->ON->WHERE->GROUP BY->HAVING->SELECT->ORDER BY->LIMIT

子查詢經典案例

#一、查詢工資最低的員工信息:last_name,salary
SELECT last_name,.salary
FROM employees
WHERE salary=(
	SELECT MIN(salary)
	FROM employees
);

#二、查詢平均工資最低的部門信息
#方式一:
SELECT d.*
FROM departments d
WHERE d.`department_id`=(
	SELECT department_id
	FROM employees
	GROUP BY department_id
	HAVING AVG(salary)=(
		SELECT MIN(ag)
		FROM (
			SELECT AVG(salary) ag,department_id
			FROM employees
			GROUP BY department_id
		) ag_dep
	)
);

#方式二
SELECT *
FROM departments
WHERE department_id=(
	SELECT department_id
	FROM employees
	GROUP BY department_id
	ORDER BY AVG(salary)
	LIMIT 1
);

#三、查詢平均工資最低的部門信息和該部門的平均工資
SELECT d.*,ag
FROM departments d
JOIN(
	SELECT department_id,AVG(salary) ag
	FROM employees
	GROUP BY department_id
	ORDER BY AVG(salary)
	LIMIT 1
) ag_dep
ON d.`department_id`=ag_dep.department_id;

#四、查詢平均工資最高的job信息
SELECT *
FROM jobs
WHERE job_id=(
	SELECT job_id
	FROM employees 
	GROUP BY job_id
	ORDER BY AVG(salary) DESC
	LIMIT 1
);

#五、查詢平均工資高於公司平均工資的部門有哪些?
SELECT AVG(salary),department_id
FROM employees
GROUP BY department_id
HAVING AVG(salary)>(
	SELECT AVG(salary)
	FROM employees
);

#六、查詢公司中全部manager的詳細信息
SELECT *
FROM employees
WHERE employee_id IN (
	SELECT manager_id
	FROM employees
);

#七、各個部門中 最高工資中最低的那個部門的最低工資是多少
SELECT MIN(salary)
FROM employees
WHERE department_id=(
	SELECT department_id
	FROM employees
	GROUP BY department_id
	ORDER BY MAX(salary)
	LIMIT 1
);

#八、查詢平均工資最高的部門的manager的詳細信息:last_name,department_id,email,salary
SELECT  last_name,department_id,email,salary
FROM employees
WHERE employee_id = (
	SELECT manager_id
	FROM departments
	WHERE department_id = (
		SELECT  department_id
		FROM employees
		GROUP BY department_id
		ORDER BY AVG(salary) DESC
		LIMIT 1
	)
);

複習題

#1、查詢每一個專業的學生人數
SELECT majorid,COUNT(*)
FROM student
GROUP BY majorid;

#2、查詢參加考試的學生中,每一個學生的平均分、最高分
SELECT AVG(score),MAX(score),studentno
FROM result
GROUP BY studentno;

#3、查詢姓張的學生中最低分大於60的學生的學號、姓名
SELECT s.`studentname`,s.`studentno` ,MIN(score)
FROM student s
INNER JOIN result r
ON s.`studentno`=r.`studentno`
WHERE s.`studentname` LIKE '張%'
GROUP BY studentno
HAVING MIN(score)>60;

#4、查詢每一個專業生日在‘1988-1-1’後的學生姓名、專業名稱
SELECT studentname, majorname,borndate
FROM student s
JOIN major m
ON s.`majorid`=m.`majorid`
WHERE DATEDIFF(s.`borndate`,'1988-1-1')>0;

#5、查詢每一個專業的男生人數和女生人數分別是多少
#方式一:
SELECT COUNT(*),sex,majorid
FROM student
GROUP BY sex,majorid;

#方式二:
SELECT s.majorid,
(SELECT COUNT(*) FROM student WHERE sex='男' AND majorid=s.`majorid`) 男,
(SELECT COUNT(*) FROM student WHERE sex='女' AND majorid=s.`majorid`) 女
FROM student s
GROUP BY majorid;

#6、查詢專業和張翠山同樣的學生的最低分
SELECT MIN(score)
FROM result
WHERE studentno IN(
	SELECT studentno
	FROM student
	WHERE majorid=(
		SELECT majorid
		FROM student
		WHERE studentname='張翠山'
	)
);

#7、查詢大於60分的學生的姓名、密碼、專業名
SELECT studentname,loginpwd,majorname
FROM student s
INNER JOIN major m ON s.`majorid`=m.`majorid`
JOIN result  r ON s.`studentno`=r.`studentno`
WHERE r.`score`>60;

#8、按郵箱位數分組,查詢每組的學生個數
SELECT COUNT(*),LENGTH(email)
FROM student
GROUP BY LENGTH(email);

#9、查詢學生名、專業名、分數
SELECT studentname,majorname,score
FROM student s
INNER JOIN major m ON s.`majorid`=m.`majorid`
LEFT JOIN result r ON s.`studentno`=r.`studentno`;

#10、查詢哪一個專業沒有學生,分別用左鏈接和右鏈接實現
SELECT m.`majorid`,m.`majorname`,studentno 
FROM major m
LEFT JOIN student s ON m.`majorid`=s.`majorid`
WHERE studentno IS NULL;

SELECT m.`majorid`,m.`majorname`,studentno 
FROM student s
RIGHT JOIN major m ON m.`majorid`=s.`majorid`
WHERE studentno IS NULL;

#11、查詢沒有成績的學生人數
SELECT COUNT(*)
FROM student s
LEFT JOIN result r 
ON s.`studentno`=r.`studentno`
WHERE r.score IS NULL;s

聯合查詢

#進階9:聯合查詢
/*
union 聯合 合併:將多條查詢語句的結果合併成一個結果

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

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

特色:
一、要求多條查詢語句的查詢列表是一致的!
二、多條查詢語句的查詢的每一列的類型和順序最好一致
三、union關鍵字默認去重,若是使用 union all 能夠包含重複項

*/

#引入的案例:查詢部門編號>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,csex FROM t_ca WHERE csex='男'
UNION ALL
SELECT t_id,tName,tGender FROM t_ua WHERE tGender='male';

DML(Data Manipulation Language)

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

*/

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

特色:
一、要求值的類型和字段的類型要一致或兼容
二、字段的個數和順序不必定與原始表中的字段個數和順序一致
   但必須保持值和字段一一對應
三、假如表中有能夠爲NULL的字段,能夠經過如下兩種方式插入null值
①字段和值都省略
②字段寫上,值使用null
四、字段和值的個數必須一致
五、字段名能夠省略,默認全部列

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

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

#方式二:
INSERT INTO beauty(id,NAME,sex,borndate,phone,boyfriend_id)
VALUES(14,'金星','女','1990-4-23','19889898989',9);

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

#三、列的順序是否能夠調換
INSERT INTO beauty(NAME,sex,id,phone)
VALUES('蔣欣','女',16,'110');

#四、列數和值的個數必須一致
INSERT INTO beauty(NAME,sex,id,phone,boyfriend_id)
VALUES('關曉彤','女',17,'110');

#五、能夠省略列名,默認全部列
INSERT INTO beauty()
VALUES(18,'張飛','男',NULL,'119',NULL,NULL);

#方式二:
/*
insert into 表名
set 列名=值,列名=值, ....
*/

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

#兩種方式的區別:

#一、方式一支持插入多行,方式二不支持
INSERT INTO beauty
VALUES(20,'唐藝昕1','女','1990-4-23','18989898989',NULL,2),
(21,'唐藝昕2','女','1990-4-23','18989898989',NULL,2),
(22,'唐藝昕3','女','1990-4-23','18989898989',NULL,2);

#二、方式一支持子查詢,方式二不支持
INSERT INTO beauty(id,NAME,phone)
SELECT 26,'宋茜','123456';

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

#2、修改語句
/*
一、修改單表中的記錄★
語法:
update 表名
set 列=新值,列=新值, ...
[where 篩選條件];
執行順序:update -> where -> set

二、修改多表的記錄[補充]

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

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

#一、修改單表的記錄

#案例1:修改beauty表中姓唐的女神的電話爲13883388337
UPDATE beauty
SET phone='13883388337'
WHERE NAME LIKE '唐%';

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

#二、修改多表的記錄

#案例1:修改張無忌的女友的手機號爲114
UPDATE boys bo
INNER JOIN beauty b
ON bo.`id`=b.`boyfriend_id`
SET b.`phone`='114'
WHERE bo.`boyName`='張無忌';

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

#3、刪除語句
/*
方式一:delete
語法:
一、單表的刪除 ★
delete from 表名 [where 篩選條件][limit ];

二、多表的刪除[補充]

sql92語法:
delete 表1的別名,表2的別名
from 表1 別名, 表2 別名
where 鏈接條件
and 篩選條件;

sql99語法:
delete 表1的別名,表2的別名
from 表1 別名
inner | left | rigth join 表2 別名 on 鏈接條件
[where 篩選條件];

方式二:truncate
語法:truncate table 表名;
*/
SELECT * FROM beauty;

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

DELETE FROM beauty
WHERE phone LIKE '%9';

#二、多表的刪除

#案例1:刪除張無忌的女友的信息
DELETE b
FROM boys bo
INNER JOIN beauty b
ON bo.id = b.boyfriend_id
WHERE bo.boyName='張無忌';

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

#方式二:truncate語句
#案例1:將魅力值>100的男神信息刪除
TRUNCATE TABLE boys;

#delete和truncate的區別
/*
一、delete 能夠加where條件,TRUNCATE 不能加
二、truncate 效率高
三、假如要刪除的表中有自增加列,若是用delete刪除後,再插入數據,自增加列的值從斷點開始,
     					  而truncate刪除後,再插入數據,自增加列的值從1開始
四、truncate 刪除沒有返回值,delete刪除返回受影響的行數
五、truncate 刪除不能回滾,delete刪除能夠回滾
*/
SELECT * FROM boys;

DELETE FROM boys;
INSERT INTO boys(boyName,usercp)
VALUES('劉備',100),('張飛',200),('關雲長',300);

TRUNCATE TABLE boys;

案例

#一、運行如下腳本建立表my_employees
USE myemployees;
CREATE TABLE my_employees(
	Id INT(10),
	First_name VARCHAR(10),
	Last_name VARCHAR(10),
	Userid VARCHAR(10),
	Salary DOUBLE(10,2)
);
CREATE TABLE users(
	id INT,
	userid VARCHAR(10),
	department_id INT
);

#二、顯示錶my_employees的結構
DESC my_employees;

#三、向my_employees表中插入下列數據
#方式一:
INSERT INTO my_employees
VALUES(1,'patel','Ralph','Rpatel',895),
(2,'Dancs','Betty','Bdances',860),
(3,'Biri','Ben','Bbiri',1100),
(4,'Newman','Chad','Cnewman',750),
(5,'Ropeburn','Audrey','Aropebur',1550);

DELETE FROM my_employees;
#方式二:
INSERT INTO my_employees
SELECT 1,'patel','Ralph','Rpatel',895 UNION
SELECT 2,'Dancs','Betty','Bdances',860 UNION
SELECT 3,'Biri','Ben','Bbiri',1100 UNION
SELECT 4,'Newman','Chad','Cnewman',750 UNION
SELECT 5,'Ropeburn','Audrey','Aropebur',1550;

#四、向users表中插入數據

INSERT INTO users
VALUES(1,'Rpatel',10),
(2,'Bdances',10),
(3,'Bbiri',20),
(4,'Cnewman',30),
(5,'Aropebur',40);

#五、將3號員工的last_name修改成'drelxer'
UPDATE my_employees
SET last_name='drelxer'
WHERE id=3;

#六、將全部工資少於900的員工的工資修改成1000
UPDATE my_employees
SET salary=1000
WHERE salary<900;

#七、將userid爲Bbiri的users表和my_employees表的記錄所有刪除
DELETE u,e
FROM users u
JOIN my_employees e
ON u.`userid`=e.`Userid`
WHERE e.userid='Bbiri'; 

#八、刪除全部數據
DELETE FROM my_employees;
DELETE FROM users;

#九、檢查所做的修正
SELECT * FROM my_employees;
SELECT * FROM users;

#十、清空表my_employees
TRUNCATE TABLE my_employees;

DDL(Data Definition Language)

#DDL數據定義語言
/*
庫和表的管理

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

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

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

#1、庫的管理

#一、庫的建立
/*
語法:
create database [if not exists] 庫名 [character set 字符集名];
*/

#案例:建立庫Books
CREATE DATABASE IF NOT EXISTS Books;

#二、庫的修改
RENAME DATABASE books TO 新庫名;

#更改庫的字符集
ALTER DATABASE books CHARACTER SET gbk;

#三、庫的刪除

DROP DATABASE IF EXISTS books;

#2、表的管理
#一、表的建立 ★

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

#案例:建立表Book
CREATE TABLE IF NOT EXISTS book(
	id INT, #書的編號
	bName VARCHAR(20), #圖書名
	price DOUBLE, #價格
	authorId INT, #做者編號
	publishDate DATETIME #出版日期
);
DESC book;

CREATE TABLE author(
	id INT,
	aName VARCHAR(20),
	nation VARCHAR(10)
);
DESC author;

#二、表的修改
/*
alter table 表名 add|drop|modify|change [column] 列名 [列類型 約束] [first|after 字段名];
*/

#①修改列名
ALTER TABLE 表名 CHANGE COLUMN 舊列名 新列名 類型;
#②修改列的類型或約束
ALTER TABLE 表名 MODIFY COLUMN 列名 新類型【新約束】; 
#③添加新列
ALTER TABLE 表名 ADD COLUMN 列名 類型;
#④刪除列(不能夠加if exists)
ALTER TABLE 表名 DROP COLUMN 列名;
#⑤修改表名
ALTER TABLE 表名 RENAME TO 新表名;

#三、表的刪除

DROP TABLE [IF EXISTS] 表名;
SHOW TABLES;
#
#通用的寫法:
DROP DATABASE IF EXISTS 舊庫名;
CREATE DATABASE 新庫名;

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

#四、表的複製

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

#①僅僅複製表的結構
CREATE TABLE 表名 LIKE 舊錶名;

#②複製表的結構+數據
CREATE TABLE 表名
SELECT * FROM 舊錶名;

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

#僅僅複製某些字段
CREATE TABLE 表名
SELECT id,aname
FROM author
WHERE 0;#恆不成立

案例

#1、建立表dept1
USE test;

CREATE TABLE dept1(
	id INT(7),
	NAME VARCHAR(25)
);

#2、將表departments中的數據插入到新表dept2中
CREATE TABLE dept2
SELECT department_id,department_name
FROM myemployees.departments;

#3、建立表emp5
CREATE TABLE emp5(
	id INT(7),
	First_name VARCHAR(25),
	Last_name VARCHAR(25),
	Dept_id INT(7)
);

#4、將Last_name的長度增長到50
ALTER TABLE emp5 MODIFY COLUMN last_name VARCHAR(50);

#5、根據表employees建立employees2
CREATE TABLE employees2 LIKE myemployees.`employees`;

#6、刪除表emp5
DROP TABLE IF EXISTS emp5;

#7、將表employees2重命名爲emp5
ALTER TABLE employees2 RENAME TO emp5;

#8、在表dept和emp5中添加新列test_column,並檢查所做的操做
ALTER TABLE dept2 ADD COLUMN test_column INT;
ALTER TABLE emp5 ADD COLUMN test_column INT;

#9、直接刪除表emp5中的列dept_id
ALTER TABLE emp5 DROP COLUMN test_column;

數據類型

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

#1、整型
/*
分類:
tinyint   1byte
smallint	  2byte
mediumint 	3byte
int/integer	4byte
bigint	8byte

特色:
①若是不設置無符號仍是有符號,默認是有符號,若是想設置無符號,須要添加unsigned關鍵字
②若是插入的數值超出了整型的範圍,會報out of range異常,插入失敗
③若是不設置長度,會有默認的長度(通過嘗試發現新版Mysql已經去除對int的長度限制)
通過嘗試發現zerofill也被廢除,mysql建議用lpad進行左填充
*/

#一、如何設置無符號和有符號
CREATE TABLE tab_int(
	t1 INT ,
	t2 INT UNSIGNED
);

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

#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
#新版本mysql提示不同意爲浮點數據類型指定位數,並將在未來的版本中刪除
CREATE TABLE tab_float(
	f1 FLOAT(5,2),
	f2 DOUBLE(5,2),
	f3 DEC(5,2)
);
#不帶M和D
CREATE TABLE tab_float(
	f1 FLOAT,
	f2 DOUBLE,
	f3 DEC
);

#成功插入數據
INSERT INTO tab_float VALUES(123.45,123.45,123.45);
#插入的數據小數部分被四捨五入
INSERT INTO tab_float VALUES(123.456,123.456,123.456);
#自動爲小數部分補0
INSERT INTO tab_float VALUES(123.4,123.4,123.4);
#報錯:Out of range value for column 'f1' at row 1
INSERT INTO tab_float VALUES(1523.4,1523.4,1523.4);

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

#3、字符型
/*
較短的文本:
char(M)			M爲最大字符數 0~255
varchar(M)					0~65535

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

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

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

*/

#枚舉類型,要求插入的值必須屬於列表中指定的值之一
/*
若是列表成員爲1~255,則須要1個字節存儲
若是列表成員爲255~65535,則須要2個字節存儲
*/
CREATE TABLE tab_char(
	c1 ENUM('a','b','c')
	
);
SELECT * FROM tab_char;

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

#Set類型
/*
和Enum類型相似,裏面能夠保存0~64個成員。和Enum類型最大的區別是:
Set類型一次能夠選取多個成員,而Enum只能選一個
根據成員個數不用,存儲所佔的字節也不一樣
成員數		字節數
1~8			1	
9~16		2
17~24		3	
25~32		4
33~64		8
*/

CREATE TABLE tab_set(
	s1 SET('a','b','c','d')
);
SELECT * FROM tab_set;

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

#4、日期型
/*
分類:
date只保存日期
time只保存時間
year只保存年
datetime保存日期+時間
timestamp保存日期+時間

特色:
			字節		範圍			時區等的影響
datetime		8		1000-9999	不受
timestamp		4		1970-2038	受

datatime 和 timestamp 的區別
一、timestamp支持的時間範圍較小,取值範圍:1970 01 01 08 0001~2038年的某個時間
    datatime的取值範圍:1000-1-1 ~ 9999-12-31
二、timestamp和實際時區有關,更能反映實際的日期,而datatime則只能反映出插入時的當地時區
三、timestamp的屬性受mysql版本的SQLMode的影響很大
*/

CREATE TABLE tab_date(
	t1 DATETIME,
	t2 TIMESTAMP
);
SELECT * FROM tab_date;
INSERT INTO tab_date VALUES(NOW(),NOW());

SHOW VARIABLES LIKE 'time_zone';
SET time_zone = '+9:00';

約束

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

分類:六大約束
	NOT NULL:非空約束,用於保證該字段的值不能爲空,好比姓名、學號等
	DEFAULT:默認約束,用於保證該字段的值有默認值,好比性別
	PRIMARY KEY:主鍵約束,用於保證該字段的值具備惟一性,而且非空,好比學號、員工編號
	UNIQUE KEY:惟一約束,用於保證該字段的值具備惟一性,可是能夠爲空,好比座位號
	CHECK:檢查約束[mysql不支持],好比年齡、性別
	FOREIGN KEY:外鍵約束,用於限制兩個表的關係,用於保證該字段的值必須來自於主表的關聯列的值
				      在從表添加外鍵約束,用於引用主表中某列的值,好比學生表的專業編號,員工表的部門編號、工種編號	      

添加約束的時機:
	一、建立表時
	二、修改表時
	
約束的添加分類:
	列級約束:
		六大約束語法上都支持,但外鍵約束沒有效果
	表級約束:
		除了非空、默認,其餘的都支持
		
主鍵和惟一的對比:
					保證惟一性	是否容許爲空	一個表中能夠有多少個	是否容許組合
			主鍵	√			×				至多有1個				√,但不推薦
			惟一	√			√(只能有1個)	能夠有多個				√,但不推薦
			
外鍵:
	一、要求在從表設置外鍵關係
	二、從表的外鍵列的類型和主表的關聯列的類型要求一致或兼容,名稱無要求
	三、要求主表中的關聯列必須是一個key(通常是主鍵或惟一)
	四、插入數據時,先插入主表的數據,再插入從表
	       刪除數據時,先刪除從表,再刪除主表
*/
CREATE TABLE 表名(
	字段名 字段類型 列級約束,
	字段名 字段類型,
	表級約束
);

#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) #外鍵約束
);

CREATE TABLE major(
	id INT PRIMARY KEY,
	majorName VARCHAR(20)
 );
 
 DESC stuinfo;
 #查看stuinfo表中全部的索引,包括主鍵、外鍵、惟一
 SHOW INDEX FROM stuinfo;
 
 #二、添加表級約束
 /*
語法:在各個字段的最下面
[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 stuinfo(
	id INT,
	stuName VARCHAR(20),
	gender CHAR(1),
	seat INT,
	age INT,
	majorId INT,
	
	PRIMARY KEY(id),#主鍵
	UNIQUE(seat),#惟一鍵
	CHECK(gender='男' OR gender = '女'),#檢查
	FOREIGN KEY(majorId) REFERENCES major(id)#外鍵
);

#通用寫法
CREATE TABLE IF NOT EXISTS stuinfo(
	id INT PRIMARY KEY,
	stuName VARCHAR(20) NOT NULL,
	gender CHAR(1),
	age INT DEFAULT 18,
	seat INT UNIQUE,
	majorId INT,
	CONSTRAINT fk_stuinfo_major FOREIGN KEY(majorId) REFERENCES major(id)
);

#2、修改表時添加約束
/*
一、添加列級約束
alter table 表名 modify column 字段名 字段類型 新約束;
二、添加表級約束
alter table 表名 add [constraint 約束名] 約束類型(字段名) [外鍵的引用];
*/
CREATE TABLE IF NOT EXISTS stuinfo(
	id INT ,
	stuName VARCHAR(20),
	gender CHAR(1),
	age INT,
	seat INT,
	majorId INT
);
desc stuinfo;
#一、添加非空約束
alter table stuinfo modify column stuName varchar(20) not null;
#二、添加默認約束
alter table stuinfo modify column age int default 18;
#三、添加主鍵
#①列級約束
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);

#五、添加外鍵
alter table stuinfo
add constraint fk_stuinfo_major foreign key (majorId) references major(id);

#3、修改表時刪除約束
desc stuinfo;
#一、刪除非空約束
alter table stuinfo modify column stuName varchar(20) null;
#二、刪除默認約束
alter table stuinfo modify column age int;
#三、刪除主鍵
alter table stuinfo drop primary key ;
#四、刪除惟一
alter table stuinfo drop index seat;
#五、刪除外鍵
show index from stuinfo;
alter table stuinfo drop constraint fk_stuinfo_major;
alter table stuinfo drop foreign key fk_stuinfo_major;
drop index fk_stuinfo_major on stuinfo;

標識列

#標識列
/*
又稱爲自增加列
含義:能夠不用手動插入值,系統提供默認的序列值

特色:
一、標識列必須和主鍵搭配嗎?不必定,但要求是一個key
二、一個表中能夠有幾個標識列?至多一個!
三、標識列的類型只能是數值型
四、標識列能夠經過set auto_increment_increment = 1;設置步長
            經過set auto_increment_offset = 1;修改起始值
*/

#1、建立表時設置標識列
drop table tab_identity;
create table tab_identity(
    id int ,
    name varchar(20)
);
truncate table tab_identity;
insert into tab_identity values(null,'john');
select * from tab_identity;
show variables like '%auto_increment%';

set auto_increment_increment = 1;#
set auto_increment_offset = 1;#起始值

#2、修改表時設置標識列
desc tab_identity;
alter table tab_identity modify column id int primary key auto_increment;

#3、修改表時刪除標識列
alter table tab_identity modify column id int ;

TCL(Transaction Control Language)

事務

事務由單獨單元的一個或多個sql語句組成,在這個單元中,每條sql語句是相互依賴的。而整個單獨單元做爲一個不可分割的總體,若是單元中某條sql語句一旦執行失敗或產生錯誤,整個單元將會回滾。全部受到影響的數據將返回到事務開始之前的狀態;若是單元中的全部sql語句均執行成功,則事務被順利執行。

MySQL中的存儲引擎

  • 在mysql中的數據用各類不一樣的技術存儲在文件(或內存)中。
  • 經過show engines;來查看mysql支持的存儲引擎
  • 在mysql中用的最多的存儲引擎有:innodb, myisam, memory 等。其中innodb支持事務,而myisam、memory等不支持事務。

事務的ACID屬性

  1. 原子性(Atomicity)

    原子性是指事務是一個不可分割的工做單位,事務中的操做要麼都發生,要麼都不發生。

  2. 一致性(Consistency)

    事務必須使數據庫從一個一致性狀態變換到另一個一致性狀態

  3. 隔離性(Isolation)

    事務的隔離性是指一個事務的執行不能被其餘事務干擾,即一個事務內部的操做及使用的數據對併發的其餘事務是隔離的,併發執行的各個事務之間不能互相干擾。

  4. 持久性(Durability)

    持久性是指一個事務一旦被提交,它對數據庫中數據的改變就是永久性的,接下來的其餘操做和數據庫故障不該該對其有任何影響

數據庫的隔離級別

對於同時運行的多個事務,當這些事務訪問數據庫中相同的數據時,若是沒有采起必要的隔離機制,就會致使各類併發問題。

髒讀:對於兩個事務T一、T2,T1讀取了已經被T2更新但還沒有被提交的字段以後,若T2回滾,T1讀取的內容就是臨時且無效的。

不可重複讀:對於兩個事務T一、T2,T1讀取了一個字段,而後T2更新了該字段以後,T1再次讀取同一個字段,值就不一樣了。

幻讀:對於兩個事務T一、T2,T1從一個表中讀取了一個字段,而後T2在該表中插入了一些新的行以後,若是T1再次讀取同一個表,就會多出幾行。

數據庫事務的隔離性:數據庫系統必須具備隔離併發運行各個事務的能力,使它們不會相互影響,避免各類併發問題。

一個事務與其餘事務隔離的程度稱爲隔離級別,數據庫規定了多種事務隔離級別,不一樣隔離級別對應不一樣的干擾程度,隔離級別越高,數據一致性就越好,但併發性越弱。

  • Oracle支持的2種事務隔離級別:READ COMMITED,SERIALIZABLE。Oracle默認的事務隔離級別爲:READ COMMITED
  • Mysql支持4種事務隔離級別。Mysql默認的事務隔離級別爲:REPEATABLE READ

注意:

  • 通過測試,發現新版本mysql的REPEATABLE READ已經能夠避免幻讀

經常使用命令

  • 每啓動一個mysql程序,就會得到一個單獨的數據庫鏈接,每一個數據庫鏈接都有一個全局變量@transaction_isolation,表示當前的事務隔離級別
  • 查看當前的事務隔離級別:show variables like 'transaction_isolation';
  • 設置當前mysql鏈接的隔離級別:set session transaction isolation level 級別;
  • 設置數據庫系統的全局的隔離級別:set global transaction isolation level 級別;

視圖

視圖:MySQL從5.0.1版本開始提供視圖功能。一種虛擬存在的表,行和列的數據來自自定義視圖的查詢中使用的表,而且是在使用視圖時動態生成的,只保存了sql邏輯,不保存查詢結果

應用場景:

  • 多個地方用到一樣的查詢結果
  • 該查詢結果使用的sql語句較複雜

好處:

  • 重用sql語句
  • 簡化複雜的sql操做,沒必要知道它的查詢細節
  • 保護數據,提升安全性

權限

視圖的可更新性和視圖中查詢的定義有關係,如下類型的視圖是不能更新的。

  • 包含如下關鍵字的sql語句:分組函數、distinct、group by、having、union或者union all
  • 常量視圖
  • Select中包含子查詢
  • join
  • from一個不能更新的視圖
  • where子句的子查詢引用了from子句中的表
相關文章
相關標籤/搜索