一、基本概念
1.數據庫:
數據庫(DataBase)就是一個存儲數據的倉庫,為了方便數據的存儲和管理,它將數據按照特定的規律存儲在磁盤上。通過數據庫管理系統,可以有效的組織和管理存儲在數據庫中的數據。數據庫是數據管理軟件。數據存儲分為三個階段:人工管理階段、文件系統階段和數據庫系統階段。
2.數據庫范式:
數據庫范式即數據庫應該遵循的規則。目前關系數據庫最常用的四種范式分別是:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、BCN范式(BCNF)。
第一范式:無重復的域。即數據庫表的每一列都是不可分割的原子數據項,而不是集合、數組、記錄等非原子數據項。
第二范式:數據庫表中的所有列都必須依賴於主鍵,這意味着一個表只描述一件事情。
第三范式:表中的每一列只與主鍵直接相關而不是間接相關。
BCN范式:Boyce-Codd,不允許出現有主鍵的一部分被主鍵另一部分或者其他部分決定。即一個表中只能有一個主鍵。
舉例(摘自其他博客)說明BCN:
假設倉庫管理關系表為StorehouseManage(倉庫ID, 存儲物品ID, 管理員ID, 數量),且有一個管理員只在一個倉庫工作;一個倉庫可以存儲多種物品。這個數據庫表中存在如下決定關系:
(倉庫ID, 存儲物品ID) →(管理員ID, 數量)
(管理員ID, 存儲物品ID) → (倉庫ID, 數量)
所以,(倉庫ID, 存儲物品ID)和(管理員ID, 存儲物品ID)都是StorehouseManage的候選關鍵字,表中的唯一非關鍵字段為數量,它是符合第三范式的。但是,由於存在如下決定關系:
(倉庫ID) → (管理員ID)
(管理員ID) → (倉庫ID)
即存在關鍵字段決定關鍵字段的情況,所以其不符合BCNF范式。
3.數據庫系統和數據庫管理系統:
數據庫系統由數據庫、數據庫管理系統、應用開發工具構成。
數據庫管理系統(DataBase Management System, DBMS)是用來定義、管理和維護數據的軟件。它是數據庫系統的重要組成部分。數據庫管理系統通過SQL語言來管理數據庫中的數據。
4.SQL語言:
SQL(Structured Query Language)語言的全稱是結構化查詢語言。它包括:
- 數據庫定義語言(Data Definition Language, DDL)
- 數據操作語言(Data Manipulation Language, DML)
- 數據控制語言(Data Control Language, DCL)
5.MySQL數據庫版本和優勢:
常見數據庫
商業數據庫:甲骨文的Oracle、IBM的DB2、微軟的Access和SQL Server。開源數據庫:PostgreSQL、MySQL。
版本分類
根據操作系統:Windows版,UNIX版,Linux版,MacOS版;根據開發情況:Alpha、Beta、Gamma與Available(GA)。
alpha 暗示這是一個以展示新特性為目的的版本,存在比較多的不穩定因素,還會向代碼中添加新新特性
beta 以后的beta版、發布版或產品發布中,所有API、外部可視結構和SQL命令列均不再更改,不再向代碼中添加影響代碼穩定性的新特性。Gamma比Beta版更高級。
GA如果沒有后綴,則暗示這是一個大多數情況下可用版本或者是產品版本。. GA releases則是穩定版。
優勢:MySQL開放源碼、跨平台性、價格優勢、功能強大且使用方便。
Linux安裝MySQL
https://www.cnblogs.com/kuaizifeng/p/8884842.html
二、MySQL數據類型
MySQL支持多種類型,大致可以分為三類:數值、日期/時間和字符串(字符)類型。(http://www.runoob.com/mysql/mysql-data-types.html)
1.整數類型的存儲和范圍
類型 | 大小 | 范圍(有符號) | 范圍(無符號) | 用途 |
---|---|---|---|---|
TINYINT | 1 字節 | (-128,127) | (0,255) | 小整數值 |
SMALLINT | 2 字節 | (-32 768,32 767) | (0,65 535) | 大整數值 |
MEDIUMINT | 3 字節 | (-8 388 608,8 388 607) | (0,16 777 215) | 大整數值 |
INT或INTEGER | 4 字節 | (-2 147 483 648,2 147 483 647) | (0,4 294 967 295) | 大整數值 |
BIGINT | 8 字節 | (-9 233 372 036 854 775 808,9 223 372 036 854 775 807) | (0,18 446 744 073 709 551 615) | 極大整數值 |
FLOAT | 4 字節 | (-3.402 823 466 E+38,-1.175 494 351 E-38),0,(1.175 494 351 E-38,3.402 823 466 351 E+38) | 0,(1.175 494 351 E-38,3.402 823 466 E+38) | 單精度 浮點數值 |
DOUBLE | 8 字節 | (-1.797 693 134 862 315 7 E+308,-2.225 073 858 507 201 4 E-308),0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) | 0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) | 雙精度 浮點數值 |
DECIMAL | 對DECIMAL(M,D) ,如果M>D,為M+2否則為D+2 | 依賴於M和D的值 | 依賴於M和D的值 | 小數值 |
2.日期和時間類型
類型 | 大小 | 范圍 | 格式 | 用途 |
---|---|---|---|---|
DATE | 3 | 1000-01-01/9999-12-31 | YYYY-MM-DD | 日期值 |
TIME | 3 | '-838:59:59'/'838:59:59' | HH:MM:SS | 時間值或持續時間 |
YEAR | 1 | 1901/2155 | YYYY | 年份值 |
DATETIME | 8 | 1000-01-01 00:00:00/9999-12-31 23:59:59 | YYYY-MM-DD HH:MM:SS | 混合日期和時間值 |
TIMESTAMP | 4 | 1970-01-01 00:00:00/2038 結束時間是第 2147483647 秒,北京時間 2038-1-19 11:14:07,格林尼治時間 2038年1月19日 凌晨 03:14:07 |
YYYYMMDD HHMMSS | 混合日期和時間值,時間戳 |
3.字符串類型
類型 | 大小 | 用途 |
---|---|---|
CHAR | 0-255字節 | 定長字符串 |
VARCHAR | 0-65535 字節 | 變長字符串 |
TINYTEXT | 0-255字節 | 短文本字符串 |
TEXT | 0-65 535字節 | 長文本數據 |
MEDIUMTEXT | 0-16 777 215字節 | 中等長度文本數據 |
LONGTEXT | 0-4 294 967 295字節 | 極大文本數據 |
TINYBLOB | 0-255字節 | 不超過 255 個字符的二進制字符串 |
BLOB | 0-65 535字節 | 二進制形式的長文本數據 |
MEDIUMBLOB | 0-16 777 215字節 | 二進制形式的中等長度文本數據 |
LONGBLOB | 0-4 294 967 295字節 | 二進制形式的極大文本數據 |
三、MySQL表操作
1.插入數據 INSERT INTO
-- 插入一條新的數據 /* INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email) VALUES('10006', 'Toy Land', '123 Any Street', 'New York', 'NY', '11111', 'USA', NULL, NULL); */ -- 按表列字段的順序插入數據時,列字段可省略 INSERT INTO customers VALUES('10006', 'Toy Land', '123 Any Street', 'New York', 'NY', '11111', 'USA', NULL, NULL); -- 將一張表插入到原來的表 /* INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email) SELECT cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email FROM cust_new WHERE cust_id NOT IN (SELECT cust_id FROM customers); */ -- 復制表 CREATE TABLE custcopy AS SELECT * FROM customers;
注意:
- 任何SELECT選項和子句都可以使用,包括WHERE和GROUP BY。
- 可以聯結多個表執行插入數據操作。
- 不管從多少個表中檢索數據,數據都只能插入到單個表中。
2.更新和刪除數據 UPDARE DEL
UPDATE可以:更新表中特定行,更新表中所有行。在沒有where子句時,UPDATE會更新所有記錄。
-- UPDATE總以要更新的表的名字開始,以SET指明一個或多個要更新的字段,以WHERE指定要更新的記錄 UPDATE customers SET cust_email = 'kim@thetoystore.com' WHERE cust_id = '10005'; UPDATE customers SET cust_contact = 'Sam Roberts', cust_email = 'sam@toyloand.com' WHERE cust_id = '10006'; -- 設置NULL來刪除某個列的值 UPDATE customers SET cust_email = NULL WHERE cust_id = '10005';
-- DELETE是刪除列 DELETE FROM customers WHERE cust_id = '10006';
DELETE用於按行刪除記錄,它本身不會修改表結構。
注:在對UPDATE或DELETE語句使用WHERE子句前,應該先用SELECT進行測試,以保證它過濾的是確實要刪除的記錄。
3.創建表及約束條件
1.創建表
-- 創建表語法:CREATE TABLE [IF NOT EXISTS] table_name(column_name data_type,...); CREATE TABLE users(id SMALLINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, name VARCHAR(20), salary FLOAT(8,2) UNSIGNED); -- 查看表結構 DESC users; SHOW COLUMNS FROM users; SHOW CREATE TABLE users;
2.約束條件
約束是為了保證數據的完整性和一致性,約束類型包括:
鍵名 | 類型 |
PRIMARY KEY | 主鍵約束 |
UNIQUE KEY | 唯一約束 |
NOT NULL | 非空約束 |
UNSIGNED | 無符號約束 |
DEFAULT | 默認約束 |
FOREIGN KEY | 外鍵約束 |
4.修改表結構
1.添加和刪除列
-- 修改數據表 -- 添加列語法: ALTER TABLE tbl_name ADD [COLUMN] col_name column_definition [FIRST|AFTER col_name] ALTER TABLE users ADD age TINYINT UNSIGNED NOT NULL DEFAULT 10 AFTER name; -- 刪除列語法: ALTER TABLE tbl_name DROP [COLUMN] col_name ALTER TABLE users DROP age; -- 混合操作 ALTER TABLE users ADD gender VARCHAR(10) NOT NULL DEFAULT "male", ADD address VARCHAR(32) NOT NULL,DROP salary;
2.修改列定義和列名
-- 修改列名,要重新聲明列的數據類型和約束條件 ALTER TABLE users CHANGE name username varchar(10) NOT NULL; -- 修改列定義 ALTER TABLE users MODIFY id SMALLINT NOT NULL FIRST; -- 修改表名 ALTER TABLE users RENAME TO tb;
四、MySQL查詢操作
1、查詢數據
1.查詢關鍵字 SELECT FROM
-- 查詢單列 SELECT prod_name FROM products; -- 查詢多列 SELECT prod_id, prod_name, prod_price FROM products; -- 查詢所有列 SELECT * FROM products;
2.排序關鍵字 ORDER BY
查詢的數據如果不排序,一般是以它在底層表中出現的順序顯示。如果不明確規定排序順序,則不應該假定檢索出的數據的順序有意義。
-- 單排 SELECT prod_name FROM products ORDER BY prod_name; -- 多排 SELECT prod_id, prod_price, prod_name FROM products ORDER BY prod_price, prod_name; -- 按列位置排 SELECT prod_id, prod_price, prod_name FROM products ORDER BY 2, 3; 注,它只能根據已選擇字段的相對位置排序 -- 指定排序方向 SELECT prod_id, prod_price, prod_name FROM products ORDER BY prod_price DESC, prod_name;
3.過濾關鍵字 where + 操作符
where子句操作符表:
操作符 | 說明 |
= | 等於 |
<> | 不等於 |
!= | 不等於 |
< | 小於 |
<= | 小於等於 |
!< | 不小於 |
> | 大於 |
>= | 大於等於 |
!> | 不大於 |
BETWEEN | 在指定的兩個值之間 |
IS NULL | 為null值 |
AND、OR、NOT、IN | 組合查詢 |
LIKE | 通配符過濾 |
用例:
-- 匹配查詢 SELECT prod_price, prod_name FROM products where prod_price = 3.49; -- 不匹配查詢 SELECT prod_price, prod_name FROM products where prod_price <> 10; -- 范圍查詢 SELECT prod_price, prod_name FROM products where prod_price BETWEEN 5 AND 10; -- 空值查詢 SELECT prod_name FROM products where prod_price IS NULL; -- 組合查詢AND SELECT prod_id, prod_name, prod_price FROM products WHERE vend_id='DLL01' AND prod_price <= 4; -- 組合查詢OR SELECT prod_name, prod_price FROM products WHERE vend_id='DLL01' OR vend_id = 'BRS01'; -- 組合查詢AND和OR SELECT prod_name, prod_price FROM products WHERE vend_id='DLL01' OR vend_id = 'BRS01' AND prod_price <= 4; -- 組合查詢IN SELECT prod_name, prod_price FROM products WHERE vend_id IN ('DLL01', 'BRS01') ORDER BY prod_name; -- 組合查詢NOT SELECT prod_name, prod_price FROM products WHERE vend_id NOT vend_id='DLL01'; -- 通配符過濾 SELECT prod_name FROM products WHERE prod_name LIKE '%TNT%';
2、數據處理函數
1.文本處理函數
函數 | 說明 |
LEFT | 返回字符串左邊的字符 |
LENGTH | 返回字符串的長度 |
LOWER | 返回字符串的小寫 |
LTRIM | 去掉字符串左邊的空格 |
RIGHT | 返回字符串右邊的字符 |
RTRIM | 去掉字符串右邊的空格 |
UPPER | 返回字符串的大寫 |
- 用例:
SELECT vend_name, UPPER(vend_name) AS vend_name_upcase FROM vendors ORDER BY vend_name;
2.日期和時間處理函數
注:日期和時間函數根據https://blog.csdn.net/qinshijangshan/article/details/72874667整理
函數 | 說明 |
NOW()、SYSDATE()、CURRENT_TIMESTAMP、LOCALTIME、LOCALTIMESTAMP | 獲取當前日期和時間 |
CURDATE(), CURRENT_DATE | 獲取當前日期 |
CURTIME(), CURRENT_TIME | 獲取當前時間 |
DATE、YEAR、QUARTER、MONTH、WEEK、DAY、HOUR、MINUTE、SECOND、MICROSECOND | 獲取指定日期和時間的日期、年、季度、月、周、日、小時、分鍾、秒、毫秒數 |
WEEKOFYEAR、DAYOFYEAR、DAYOFMONTH、DAYOFWEEK、LAST_DAY | 獲取指定日期和時間的年周索引、年天索引、月天索引、周天索引,最后一天的日期 |
MONTHNAME、 DAYNAME | 獲取指定日期和時間的英文月名、英文天名 |
DATE_ADD、DATE_SUB | 指定日期按指定參數進行加減運算 |
PERIOD_ADD、PERIOD_DIFF | 指定日期加、減多少個月 |
TIMEDIFF | 指定日期和時間相差多少個時間 |
TIMESTAMPDIFF | 指定日期/時間或日期時間的差值 |
TO_DAYS、FROM_DAYS | 日期和月數的相互轉換函數 |
TIME_TO_SEC、SEC_TO_TIME | 時間和秒數的相互轉換函數 |
STR_TO_DATE、DATE_FORMAT | 字符串/日期時間格式轉換成新的格式 |
TIME_FORMAT | 時間格式轉換你成新的格式 |
MAKEDATE、MAKETIME | 拼湊日期/時間 |
UNIX_TIMESTAMP、FROM_UNIXTIME | 日期時間和unix時間戳的相互轉化 |
用例:
-- 獲取當前日期和時間,日期指的是年月日,時間指的是時分秒 SELECT NOW(), SYSDATE(), CURRENT_TIMESTAMP, LOCALTIME, LOCALTIMESTAMP; -- 分別獲取當前日期和時間 SELECT CURDATE(), CURRENT_DATE, CURTIME(), CURRENT_TIME; -- 分別獲取日期時間、年、季度、月、周、日、時、分、秒 SELECT DATE(SYSDATE()), YEAR(SYSDATE()), QUARTER(SYSDATE()), MONTH(SYSDATE()), WEEK(SYSDATE()), DAY(SYSDATE()), HOUR(SYSDATE()), MINUTE(SYSDATE()), SECOND(SYSDATE()), MICROSECOND(SYSDATE()); -- 獲取指定索引 SELECT WEEKOFYEAR(SYSDATE()), DAYOFYEAR(SYSDATE()), DAYOFMONTH(SYSDATE()), DAYOFWEEK(SYSDATE()), LAST_DAY(SYSDATE()); -- 獲取月和周的英文名稱 SELECT MONTHNAME(SYSDATE()), DAYNAME(SYSDATE());
-- DATE加,第一個參數是指定的日期和時間,第二個參數是間隔和單位 SELECT DATE_ADD(now(), INTERVAL 1 YEAR), DATE_ADD(now(), INTERVAL 2 MONTH), DATE_ADD(now(), INTERVAL 1000 SECOND); -- DATE減,與DATE加參數相同 SELECT DATE_SUB(now(), INTERVAL 1 YEAR), DATE_SUB(now(), INTERVAL 2 MONTH), DATE_SUB(now(), INTERVAL 1000 SECOND); -- 日期的加減運算 SELECT PERIOD_ADD(201808, 2), PERIOD_ADD(1808, 2),PERIOD_ADD(DATE_FORMAT(SYSDATE(), '%Y%m'), 2), PERIOD_DIFF(201808, 201004), PERIOD_DIFF(1808, 1004); -- 時間差計算 SELECT TIMEDIFF('2018-08-06', '2018-08-5');-- 不支持日期 SELECT TIMEDIFF('19:00:00', '17:00:00'), TIMEDIFF('2018-08-6 9:30:30', '2018-08-5 17:00:00'); -- 更便捷的日期/時間差值計算,第一個參數是要計算的字段,其值為第三個日期時間減去第二個日期時間 SELECT TIMESTAMPDIFF(DAY, '2018-08-5 17:00:00', '2018-08-8 9:30:30'), TIMESTAMPDIFF(DAY, '2018-08-5', '2018-08-8'); SELECT TIMESTAMPDIFF(SECOND, '17:00:00', '19:30:30');-- 不支持單獨時間計算 -- 日期和天數的相互轉換 SELECT TO_DAYS(SYSDATE()), TO_DAYS('2018-8-8'), FROM_DAYS(737279); -- 時間和秒數的相互轉換 SELECT TIME_TO_SEC(SYSDATE()), TIME_TO_SEC('12:00:00'), SEC_TO_TIME(43200); -- 字符串格式化;字符串格式化成日期只能要按照字符串的寫法改寫成標准日期時間字符串 SELECT STR_TO_DATE('2018.08.6 9:30:30', '%Y.%m.%d %H:%i:%s'); -- 日期時間字符串可以隨便更改或獲取字段 SELECT DATE_FORMAT('2018-08-06 09:30:30', '%Y%m');-- 獲取年月的組合字符串 SELECT DATE_FORMAT('2018-08-06 09:30:30', '%H%i%s');-- 獲取時分秒的組合字符串 SELECT DATE_FORMAT(SYSDATE(), '%Y年%m月%d日 %H時哈哈%i分嘿嘿%d秒呵呵');-- 重新格式化 -- 時間格式化只能格式化時間 SELECT TIME_FORMAT('2018-08-06 09:30:30', '%Y年%m月%d日 %H時%i分%d秒'); -- 只對'09:30:30'進行格式化,日期全部為00 SELECT TIME_FORMAT('09:30:30', '%H時%i分%d秒'); -- MAKEDATE根據數字組合成日期(以天數換算),MAKETIME根據數字組合成時間 SELECT MAKEDATE(2018, 9);-- 結果是'2018-01-09'而不是'2018-09-01' SELECT MAKEDATE(2018, 220);-- 結果是'2018-08-08' SELECT MAKETIME(19,30,30);-- 與日期相反,支持三個參數拼接而不支持兩個參數換算 -- 日期時間和unix時間的相互轉換 SELECT UNIX_TIMESTAMP(), FROM_UNIXTIME(UNIX_TIMESTAMP());
3.數值處理函數
函數 | 說明 |
ABS() | 返回數字表達式的絕對值。 |
ACOS() | 返回數字表達式的反余弦值。如果值是不在范圍-1到1,則返回NULL。 |
ASIN() | 返回數字表達式的反正弦。返回NULL,如果值不在范圍-1到1 |
ATAN() | 返回數字表達式的反正切。 |
ATAN2() | 返回傳遞給它的兩個變量的反正切。 |
BIT_AND() | 返回按位AND運算表達中的所有位。 |
BIT_COUNT() | 返回傳遞給它的二進制值的字符串表示。 |
BIT_OR() | 返回傳遞表達的所有位的位或。 |
CEIL() | 返回最小的整數值但不能比傳遞的數字表達式小 |
CEILING() | 返回最小的整數值但不能比傳遞的數字表達式小 |
CONV() | 表達式從一個基數到另一個基數轉換的數字。 |
COS() | 返回傳遞數字表達式的余弦值。數字表達式應該用弧度表示。 |
COT() | 返回傳遞數字表達式的余切。 |
DEGREES() | 返回數字表達式從弧度轉換為度。 |
EXP() | 返回數值表達式的自然對數(E)為基數的冪。 |
FLOOR() | 返回最大整數值但不能大於通過表達式數值。 |
FORMAT() | 返回數字表達式舍入到小數位數。 |
GREATEST() | 返回輸入表達式的最大值。 |
INTERVAL() | 需要多個表達式exp1, exp2和exp3等..如果為exp1小於exp2返回0,如果為exp1小於exp3返回1等。 |
LEAST() | 給兩個或兩個以上時,返回所有輸入的最小值。 |
LOG() | 返回通過數字表達式的自然對數。 |
LOG10() | 返回傳遞表達的基數為10對數的數值。 |
MOD() | 返回表達式由另一個表達式除以剩余部分。 |
OCT() | 返回通過數字表達式的八進制值的字符串表示。如果傳遞值為NULL,返回NULL。 |
PI() | 返回圓周率的值 |
POW() | 返回一個表達式到另一個表達的次方值 |
POWER() | 返回一個表達式到另一個表達的次方值 |
RADIANS() | 返回傳遞表達從度轉換為弧度值 |
ROUND() | 返回數字表達式四舍五入到整數。可用於舍入表達式為小數點數值 |
SIN() | 返回給定的數字表達的正弦值(弧度) |
SQRT() | 返回數字表達式的非負平方根 |
STD() | 返回數字表達式的標准偏差 |
STDDEV() | 返回數字表達式的標准偏差 |
TAN() | 返回以弧度表示數值表達式的正切值。 |
TRUNCATE() | 返回exp1小數位數字截斷到exp2。如果exp2為0,則結果將沒有小數點。 |
4.聚合函數
函數 | 說明 |
AVG | 返回某列的平均值 |
COUNT | 返回某類的行數 |
MAX | 返回某列的最大值 |
MIN | 返回某列的最小值 |
SUM | 返回某列值之和 |
用例:
-- AVG SELECT AVG(prod_price) AS avg_price FROM products; SELECT AVG(prod_price) AS avg_price FROM products WHERE vend_id=1003; SELECT AVG(DISTINCT prod_price) AS avg_price FROM products WHERE vend_id=1003;-- 計算唯一值列表平均值 -- COUNT SELECT COUNT(*) AS num_cust FROM customers;-- 對所有行技數 SELECT COUNT(cust_email) as num_cust FROM customers;-- 只對具有電子郵寄地址的客戶計數(除去null) -- SUM SELECT SUM(item_price * quantity) AS total_price FROM orderitems WHERE order_num = 20005; -- 組合 SELECT COUNT(*) AS nun_items, MIN(prod_price) AS price_min, MAX(prod_price) AS pric_max, AVG(prod_price) AS price_ag FROM products;
3、分組關鍵字 GROUP BY 和HAVING
1.GROUP BY
- GROUP BY子句可以包含任意數目的列。
- GROUP BY會在最后規定的分組上進行匯總。
- GROUP BY子句列出的每個列都必須是檢索列或有效的表達式(但不能是聚合函數)。
- 除聚合函數外,SELECT語句中的每個列都必須在GROUP BY子句中給出。
- 如果分組列中具有NULL值,則NULL將作為一個分組返回;如果列中有多行NULL值,它們將分為一組。
- GROUP BY子句必須出現在WHERE子句字后,ORDER BY子句之前。
一般在使用GROUP BY子句時,應該也給出ORDER BY子句,以保證數據正確排序。
2.HAVING
HAVING支持所有WHERE操作符。它與WHERE最重要的區別是,HAVING對GROUP BY分組后的數據進行過濾,而where在GROUP BY分組前組織新表時進行過濾。
用例:
-- GROUP BY 與 HAVINNG SELECT cust_id, COUNT(*) AS orders FROM orders GROUP BY cust_id HAVING COUNT(*) >= 2; -- GROUP BY 與 ORDER BY SELECT order_num, COUNT(*) AS items FROM orderitems GROUP BY order_num HAVING COUNT(*) >= 3 ORDER BY items, order_num;
4、關鍵字順序
關鍵字(子句) | 說明 |
是否必須使用 |
SELECT | 要返回的列或表達式 | 是 |
FROM | 從中檢索數據的表 | 僅在從表選擇數據時使用 |
WHERE | 行級過濾 | 否 |
GROUP BY | 分組說明 | 僅在按組計算聚集時使用 |
HAVING | 組級過濾 | 否 |
ORDER BY | 指定排序字段和熟順序 | 否 |
在實現SQL語句時,通用格式為:
SELECT *columns* FROM *tables* WHERE *condition* GROUP BY *columns* HAVING *condition* ORDER BY *columns* LIMIT *start*, *offset*;
實際執行的順序為:
FROM *tables* WHERE *condition* GROUP BY *columns* HAVING *condition* SELECT *columns* ORDER BY *columns* LIMIT *start*, *offset*
# 注:數據表來自https://www.cnblogs.com/sanjun/p/8274469.html。

CREATE TABLE customers ( cust_id int NOT NULL AUTO_INCREMENT, cust_name char(50) NOT NULL , cust_address char(50) NULL , cust_city char(50) NULL , cust_state char(5) NULL , cust_zip char(10) NULL , cust_country char(50) NULL , cust_contact char(50) NULL , cust_email char(255) NULL , PRIMARY KEY (cust_id) ) ENGINE=InnoDB; CREATE TABLE orderitems ( order_num int NOT NULL , order_item int NOT NULL , prod_id char(10) NOT NULL , quantity int NOT NULL , item_price decimal(8,2) NOT NULL , PRIMARY KEY (order_num, order_item) ) ENGINE=InnoDB; CREATE TABLE orders ( order_num int NOT NULL AUTO_INCREMENT, order_date datetime NOT NULL , cust_id int NOT NULL , PRIMARY KEY (order_num) ) ENGINE=InnoDB; CREATE TABLE products ( prod_id char(10) NOT NULL, vend_id int NOT NULL , prod_name char(255) NOT NULL , prod_price decimal(8,2) NOT NULL , prod_desc text NULL , PRIMARY KEY(prod_id) ) ENGINE=InnoDB; CREATE TABLE vendors ( vend_id int NOT NULL AUTO_INCREMENT, vend_name char(50) NOT NULL , vend_address char(50) NULL , vend_city char(50) NULL , vend_state char(5) NULL , vend_zip char(10) NULL , vend_country char(50) NULL , PRIMARY KEY (vend_id) ) ENGINE=InnoDB; CREATE TABLE productnotes ( note_id int NOT NULL AUTO_INCREMENT, prod_id char(10) NOT NULL, note_date datetime NOT NULL, note_text text NULL , PRIMARY KEY(note_id), FULLTEXT(note_text) ) ENGINE=MyISAM; ALTER TABLE orderitems ADD CONSTRAINT fk_orderitems_orders FOREIGN KEY (order_num) REFERENCES orders (order_num); ALTER TABLE orderitems ADD CONSTRAINT fk_orderitems_products FOREIGN KEY (prod_id) REFERENCES products (prod_id); ALTER TABLE orders ADD CONSTRAINT fk_orders_customers FOREIGN KEY (cust_id) REFERENCES customers (cust_id); ALTER TABLE products ADD CONSTRAINT fk_products_vendors FOREIGN KEY (vend_id) REFERENCES vendors (vend_id); INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email) VALUES(10001, 'Coyote Inc.', '200 Maple Lane', 'Detroit', 'MI', '44444', 'USA', 'Y Lee', 'ylee@coyote.com'); INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact) VALUES(10002, 'Mouse House', '333 Fromage Lane', 'Columbus', 'OH', '43333', 'USA', 'Jerry Mouse'); INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email) VALUES(10003, 'Wascals', '1 Sunny Place', 'Muncie', 'IN', '42222', 'USA', 'Jim Jones', 'rabbit@wascally.com'); INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email) VALUES(10004, 'Yosemite Place', '829 Riverside Drive', 'Phoenix', 'AZ', '88888', 'USA', 'Y Sam', 'sam@yosemite.com'); INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact) VALUES(10005, 'E Fudd', '4545 53rd Street', 'Chicago', 'IL', '54545', 'USA', 'E Fudd'); INSERT INTO vendors(vend_id, vend_name, vend_address, vend_city, vend_state, vend_zip, vend_country) VALUES(1001,'Anvils R Us','123 Main Street','Southfield','MI','48075', 'USA'); INSERT INTO vendors(vend_id, vend_name, vend_address, vend_city, vend_state, vend_zip, vend_country) VALUES(1002,'LT Supplies','500 Park Street','Anytown','OH','44333', 'USA'); INSERT INTO vendors(vend_id, vend_name, vend_address, vend_city, vend_state, vend_zip, vend_country) VALUES(1003,'ACME','555 High Street','Los Angeles','CA','90046', 'USA'); INSERT INTO vendors(vend_id, vend_name, vend_address, vend_city, vend_state, vend_zip, vend_country) VALUES(1004,'Furball Inc.','1000 5th Avenue','New York','NY','11111', 'USA'); INSERT INTO vendors(vend_id, vend_name, vend_address, vend_city, vend_state, vend_zip, vend_country) VALUES(1005,'Jet Set','42 Galaxy Road','London', NULL,'N16 6PS', 'England'); INSERT INTO vendors(vend_id, vend_name, vend_address, vend_city, vend_state, vend_zip, vend_country) VALUES(1006,'Jouets Et Ours','1 Rue Amusement','Paris', NULL,'45678', 'France'); INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('ANV01', 1001, '.5 ton anvil', 5.99, '.5 ton anvil, black, complete with handy hook'); INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('ANV02', 1001, '1 ton anvil', 9.99, '1 ton anvil, black, complete with handy hook and carrying case'); INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('ANV03', 1001, '2 ton anvil', 14.99, '2 ton anvil, black, complete with handy hook and carrying case'); INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('OL1', 1002, 'Oil can', 8.99, 'Oil can, red'); INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('FU1', 1002, 'Fuses', 3.42, '1 dozen, extra long'); INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('SLING', 1003, 'Sling', 4.49, 'Sling, one size fits all'); INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('TNT1', 1003, 'TNT (1 stick)', 2.50, 'TNT, red, single stick'); INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('TNT2', 1003, 'TNT (5 sticks)', 10, 'TNT, red, pack of 10 sticks'); INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('FB', 1003, 'Bird seed', 10, 'Large bag (suitable for road runners)'); INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('FC', 1003, 'Carrots', 2.50, 'Carrots (rabbit hunting season only)'); INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('SAFE', 1003, 'Safe', 50, 'Safe with combination lock'); INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('DTNTR', 1003, 'Detonator', 13, 'Detonator (plunger powered), fuses not included'); INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('JP1000', 1005, 'JetPack 1000', 35, 'JetPack 1000, intended for single use'); INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('JP2000', 1005, 'JetPack 2000', 55, 'JetPack 2000, multi-use'); INSERT INTO orders(order_num, order_date, cust_id) VALUES(20005, '2005-09-01', 10001); INSERT INTO orders(order_num, order_date, cust_id) VALUES(20006, '2005-09-12', 10003); INSERT INTO orders(order_num, order_date, cust_id) VALUES(20007, '2005-09-30', 10004); INSERT INTO orders(order_num, order_date, cust_id) VALUES(20008, '2005-10-03', 10005); INSERT INTO orders(order_num, order_date, cust_id) VALUES(20009, '2005-10-08', 10001); INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price) VALUES(20005, 1, 'ANV01', 10, 5.99); INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price) VALUES(20005, 2, 'ANV02', 3, 9.99); INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price) VALUES(20005, 3, 'TNT2', 5, 10); INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price) VALUES(20005, 4, 'FB', 1, 10); INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price) VALUES(20006, 1, 'JP2000', 1, 55); INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price) VALUES(20007, 1, 'TNT2', 100, 10); INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price) VALUES(20008, 1, 'FC', 50, 2.50); INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price) VALUES(20009, 1, 'FB', 1, 10); INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price) VALUES(20009, 2, 'OL1', 1, 8.99); INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price) VALUES(20009, 3, 'SLING', 1, 4.49); INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price) VALUES(20009, 4, 'ANV03', 1, 14.99); INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(101, 'TNT2', '2005-08-17', 'Customer complaint: Sticks not individually wrapped, too easy to mistakenly detonate all at once. Recommend individual wrapping.' ); INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(102, 'OL1', '2005-08-18', 'Can shipped full, refills not available. Need to order new can if refill needed.' ); INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(103, 'SAFE', '2005-08-18', 'Safe is combination locked, combination not provided with safe. This is rarely a problem as safes are typically blown up or dropped by customers.' ); INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(104, 'FC', '2005-08-19', 'Quantity varies, sold by the sack load. All guaranteed to be bright and orange, and suitable for use as rabbit bait.' ); INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(105, 'TNT2', '2005-08-20', 'Included fuses are short and have been known to detonate too quickly for some customers. Longer fuses are available (item FU1) and should be recommended.' ); INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(106, 'TNT2', '2005-08-22', 'Matches not included, recommend purchase of matches or detonator (item DTNTR).' ); INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(107, 'SAFE', '2005-08-23', 'Please note that no returns will be accepted if safe opened using explosives.' ); INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(108, 'ANV01', '2005-08-25', 'Multiple customer returns, anvils failing to drop fast enough or falling backwards on purchaser. Recommend that customer considers using heavier anvils.' ); INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(109, 'ANV03', '2005-09-01', 'Item is extremely heavy. Designed for dropping, not recommended for use with slings, ropes, pulleys, or tightropes.' ); INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(110, 'FC', '2005-09-01', 'Customer complaint: rabbit has been able to detect trap, food apparently less effective now.' ); INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(111, 'SLING', '2005-09-02', 'Shipped unassembled, requires common tools (including oversized hammer).' ); INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(112, 'SAFE', '2005-09-02', 'Customer complaint: Circular hole in safe floor can apparently be easily cut with handsaw.' ); INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(113, 'ANV01', '2005-09-05', 'Customer complaint: Not heavy enough to generate flying stars around head of victim. If being purchased for dropping, recommend ANV02 or ANV03 instead.' ); INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(114, 'SAFE', '2005-09-07', 'Call from individual trapped in safe plummeting to the ground, suggests an escape hatch be added. Comment forwarded to vendor.' );