數據庫(datebase):存儲數據的「倉庫」。他保存了一系列有組織的數據。java
數據庫管理系統(Datebase Management System)。數據庫是經過DBMS建立和操做的容器mysql
常見的數據庫管理系統:MySQL、Oracle(太貴了)、DB2(適合處理海量數據)、SqlServer(微軟的,只能在安裝在Windows)等面試
結構化查詢語言(Structure Query Language):專門用來與數據庫通訊的語言。sql
一、不是某個特定數據庫供應商專有的語言,幾乎全部DBMS都支持SQL數據庫
二、簡單易學express
三、雖然簡單,但其實是一種強有力的語言,靈活使用其語言元素,能夠進行很是複雜和高級的數據庫操做。windows
一、將數據放到表中,表再放到庫中安全
二、一個數據庫中能夠有多個表,每一個表都有一個名字,用來標識本身。表名具備惟一性。服務器
三、表具備一些特性,這些特性定義了數據在表中如何存儲,相似 JAVA 中「類」的設計。session
四、表由列組成,咱們也稱爲字段。全部表都是由一個或多個列組成的,每一列相似 JAVA 中的「屬性」
五、表中的數據是按行存儲的,每一行相似於JAVA中的「對象」
net stop mysqlxxx
中止 -> net start mysqlxxx
啓動方式一 : 經過mysql自帶的客戶端 (只限於root用戶)
方法二 : 經過windows的cmd
完整的輸入爲:mysql -h localhost(主機名) -P3306(端口號) -u(用戶名) root -p(密碼)
簡略的輸入爲:mysql -u root -p
show databases;
查看當前全部的庫
user 庫名;
打開指定的庫
show tables;
查看當前庫下的表
show tables from 庫名;
顯示指定庫下的表
-- 建立表 create table 表名( 列名 列類型, 列名 列類型, 列名 列類型 )
select database();
顯示當前處於哪一個庫
desc 表名;
查看錶格結構
select * from 表名;
查看錶格數據
select version();
查看MySQL版本
mysql --version
或 mysql -V
cmd下查看MySQL版本
一、不區分大小寫,但建議關鍵字大寫,表名、列名小寫
二、建議每條命令用 ; 結尾(用\g也能夠)
三、每條命令根據須要,能夠進行縮進或換行
四、註釋
單行註釋:#註釋文字 單行註釋:-- 註釋文字 多行註釋: /* 註釋文字 */
``表明着重號,加不加均可以,當字段和關鍵字混淆時須要爲字段加上着重號
#進階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');
#進階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語言 /* 數據操做語言: 插入: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數據定義語言 /* 庫和表的管理 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 ;
事務由單獨單元的一個或多個sql語句組成,在這個單元中,每條sql語句是相互依賴的。而整個單獨單元做爲一個不可分割的總體,若是單元中某條sql語句一旦執行失敗或產生錯誤,整個單元將會回滾。全部受到影響的數據將返回到事務開始之前的狀態;若是單元中的全部sql語句均執行成功,則事務被順利執行。
show engines;
來查看mysql支持的存儲引擎原子性(Atomicity)
原子性是指事務是一個不可分割的工做單位,事務中的操做要麼都發生,要麼都不發生。
一致性(Consistency)
事務必須使數據庫從一個一致性狀態變換到另一個一致性狀態。
隔離性(Isolation)
事務的隔離性是指一個事務的執行不能被其餘事務干擾,即一個事務內部的操做及使用的數據對併發的其餘事務是隔離的,併發執行的各個事務之間不能互相干擾。
持久性(Durability)
持久性是指一個事務一旦被提交,它對數據庫中數據的改變就是永久性的,接下來的其餘操做和數據庫故障不該該對其有任何影響
對於同時運行的多個事務,當這些事務訪問數據庫中相同的數據時,若是沒有采起必要的隔離機制,就會致使各類併發問題。
髒讀:對於兩個事務T一、T2,T1讀取了已經被T2更新但還沒有被提交的字段以後,若T2回滾,T1讀取的內容就是臨時且無效的。
不可重複讀:對於兩個事務T一、T2,T1讀取了一個字段,而後T2更新了該字段以後,T1再次讀取同一個字段,值就不一樣了。
幻讀:對於兩個事務T一、T2,T1從一個表中讀取了一個字段,而後T2在該表中插入了一些新的行以後,若是T1再次讀取同一個表,就會多出幾行。
數據庫事務的隔離性:數據庫系統必須具備隔離併發運行各個事務的能力,使它們不會相互影響,避免各類併發問題。
一個事務與其餘事務隔離的程度稱爲隔離級別,數據庫規定了多種事務隔離級別,不一樣隔離級別對應不一樣的干擾程度,隔離級別越高,數據一致性就越好,但併發性越弱。
注意:
show variables like 'transaction_isolation';
set session transaction isolation level 級別;
set global transaction isolation level 級別;
視圖:MySQL從5.0.1版本開始提供視圖功能。一種虛擬存在的表,行和列的數據來自自定義視圖的查詢中使用的表,而且是在使用視圖時動態生成的,只保存了sql邏輯,不保存查詢結果
應用場景:
好處:
權限:
視圖的可更新性和視圖中查詢的定義有關係,如下類型的視圖是不能更新的。