一、MySQL的使用
如果通過命令行啟動和停止MySQL數據庫,一定要以管理員身份運行命令行cmd。

否則,會出現錯誤。

1、啟動和停止MySQL服務
(1)通過Windows計算機管理方式
右擊此電腦—管理—服務和應用程序—服務,啟動或停止MySQL服務

(2)通過命令行方式
- 啟動:net start mysql
- 停止:net stop mysql
一定要以管理員的身份打開cmd命令。

2、登錄和退出MySQL數據庫
(1)使用命令行登錄和退出
C:\Windows\system32>mysql -h localhost -P 3306 -u root -p1234 db_hr -e"select * from user;"
- 最前面的mysql你可以理解成一個關鍵字或者理解成一個固定的命令,是固定寫法,類似於java、jdk中的javac命令或java命令;
- -h表示host,即主機的ip地址——127.0.0.1;
- -P表示port,端口,mysql數據庫的默認端口是3306,當然,你也可以自己修改端口號,我這里沒改端口號(注意:這是大寫的字母P);
- -u表示user用戶名,這里是root;
- -p表示password密碼1234(注意:這是小寫的字母p);
- db_hr:數據庫名表示登錄到哪一個數據庫中;
- -e參數后面可以直接加SQL語句。登錄mysql服務器之后,立即執行這個SQL語句。-e后面不要有空格。
下面說說mysql這個命令的注意事項:
大寫的P表示端口號,小寫的p表示密碼;
小寫的p表示密碼,-p和密碼之間一定不能有空格,其他的像-u,-h,-P之類的,是可以有空格的,也可以沒有空格。
如果是本機的話,主機ip和端口號可以不寫(即主機ip和端口號可以省略),直接寫成mysql -u root -p1234
如果是本機,但是端口號你改成了其他的端口號,不是默認的3306了,比如你把端口號改成了6688,那你就加上端口號,即mysql -P 6688 -u root -p1234
以下這3種語法都是正確的,我依次舉例和截圖演示:
我這里用的用戶名是root,密碼也是1234
語法1:mysql -h 主機ip地址 -P 端口號 -u 用戶名 -p密碼
(-h和主機ip地址之間有空格,-P和端口號之間有空格,-u和用戶名之間有空格,-p和密碼之間一定不能有空格)
mysql -h localhost -P 3306 -u root -p1234
如果是本機的話,主機ip地址和端口號(是默認3306的情況下)-h localhost -P 3306可以省略不寫,
mysql -u root -p1234
如果是本機,但是端口你之前改成了其他的,比如端口你改成了8801,不是默認的3306端口了,那么主機ip地址可以省略不寫,但是要寫上端口號,
mysql -P 8801 -u root -p1234
如果是遠程主機的話,必須寫-h 遠程主機的ip,
mysql -h 192.168.117.66 -P 3306 -u root -p1234
如果遠程主機的mysql數據庫端口默認是3306,那端口號可以省略不寫,但是遠程主機的ip地址要寫,
mysql -h 192.168.117.66 -u root -p1234
如果遠程主機的mysql數據庫端口不是默認的3306,端口而被改成了比如6655,那遠程主機ip地址和端口號都要寫上,
mysql -h 192.168.117.66 -P 6655 -u root -p1234
語法2:mysql -h主機 ip地址 -P端口號 -u用戶名 -p密碼
(-h和主機ip地址之間無空格,-P和端口號之間無空格,-u和用戶名之間無空格,-p和密碼之間一定不能有空格)
mysql -h192.168.117.66 -P3306 -uroot -p1234
語法3:mysql -h主機ip地址 -P端口號 -u用戶名 -p
(最后一個-p,小寫字母p后面不寫密碼)
mysql -h 192.168.117.66 -P 3306 -u root -p
或者
mysql -h192.168.117.66 -P3306 -uroot -p
注意:小寫字母p后面不寫密碼,這樣的話,密碼就不會顯示暴露出來了,輸入密碼的時候也是顯示成****,進入數據庫之后再輸入密碼。

退出登錄,可以使用 quit 或者 exit 或者 \q 命令
![]()
![]()
(2)通過MySQL自帶的客戶端,僅限於root用戶。
3、MySQL的相關命令
List of all client commands:
Note that all text commands must be first on line and end with ';'
? (\?) Synonym for `help'.
clear (\c) Clear the current input statement. --清除當前輸入的語句
connect (\r) Reconnect to the server. Optional arguments are db and host. --重新連接,通常用於被踢出或異常斷開后重新連接,SQL*plus下也有這樣一個connect命令。
delimiter (\d) Set statement delimiter.--設置命令終止符,缺省為;,比如我們可以設定為/來表示語句結束
edit (\e) Edit command with $EDITOR. --編輯緩沖區的上一條SQL語句到文件,缺省調用vi,文件會放在/tmp路徑下
ego (\G) Send command to MariaDB server, display result vertically. --控制結果顯示為垂直顯示
exit (\q) Exit mysql. Same as quit. --退出mysql
go (\g) Send command to MariaDB server. --發送命令到mysql服務
help (\h) Display this help.
nopager (\n) Disable pager, print to stdout. --關閉頁設置,打印到標准輸出
notee (\t) Don't write into outfile. --關閉輸出到文件
pager (\P) Set PAGER [to_pager]. Print the query results via PAGER. --設置pager方式,可以設置為調用more,less等等,主要是用於分頁顯示
print (\p) Print current command.
prompt (\R) Change your mysql prompt. --改變mysql的提示符
quit (\q) Quit mysql.
rehash (\#) Rebuild completion hash. --自動補齊相關對象名字
source (\.) Execute an SQL script file. Takes a file name as an argument. --執行腳本文件
status (\s) Get status information from the server. --獲得狀態信息
system (\!) Execute a system shell command. --執行系統命令
tee (\T) Set outfile [to_outfile]. Append everything into given outfile. --操作結果輸出到文件
use (\u) Use another database. Takes database name as argument. --切換數據庫
charset (\C) Switch to another charset. Might be needed for processing binlog with multi-byte charsets. --設置字符集
warnings (\W) Show warnings after every statement. --打印警告信息
nowarning (\w) Don't show warnings after every statement.
resetconnection(\x) Clean session context.
注意:上面的所有命令,擴號內的為快捷操作,即只需要輸入“\”+ 字母即可執行。
二、MySQL支持的基本數據類型
1、數值類型
MySQL 支持所有標准 SQL 數值數據類型。
這些類型包括嚴格數值數據類型(INTEGER、SMALLINT、DECIMAL 和 NUMERIC)、近似數值數據類型(FLOAT、REAL 和 DOUBLE PRECISION)。
關鍵字INT是INTEGER的同義詞,關鍵字DEC是DECIMAL的同義詞。
BIT數據類型保存位字段值,並且支持 MyISAM、MEMORY、InnoDB 和 BDB表。
作為 SQL 標准的擴展,MySQL 也支持整數類型 TINYINT、MEDIUMINT 和 BIGINT。下面的表顯示了需要的每個整數類型的存儲和范圍。
| 類型 | 大小 | 范圍(有符號) | 范圍(無符號) | 用途 |
|---|---|---|---|---|
| TINYINT | 1 Bytes | (-128,127) | (0,255) | 小整數值 |
| SMALLINT | 2 Bytes | (-32 768,32 767) | (0,65 535) | 大整數值 |
| MEDIUMINT | 3 Bytes | (-8 388 608,8 388 607) | (0,16 777 215) | 大整數值 |
| INT或INTEGER | 4 Bytes | (-2 147 483 648,2 147 483 647) | (0,4 294 967 295) | 大整數值 |
| BIGINT | 8 Bytes | (-9,223,372,036,854,775,808,9 223 372 036 854 775 807) | (0,18 446 744 073 709 551 615) | 極大整數值 |
| FLOAT | 4 Bytes | (-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 Bytes | (-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、字符串類型
字符串類型指CHAR、VARCHAR、BINARY、VARBINARY、BLOB、TEXT、ENUM和SET。
該節描述了這些類型如何工作以及如何在查詢中使用這些類型。
| 類型 | 大小 | 用途 |
|---|---|---|
| CHAR | 0-255 bytes | 定長字符串 |
| VARCHAR | 0-65535 bytes | 變長字符串 |
| TINYBLOB | 0-255 bytes | 不超過 255 個字符的二進制字符串 |
| TINYTEXT | 0-255 bytes | 短文本字符串 |
| BLOB | 0-65 535 bytes | 二進制形式的長文本數據 |
| TEXT | 0-65 535 bytes | 長文本數據 |
| MEDIUMBLOB | 0-16 777 215 bytes | 二進制形式的中等長度文本數據 |
| MEDIUMTEXT | 0-16 777 215 bytes | 中等長度文本數據 |
| LONGBLOB | 0-4 294 967 295 bytes | 二進制形式的極大文本數據 |
| LONGTEXT | 0-4 294 967 295 bytes | 極大文本數據 |
注意:char(n) 和 varchar(n) 中括號中 n 代表字符的個數,並不代表字節個數,比如 CHAR(30) 就可以存儲 30 個字符。
CHAR 和 VARCHAR 類型類似,但它們保存和檢索的方式不同。它們的最大長度和是否尾部空格被保留等方面也不同。在存儲或檢索過程中不進行大小寫轉換。
BINARY 和 VARBINARY 類似於 CHAR 和 VARCHAR,不同的是它們包含二進制字符串而不要非二進制字符串。也就是說,它們包含字節字符串而不是字符字符串。這說明它們沒有字符集,並且排序和比較基於列值字節的數值值。
BLOB 是一個二進制大對象,可以容納可變數量的數據。有 4 種 BLOB 類型:TINYBLOB、BLOB、MEDIUMBLOB 和 LONGBLOB。它們區別在於可容納存儲范圍不同。
有 4 種 TEXT 類型:TINYTEXT、TEXT、MEDIUMTEXT 和 LONGTEXT。對應的這 4 種 BLOB 類型,可存儲的最大長度不同,可根據實際情況選擇。
3、日期和時間類型
表示時間值的日期和時間類型為DATETIME、DATE、TIMESTAMP、TIME和YEAR。
每個時間類型有一個有效值范圍和一個"零"值,當指定不合法的MySQL不能表示的值時使用"零"值。
TIMESTAMP類型有專有的自動更新特性,將在后面描述。
| 類型 | 大小( bytes) | 范圍 | 格式 | 用途 |
|---|---|---|---|---|
| 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 | 混合日期和時間值,時間戳 |
三、數據庫的基本操作
1、創建和查看數據庫
我們可以在登陸 MySQL 服務后,使用 create 命令創建數據庫,語法如下:
CREATE DATABASE 數據庫名;
以下命令簡單的演示了創建數據庫的過程,數據名為db_hr:
mysql> create DATABASE db_hr;
使用 show命令來查看已創建的數據庫,語法如下:
mysql> show DATABASE;
另外,還可以使用 show命令來查看已創建的數據庫信息,語法如下:
mysql> show CREATE DATABASE db_hr;

以上的執行結果顯示數據庫db_hr的創建信息,例如編碼方式是utf8。
除了可以用默認的編碼方式創建數據庫外,還可以在創建數據庫時指定編碼方式,
mysql> CREATE DATABASE db_hr2 CHARACTER SET gbk;

可以看出數據庫db_hr2的編碼方式為gbk。
2、使用數據庫
在你連接到 MySQL 數據庫后,可能有多個可以操作的數據庫,所以你需要選擇你要操作的數據庫。
在 mysql> 提示窗口中可以很簡單的選擇特定的數據庫。你可以使用SQL命令來選擇指定的數據庫。語法格式如下:
use 數據庫名;
mysql> use db_hr; Database changed
在出現Database changed提示時,證明已經切換到了數據庫db_hr。
mysql數據庫文件的真實的物理存儲位置。
mysql> show global variables like "%datadir%";
3、修改數據庫
在 MySQL中,可以使用 ALTER DATABASE 語句來修改已經被創建或者存在的數據庫的相關參數。修改數據庫的語法格式為:
ALTER DATABASE [數據庫名] { [ DEFAULT ] CHARACTER SET <字符集名> | [ DEFAULT ] COLLATE <校對規則名>}
語法說明如下:
- ALTER DATABASE 用於更改數據庫的全局特性。這些特性存儲在數據庫目錄的 db.opt 文件中。
- 使用 ALTER DATABASE 需要獲得數據庫 ALTER 權限。
- 數據庫名稱可以忽略,此時語句對應於默認數據庫。
- CHARACTER SET 子句用於更改默認的數據庫字符集
例如,用alter命令將數據庫 db_hr2 的指定字符集修改為 gb2312,默認校對規則修改為 gb2312_unicode_ci,輸入 SQL 語句與執行結果如下所示:
mysql> ALTER DATABASE db_hr2 DEFAULT CHARACTER SET gb2312 DEFAULT COLLATE gb2312_chinese_ci;
4、刪除數據庫
當數據庫不再使用時應該將其刪除,以確保數據庫存儲空間中存放的是有效數據。
刪除數據庫是將已經存在的數據庫從磁盤空間上清除,清除之后,數據庫中的所有數據也將一同被刪除。
在 MySQL 中,當需要刪除已創建的數據庫時,可以使用 DROP DATABASE 語句。其語法格式為:
DROP DATABASE [ IF EXISTS ] <數據庫名>
語法說明如下:
- <數據庫名>:指定要刪除的數據庫名。
- IF EXISTS:用於防止當數據庫不存在時發生錯誤。
- DROP DATABASE:刪除數據庫中的所有表格並同時刪除數據庫。使用此語句時要非常小心,以免錯誤刪除。如果要使用 DROP DATABASE,需要獲得數據庫 DROP 權限。
注意:MySQL 安裝后,系統會自動創建名為 information_schema 和 mysql 的兩個系統數據庫,系統數據庫存放一些和數據庫相關的信息,如果刪除了這兩個數據庫,MySQL 將不能正常工作。
使用命令行工具將數據庫db_hr2從數據庫列表中刪除,輸入的 SQL 語句與執行結果如下所示:
mysql> DROP DATABASE db_hr2;
此時數據庫db_hr2不存在。再次執行相同的命令,直接使用 DROP DATABASE db_hr2,系統會報錯,如下所示:
![]()
如果使用IF EXISTS從句,可以防止系統報此類錯誤,如下所示:
mysql> DROP DATABASE IF EXISTS db_hr2;
使用 DROP DATABASE 命令時要非常謹慎,在執行該命令后,MySQL 不會給出任何提示確認信息。
DROP DATABASE 刪除數據庫后,數據庫中存儲的所有數據表和數據也將一同被刪除,而且不能恢復。
因此最好在刪除數據庫之前先將數據庫進行備份。備份數據庫的方法會在教程后面進行講解。
四、表的基本操作
1、創建數據表
在創建數據庫之后,接下來就要在數據庫中創建數據表。所謂創建數據表,指的是在已經創建的數據庫中建立新表。
創建數據表的過程是規定數據列的屬性的過程,同時也是實施數據完整性(包括實體完整性、引用完整性和域完整性)約束的過程。
創建MySQL數據表需要以下信息:
- 表名
- 表字段名
- 定義每個表字段
接下來我們介紹一下創建數據表的語法形式。
可以使用 CREATE TABLE 語句創建表。其語法格式為:
CREATE TABLE <表名> ([表定義選項])[表選項][分區選項];
其中,[表定義選項]的格式為:<列名1> <類型1> [,…] <列名n> <類型n>
CREATE TABLE 命令語法比較多,其主要是由表創建定義(create-definition)、表選項(table-options)和分區選項(partition-options)所組成的。
這里首先描述一個簡單的新建表的例子,然后重點介紹 CREATE TABLE 命令中的一些主要的語法知識點。
CREATE TABLE 語句的主要語法及使用說明如下:
- CREATE TABLE:用於創建給定名稱的表,必須擁有表CREATE的權限。
- <表名>:指定要創建表的名稱,在 CREATE TABLE 之后給出,必須符合標識符命名規則。表名稱被指定為 db_name.tbl_name,以便在特定的數據庫中創建表。無論是否有當前數據庫,都可以通過這種方式創建。在當前數據庫中創建表時,可以省略 db_name。如果使用加引號的識別名,則應對數據庫和表名稱分別加引號。例如,'mydb'.'mytbl' 是合法的,但 'mydb.mytbl' 不合法。
- <表定義選項>:表創建定義,由列名(col_name)、列的定義(column_definition)以及可能的空值說明、完整性約束或表索引組成。
- 默認的情況是,表被創建到當前的數據庫中。若表已存在、沒有當前數據庫或者數據庫不存在,則會出現錯誤。
提示:使用 CREATE TABLE 創建表時,必須指定以下信息:
- 要創建的表的名稱不區分大小寫,不能使用SQL語言中的關鍵字,如DROP、ALTER、INSERT等。
- 數據表中每個列(字段)的名稱和數據類型,如果創建多個列,要用逗號隔開。
(1)在指定的數據庫中創建表
數據表屬於數據庫,在創建數據表之前,應使用語句“USE <數據庫>”指定操作在哪個數據庫中進行,
如果沒有選擇數據庫,就會拋出 No database selected 的錯誤。
創建員工表 tb_emp1,結構如下表所示。
| 字段名稱 | 數據類型 | 備注 |
|---|---|---|
| id | INT(10) | 員工編號 |
| name | VARCHAR(25) | 員工名稱 |
| deptld | INT(10) | 所在部門編號 |
| salary | FLOAT | 工資 |
如果之前創建過數據庫,可以使用之前創建的數據庫,如果沒有,我們可以新建一個數據庫,我們創建一個新的數據庫db_test。
mysql> create DATABASE db_test; Query OK, 1 row affected (0.00 sec)
選擇創建表的數據庫 db_test,創建 tb_emp1 數據表,輸入的 SQL 語句和運行結果如下所示。
mysql> use db_test;
Database changed
mysql> CREATE TABLE tb_emp1 ( id INT(10), name VARCHAR(25), deptId INT(10), salary FLOAT );
Query OK, 0 rows affected (0.02 sec)
語句執行后,便創建了一個名稱為 tb_emp1 的數據表,使用 SHOW TABLES;語句查看數據表是否創建成功,如下所示。

可以看出,數據庫中已經成功創建了tb_emp1表。
2、查看數據表
我們可以通過SHOW CREATE TABLE語句來查看數據表,語法格式如下。
SHOW CREATE TABLE <表名>
查看前面創建的tb_emp1表。
mysql> SHOW CREATE TABLE tb_emp1;

結果看起來有點亂,我們可以在查詢語句后面加上參數“\G”進行格式化。
mysql> SHOW CREATE TABLE tb_emp1 \G;

這樣看起來比之前整齊多了。
另外,我們還可以使用DESCRIBE語句或簡寫形式DESC語句查看表中列的信息。語法格式如下。
DESCRIBE <表名>;
DESC <表名>;
mysql> DESCRIBE tb_emp1;

3、修改數據表
在 MySQL 中可以使用 ALTER TABLE 語句來改變原有表的結構,例如增加或刪減列、更改原有列類型、重新命名列或表等。其語法格式如下:
ALTER TABLE <表名> [修改選項]
修改選項的語法格式如下:
{ ADD COLUMN <列名> <類型>
| CHANGE COLUMN <舊列名> <新列名> <新列類型>
| ALTER COLUMN <列名> { SET DEFAULT <默認值> | DROP DEFAULT }
| MODIFY COLUMN <列名> <類型>
| DROP COLUMN <列名>
| RENAME TO <新表名>
| CHARACTER SET <字符集名>
| COLLATE <校對規則名> }
(1)修改表名
MySQL 通過 ALTER TABLE 語句來實現表名的修改,語法規則如下:
ALTER TABLE <舊表名> RENAME [TO] <新表名>;
其中,TO 為可選參數,使用與否均不影響結果。
使用 ALTER TABLE 將數據表 tb_emp1改名為 tb_emp_info,SQL 語句和運行結果如下所示。
mysql> ALTER TABLE tb_emp1 RENAME TO tb_emp_info;
提示:修改表名並不修改表的結構,因此修改名稱后的表和修改名稱前的表的結構是相同的。用戶可以使用 DESC 命令查看修改后的表結構。
(2)修改字段
MySQL 中修改表字段名的語法規則如下:
ALTER TABLE <表名> CHANGE <舊字段名> <新字段名> <新數據類型>;
其中:
- 舊字段名:指修改前的字段名;
- 新字段名:指修改后的字段名;
- 新數據類型:指修改后的數據類型,如果不需要修改字段的數據類型,可以將新數據類型設置成與原來一樣,但數據類型不能為空。
使用 ALTER TABLE 修改表 tb_emp_info 的結構,將 deptId字段名稱改為 sex,同時將數據類型變為 VARCHAR(10),SQL 語句和運行結果如下所示。
mysql> ALTER TABLE tb_emp_info CHANGE deptId sex VARCHAR(10);
語句執行后,發現表 tb_emp_info 中 deptId字段名稱改為 sex,同時將數據類型變為 VARCHAR(10),修改成功。

CHANGE 也可以只修改數據類型,實現和 MODIFY (下一小節)同樣的效果,方法是將 SQL 語句中的“新字段名”和“舊字段名”設置為相同的名稱,只改變“數據類型”。
提示:由於不同類型的數據在機器中的存儲方式及長度並不相同,修改數據類型可能會影響數據表中已有的數據記錄.
因此,當數據表中已經有數據時,不要輕易修改數據類型。
(3)修改字段的數據類型
修改字段的數據類型就是把字段的數據類型轉換成另一種數據類型。在 MySQL 中修改字段數據類型的語法規則如下:
ALTER TABLE <表名> MODIFY <字段名> <數據類型>
其中:
- 表名:指要修改數據類型的字段所在表的名稱;
- 字段名:指需要修改的字段;
- 數據類型:指修改后字段的新數據類型。
使用 ALTER TABLE 修改表 tb_emp_info 的結構,將 name 字段的數據類型由 VARCHAR(25) 修改成 VARCHAR(30),SQL 語句和運行結果如下所示。
mysql> ALTER TABLE tb_emp_info MODIFY name VARCHAR(30);
語句執行后,發現表 tb_emp_info 中 name 字段的數據類型已經修改成 VARCHAR(30),修改成功。
(4)刪除字段
刪除字段是將數據表中的某個字段從表中移除,語法格式如下:
ALTER TABLE <表名> DROP <字段名>;
其中,“字段名”指需要從表中刪除的字段的名稱。
使用 ALTER TABLE 修改表 tb_emp_info 的結構,刪除 salary字段,SQL 語句和運行結果如下所示。
mysql> ALTER TABLE tb_emp_info DROP salary;
語句執行后,發現表 tb_emp_info 中 salary 字段沒有了,刪除成功。
(5)添加字段
MySQL 允許在開頭、中間和結尾處添加字段。
在末尾添加字段
一個完整的字段包括字段名、數據類型和約束條件。MySQL 添加字段的語法格式如下:
ALTER TABLE <表名> ADD <新字段名> <數據類型> [約束條件];
對語法格式的說明如下:
- <表名> 為數據表的名字;
- <新字段名> 為所要添加的字段的名字;
- <數據類型> 為所要添加的字段能存儲數據的數據類型;
- [約束條件] 是可選的,用來對添加的字段進行約束。
這種語法格式默認在表的最后位置(最后一列的后面)添加新字段。
注意:這里我們只添加新的字段,不關注它的約束條件。
使用 ALTER TABLE 語句在tb_emp_info表中添加一個 INT 類型的字段 age,SQL 語句和運行結果如下:
mysql> ALTER TABLE tb_emp_info ADD age INT(4);
由運行結果可以看到,tb_emp_info表已經添加了 age 字段,且該字段在表的最后一個位置,添加字段成功。
在開頭添加字段
MySQL 默認在表的最后位置添加新字段,如果希望在開頭位置(第一列的前面)添加新字段,那么可以使用 FIRST 關鍵字,語法格式如下:
ALTER TABLE <表名> ADD <新字段名> <數據類型> [約束條件] FIRST;
FIRST 關鍵字一般放在語句的末尾。
使用 ALTER TABLE 語句在表的第一列添加 INT 類型的字段 stuId,SQL 語句和運行結果如下所示。
mysql> ALTER TABLE tb_emp_info ADD empNum INT(4) FIRST;
由運行結果可以看到,tb_emp_info表中已經添加了empNum字段,且該字段在表中的第一個位置,添加字段成功。
在中間位置添加字段
MySQL 除了允許在表的開頭位置和末尾位置添加字段外,還允許在中間位置(指定的字段之后)添加字段,此時需要使用 AFTER 關鍵字,語法格式如下:
ALTER TABLE <表名> ADD <新字段名> <數據類型> [約束條件] AFTER <已經存在的字段名>;
AFTER 的作用是將新字段添加到某個已有字段后面。
注意,只能在某個已有字段的后面添加新字段,不能在它的前面添加新字段。
使用 ALTER TABLE 語句在tb_emp_info表中添加名為 school,數據類型為 VARCHAR(30)的字段,school字段位於 name 字段的后面。SQL 語句和運行結果如下:
mysql> ALTER TABLE tb_emp_info ADD school VARCHAR(30) AFTER name;
由運行結果可以看到,tb_emp_info表中已經添加了 school字段,且該字段在 name 字段后面的位置,添加字段成功。
(6)修改字段的排位順序
如果需要修改表中字段的位置,可以使用 ALTER TABLE 語句,語法格式如下:
ALTER TABLE <表名> MODIFY <字段名1> <數據類型> FIRST | AFTER <字段名2>;
對語法格式的說明如下:
- <表名> 為數據表的名字;
- <字段名1> 為需要修改位置的字段;
- <數據類型> 為需要修改位置的字段的數據類型;
- FIRST是可選參數,表示將字段1修改為第一個字段;
- AFTER <字段名2>表示將字段1插入到字段2的后面。
使用 ALTER TABLE 語句在tb_emp_info表中,將empNum字段移動到 id字段的后面。SQL 語句和運行結果如下:
mysql> ALTER TABLE tb_emp_info MODIFY empNum INT(4) AFTER id;
4、刪除數據表
在 MySQL 數據庫中,對於不再需要的數據表,我們可以將其從數據庫中刪除。
在刪除表的同時,表的結構和表中所有的數據都會被刪除,因此在刪除數據表之前最好先備份,以免造成無法挽回的損失。
使用 DROP TABLE 語句可以刪除一個或多個數據表,語法格式如下:
DROP TABLE [IF EXISTS] 表名1 [ ,表名2, 表名3 ...]
對語法格式的說明如下:
表名1, 表名2, 表名3 ...表示要被刪除的數據表的名稱。DROP TABLE 可以同時刪除多個表,只要將表名依次寫在后面,相互之間用逗號隔開即可。- IF EXISTS 用於在刪除數據表之前判斷該表是否存在。如果不加 IF EXISTS,當數據表不存在時 MySQL 將提示錯誤,中斷 SQL 語句的執行;加上 IF EXISTS 后,當數據表不存在時 SQL 語句可以順利執行,但是會發出警告(warning)。
兩點注意:
- 用戶必須擁有執行 DROP TABLE 命令的權限,否則數據表不會被刪除。
- 表被刪除時,用戶在該表上的權限不會自動刪除。
刪除數據表 tb_emp_info,輸入的 SQL 語句和運行結果如下所示:
mysql> DROP TABLE tb_emp_info;
五、表中數據的基本操作
1、添加數據
數據庫與表創建成功以后,需要向數據庫的表中插入數據。在 MySQL 中可以使用 INSERT 語句向數據庫已有的表中插入一行或者多行元組數據。
基本語法
INSERT 語句有兩種語法形式,分別是 INSERT…VALUES 語句和 INSERT…SET 語句。
(1)INSERT…VALUES語句
INSERT VALUES 的語法格式為:
INSERT INTO <表名> [ <列名1> [ , … <列名n>] ] VALUES (值1) [… , (值n) ];
語法說明如下。
<表名>:指定被操作的表名。<列名>:指定需要插入數據的列名。若向表中的所有列插入數據,則全部的列名均可以省略,直接采用 INSERT<表名>VALUES(…) 即可。VALUES或VALUE子句:該子句包含要插入的數據清單。數據清單中數據的順序要和列的順序相對應。
(2)INSERT…SET語句
語法格式為:
INSERT INTO <表名> SET <列名1> = <值1>, <列名2> = <值2>, …
此語句用於直接給表中的某些列指定對應的列值,即要插入的數據的列名在 SET 子句中指定,等號前面為指定的列名,等號后面為指定的數據,而對於未指定的列,列值會指定為該列的默認值。
由 INSERT 語句的兩種形式可以看出:
- 使用 INSERT…VALUES 語句可以向表中插入一行數據,也可以插入多行數據;
- 使用 INSERT…SET 語句可以指定插入行中每列的值,也可以指定部分列的值;
- INSERT…SELECT 語句向表中插入其他表的數據。
- 采用 INSERT…SET 語句可以向表中插入部分列的值,這種方式更為靈活;
- INSERT…VALUES 語句可以一次插入多條數據。
在 MySQL 中,用單條 INSERT 語句處理多個插入要比使用多條 INSERT 語句更快。
當使用單條 INSERT 語句插入多行數據的時候,只需要將每行數據用圓括號括起來即可。
向表中的全部字段添加值
在db_test 數據庫中創建一個課程信息表 tb_courses。
包含:課程編號 course_id、課程名稱 course_name、課程學分 course_grade 、課程備注 course_info,輸入的 SQL 語句和執行結果如下所示。
mysql> CREATE TABLE tb_courses
-> (
-> course_id INT NOT NULL AUTO_INCREMENT,
-> course_name CHAR(40) NOT NULL,
-> course_grade FLOAT NOT NULL,
-> course_info CHAR(100) NULL,
-> PRIMARY KEY(course_id)
-> );
Query OK, 0 rows affected (0.02 sec)

向表中所有字段插入值的方法有兩種:一種是指定所有字段名;另一種是完全不指定字段名。
【例 1】在 tb_courses 表中插入一條新記錄,course_id 值為 1,course_name 值為“Network”,course_grade 值為 3,info 值為“Computer Network”。
在執行插入操作之前,查看 tb_courses 表的SQL語句和執行結果如下所示。
mysql> SELECT * FROM tb_courses; Empty set (0.00 sec)
查詢結果顯示當前表內容為空,沒有數據,接下來執行插入數據的操作,輸入的 SQL 語句和執行過程如下所示。
mysql> INSERT INTO tb_courses (course_id,course_name,course_grade,course_info) VALUES(1,'Network',3,'Computer Network'); Query OK, 1 rows affected (0.01 sec) mysql> SELECT * FROM tb_courses;

可以看到插入記錄成功。在插入數據時,指定了 tb_courses 表的所有字段,因此將為每一個字段插入新的值。
INSERT 語句后面的列名稱順序可以不是 tb_courses 表定義時的順序,即插入數據時,不需要按照表定義的順序插入,只要保證值的順序與列字段的順序相同就可以。
【例 2】在 tb_courses 表中插入一條新記錄,course_id 值為 2,course_name 值為“Database”,course_grade 值為 3,info值為“MySQL”。輸入的 SQL 語句和執行結果如下所示。
mysql> INSERT INTO tb_courses (course_name,course_info,course_id,course_grade) VALUES('Database','MySQL',2,3);
Query OK, 1 rows affected (0.01 sec)
mysql> SELECT * FROM tb_courses;

使用 INSERT 插入數據時,允許列名稱列表 column_list 為空,此時值列表中需要為表的每一個字段指定值,並且值的順序必須和數據表中字段定義時的順序相同。
【例 3】在 tb_courses 表中插入一條新記錄,course_id 值為 3,course_name 值為“Java”,course_grade 值為 4,info 值為“Jave EE”。輸入的 SQL 語句和執行結果如下所示。
mysql> INSERT INTO tb_courses VALUES(3,'Java',4,'Java EE'); Query OK, 1 rows affected (0.01 sec) mysql> SELECT * FROM tb_courses;

INSERT 語句中沒有指定插入列表,只有一個值列表。在這種情況下,值列表為每一個字段列指定插入的值,並且這些值的順序必須和 tb_courses 表中字段定義的順序相同。
注意:雖然使用 INSERT 插入數據時可以忽略插入數據的列名稱,若值不包含列名稱,則 VALUES 關鍵字后面的值不僅要求完整,而且順序必須和表定義時列的順序相同。如果表的結構被修改,對列進行增加、刪除或者位置改變操作,這些操作將使得用這種方式插入數據時的順序也同時改變。如果指定列名稱,就不會受到表結構改變的影響。
向表中指定字段添加值
為表的指定字段插入數據,是在 INSERT 語句中只向部分字段中插入值,而其他字段的值為表定義時的默認值。
【例 4】在 tb_courses 表中插入一條新記錄,course_name 值為“System”,course_grade 值為 3,course_info 值為“Operating System”,輸入的 SQL 語句和執行結果如下所示。
mysql> INSERT INTO tb_courses (course_name,course_grade,course_info) VALUES('System',3,'Operation System');
Query OK, 1 rows affected (0.08 sec)
mysql> SELECT * FROM tb_courses;

可以看到插入記錄成功。如查詢結果顯示,這里的 course_id 字段自動添加了一個整數值 4。這時的 course_id 字段為表的主鍵,不能為空,系統自動為該字段插入自增的序列值。在插入記錄時,如果某些字段沒有指定插入值,MySQL 將插入該字段定義時的默認值。
(3)使用 INSERT INTO…FROM 語句復制表數據
INSERT INTO…SELECT…FROM 語句用於快速地從一個或多個表中取出數據,並將這些數據作為行數據插入另一個表中。
SELECT 子句返回的是一個查詢到的結果集,INSERT 語句將這個結果集插入指定表中,結果集中的每行數據的字段數、字段的數據類型都必須與被操作的表完全一致。
在數據庫 test_db 中創建一個與 tb_courses 表結構相同的數據表 tb_courses_new,創建表的 SQL 語句和執行過程如下所示。
mysql> CREATE TABLE tb_courses_new
-> (
-> course_id INT NOT NULL AUTO_INCREMENT,
-> course_name CHAR(40) NOT NULL,
-> course_grade FLOAT NOT NULL,
-> course_info CHAR(100) NULL,
-> PRIMARY KEY(course_id)
-> );
Query OK, 0 rows affected (0.03 sec)
mysql> SELECT * FROM tb_courses_new;
Empty set (0.00 sec)
【例 5】從 tb_courses 表中查詢所有的記錄,並將其插入 tb_courses_new 表中。輸入的 SQL 語句和執行結果如下所示。
mysql> INSERT INTO tb_courses_new (course_id,course_name,course_grade,course_info)
-> SELECT course_id,course_name,course_grade,course_info FROM tb_courses;
Query OK, 4 rows affected (0.17 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM tb_courses_new;

2、修改數據
在 MySQL 中,可以使用 UPDATE 語句來修改、更新一個或多個表的數據。
UPDATE 語句的基本語法
使用 UPDATE 語句修改單個表,語法格式為:
UPDATE <表名> SET 字段 1=值 1 [,字段 2=值 2… ] [WHERE 子句 ] [ORDER BY 子句] [LIMIT 子句]
語法說明如下:
<表名>:用於指定要更新的表名稱。SET子句:用於指定表中要修改的列名及其列值。其中,每個指定的列值可以是表達式,也可以是該列對應的默認值。如果指定的是默認值,可用關鍵字 DEFAULT 表示列值。WHERE子句:可選項。用於限定表中要修改的行。若不指定,則修改表中所有的行。ORDER BY子句:可選項。用於限定表中的行被修改的次序。LIMIT子句:可選項。用於限定被修改的行數。
注意:修改一行數據的多個列值時,SET 子句的每個值用逗號分開即可。
(1)修改表中的數據
【例 1】在 tb_courses_new 表中,更新所有行的 course_grade 字段值為 4,輸入的 SQL 語句和執行結果如下所示。
mysql> UPDATE tb_courses_new SET course_grade=4; Query OK, 3 rows affected (0.01 sec) Rows matched: 4 Changed: 3 Warnings: 0 mysql> SELECT * FROM tb_courses_new;

(2)根據條件修改表中的數據
【例 2】在 tb_courses 表中,更新 course_id 值為 2 的記錄,將 course_grade 字段值改為 3.5,將 course_name 字段值改為“DB”,輸入的 SQL 語句和執行結果如下所示。
mysql> UPDATE tb_courses_new SET course_name='DB',course_grade=3.5 WHERE course_id=2; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> SELECT * FROM tb_courses_new;

注意:保證 UPDATE 以 WHERE 子句結束,通過 WHERE 子句指定被更新的記錄所需要滿足的條件,如果忽略 WHERE 子句,MySQL 將更新表中所有的行。
3、刪除數據
在 MySQL 中,可以使用 DELETE 語句來刪除表的一行或者多行數據。
(1)刪除單個表中的數據
使用 DELETE 語句從單個表中刪除數據,語法格式為:
DELETE FROM <表名> [WHERE 子句] [ORDER BY 子句] [LIMIT 子句]
語法說明如下:
<表名>:指定要刪除數據的表名。ORDER BY子句:可選項。表示刪除時,表中各行將按照子句中指定的順序進行刪除。WHERE子句:可選項。表示為刪除操作限定刪除條件,若省略該子句,則代表刪除該表中的所有行。LIMIT子句:可選項。用於告知服務器在控制命令被返回到客戶端前被刪除行的最大值。
注意:在不使用 WHERE 條件的時候,將刪除所有數據。
(2)刪除表中的全部數據
【例 1】刪除 tb_courses_new 表中的全部數據,輸入的 SQL 語句和執行結果如下所示。
mysql> DELETE FROM tb_courses_new; Query OK, 4 rows affected (0.12 sec) mysql> SELECT * FROM tb_courses_new; Empty set (0.00 sec)

(3)根據條件刪除表中的數據
【例 2】在 tb_courses_new 表中,刪除 course_id 為 4 的記錄,輸入的 SQL 語句和執行結果如下所示。
mysql> DELETE FROM tb_courses WHERE course_id=4; Query OK, 1 row affected (0.01 sec) mysql> SELECT * FROM tb_courses;

由運行結果可以看出,course_id 為 4 的記錄已經被刪除。
4、清空表記錄
MySQL 提供了 DELETE 和 TRUNCATE 關鍵字來刪除表中的數據。這里主要講解 TRUNCATE 關鍵字的使用。
TRUNCATE 關鍵字用於完全清空一個表。其語法格式如下:
TRUNCATE [TABLE] 表名
其中,TABLE 關鍵字可省略。
【例1】新建表 tb_student_course,插入數據並查詢,SQL 語句和運行結果如下:
mysql> CREATE TABLE `tb_student_course` (
-> `id` int(4) NOT NULL AUTO_INCREMENT,
-> `name` varchar(25) NOT NULL,
-> PRIMARY KEY (`id`)
-> );
Query OK, 0 rows affected (0.03 sec)
mysql> INSERT INTO tb_student_course(name) VALUES ('Java'),('MySQL'),('Python');
Query OK, 3 rows affected (0.01 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM tb_student_course;

使用 TRUNCATE 語句清空 tb_student_course 表中的記錄,SQL 語句和運行結果如下:
mysql> TRUNCATE TABLE tb_student_course; Query OK, 0 rows affected (0.03 sec) mysql> SELECT * FROM tb_student_course; Empty set (0.00 sec)
TRUNCATE 和 DELETE 的區別
從邏輯上說,TRUNCATE 語句與 DELETE 語句作用相同,但是在某些情況下,兩者在使用上有所區別。
- DELETE 是 DML 類型的語句;TRUNCATE 是 DDL 類型的語句。它們都用來清空表中的數據。
- DELETE 是逐行一條一條刪除記錄的;TRUNCATE 則是直接刪除原來的表,再重新創建一個一模一樣的新表,而不是逐行刪除表中的數據,執行數據比 DELETE 快。因此需要刪除表中全部的數據行時,盡量使用 TRUNCATE 語句, 可以縮短執行時間。
- DELETE 刪除數據后,配合事件回滾可以找回數據;TRUNCATE 不支持事務的回滾,數據刪除后無法找回。
- DELETE 刪除數據后,系統不會重新設置自增字段的計數器;TRUNCATE 清空表記錄后,系統會重新設置自增字段的計數器。
- DELETE 的使用范圍更廣,因為它可以通過 WHERE 子句指定條件來刪除部分數據;而 TRUNCATE 不支持 WHERE 子句,只能刪除整體。
- DELETE 會返回刪除數據的行數,但是 TRUNCATE 只會返回 0,沒有任何意義。
總結
當不需要該表時,用 DROP;當仍要保留該表,但要刪除所有記錄時,用 TRUNCATE;當要刪除部分記錄時,用 DELETE。
六、查詢數據
在 MySQL 中,可以使用 SELECT 語句來查詢數據。查詢數據是指從數據庫中根據需求,使用不同的查詢方式來獲取不同的數據,是使用頻率最高、最重要的操作。
SELECT 的語法格式如下:
SELECT
{* | <字段列名>}
[
FROM <表 1>, <表 2>…
[WHERE <表達式>
[GROUP BY <group by definition>
[HAVING <expression> [{<operator> <expression>}…]]
[ORDER BY <order by definition>]
[LIMIT[<offset>,] <row count>]
]
其中,各條子句的含義如下:
{*|<字段列名>}包含星號通配符的字段列表,表示所要查詢字段的名稱。<表 1>,<表 2>…,表 1 和表 2 表示查詢數據的來源,可以是單個或多個。WHERE <表達式>是可選項,如果選擇該項,將限定查詢數據必須滿足該查詢條件。GROUP BY< 字段 >,該子句告訴 MySQL 如何顯示查詢出來的數據,並按照指定的字段分組。[ORDER BY< 字段 >],該子句告訴 MySQL 按什么樣的順序顯示查詢出來的數據,可以進行的排序有升序(ASC)和降序(DESC),默認情況下是升序。[LIMIT[<offset>,]<row count>],該子句告訴 MySQL 每次顯示查詢出來的數據條數。
下面先介紹一些簡單的 SELECT 語句,關於 WHERE、GROUP BY、ORDER BY 和 LIMIT 等限制條件,后面我們會一一講解。
1、查詢表中所有字段
查詢所有字段是指查詢表中所有字段的數據。MySQL 提供了以下 2 種方式查詢表中的所有字段。
- 使用“*”通配符查詢所有字段
- 列出表的所有字段
(1)使用“*”查詢表的所有字段
SELECT 可以使用“*”查找表中所有字段的數據,語法格式如下:
SELECT * FROM 表名;
使用“*”查詢時,只能按照數據表中字段的順序進行排列,不能改變字段的排列順序。
【例1】從 tb_courses 表中查詢所有字段的數據,SQL 語句和運行結果如下所示。
mysql> SELECT * FROM tb_courses;

結果顯示,使用“*”通配符時,將返回所有列,數據列按照創建表時的順序顯示。
注意:一般情況下,除非需要使用表中所有的字段數據,否則最好不要使用通配符“*”。雖然使用通配符可以節省輸入查詢語句的時間,但是獲取不需要的列數據通常會降低查詢和所使用的應用程序的效率。使用“*”的優勢是,當不知道所需列的名稱時,可以通過“*”獲取它們。
(2)列出表的所有字段
SELECT 關鍵字后面的字段名為需要查找的字段,因此可以將表中所有字段的名稱跟在 SELECT 關鍵字后面。如果忘記了字段名稱,可以使用 DESC 命令查看表的結構。
有時,由於表的字段比較多,不一定能記得所有字段的名稱,因此該方法很不方便,不建議使用。
【例2】查詢 tb_students_info 表中的所有數據,SQL 語句還可以書寫如下:
mysql> SELECT course_id,course_name,course_grade,course_info FROM tb_courses;
運行結果和例 1 相同。

這種查詢方式比較靈活,如果需要改變字段顯示的順序,只需調整 SELECT 關鍵字后面的字段列表順序即可。
雖然列出表的所有字段的方式比較靈活,但是查詢所有字段時通常使用“*”通配符。使用“*”這種方式比較簡單,尤其是表中的字段很多的時候,這種方式的優勢更加明顯。當然,如果需要改變字段顯示的順序,可以選擇列出表的所有字段。
2、查詢表中指定的字段
查詢表中的某一個字段的語法格式為:
SELECT < 列名 > FROM < 表名 >;
【例3】查詢 tb_courses 表中 name 列所有學生的姓名,SQL 語句和運行結果如下所示。
mysql> SELECT course_name FROM tb_courses;

輸出結果顯示了 tb_courses表中 course_name 字段下的所有數據。
使用 SELECT 聲明可以獲取多個字段下的數據,只需要在關鍵字 SELECT 后面指定要查找的字段名稱,不同字段名稱之間用逗號“,”分隔開,最后一個字段后面不需要加逗號,語法格式如下:
SELECT <字段名1>,<字段名2>,…,<字段名n> FROM <表名>;
【例4】從 tb_courses 表中獲取course_id、course_name 和 course_info三列,SQL 語句和運行結果如下所示。
mysql> SELECT course_id,course_name,course_info FROM tb_courses;

輸出結果顯示了tb_courses 表中的course_id、course_name 和 course_info三個字段下的所有數據。
3、使用DISTINCT過濾重復數據
在 MySQL 中使用 SELECT 語句執行簡單的數據查詢時,返回的是所有匹配的記錄。
如果表中的某些字段沒有唯一性約束,那么這些字段就可能存在重復值。
為了實現查詢不重復的數據,MySQL 提供了 DISTINCT 關鍵字。
DISTINCT 關鍵字的主要作用就是對數據表中一個或多個字段重復的數據進行過濾,只返回其中的一條數據給用戶。
DISTINCT 關鍵字的語法格式為:
SELECT DISTINCT <字段名> FROM <表名>;
其中,“字段名”為需要消除重復記錄的字段名稱,多個字段時用逗號隔開。
使用 DISTINCT 關鍵字時需要注意以下幾點:
- DISTINCT 關鍵字只能在 SELECT 語句中使用。
- 在對一個或多個字段去重時,DISTINCT 關鍵字必須在所有字段的最前面。
- 如果 DISTINCT 關鍵字后有多個字段,則會對多個字段進行組合去重,也就是說,只有多個字段組合起來完全是一樣的情況下才會被去重。
我們先在db_test數據庫中,創建一個測試用表tb_students,輸入的 SQL 語句如下所示。
mysql> use db_test
Database changed
mysql> CREATE TABLE tb_students
-> (
-> id INT NOT NULL AUTO_INCREMENT,
-> name VARCHAR(40) NOT NULL,
-> stuNo INT NOT NULL,
-> deptID INT NOT NULL,
-> age INT NOT NULL,
-> sex VARCHAR(1) NOT NULL,
-> height FLOAT,
-> weight FLOAT,
-> PRIMARY KEY(id)
-> );
Query OK, 0 rows affected (0.03 sec)
mysql> DESC tb_students;
然后,插入數據,輸入的 SQL 語句如下所示。
mysql> INSERT INTO tb_students (name,stuNo,deptId,age,sex,height,weight)
-> VALUES('zhangsan',10001,360101,18,'F',173,65);
Query OK, 1 row affected (0.01 sec)
mysql> INSERT INTO tb_students (name,stuNo,deptId,age,sex,height,weight)
-> VALUES('lisi',10002,360101,19,'M',175,68);
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO tb_students (name,stuNo,deptId,age,sex,height,weight)
-> VALUES('wangwu',10003,360101,18,'F',165,48);
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO tb_students (name,stuNo,deptId,age,sex,height,weight)
-> VALUES('zhaoliu',10004,360202,18,'M',185,68);
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO tb_students (name,stuNo,deptId,age,sex,height,weight)
-> VALUES('zhangsan',10005,360201,21,'M',185,88);
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO tb_students (name,stuNo,deptId,age,sex,height,weight)
-> VALUES('wangwu',10006,360202,21,'F',170,55);
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO tb_students (name,stuNo,deptId,age,sex,height,weight)
-> VALUES('zhaoliu',10007,360102,19,'F',173,48);
Query OK, 1 row affected (0.00 sec)
【例 1】下面通過一個具體的實例來說明如何實現查詢不重復數據。
db_test 數據庫中 tb_students 表的表結構和數據如下所示:
mysql> SELECT * FROM tb_students;

結果顯示,tb_students 表中存在 7條記錄。
下面對 tb_students 表的 age 字段進行去重,SQL 語句和運行結果如下:
mysql> SELECT DISTINCT age FROM tb_students;

對 tb_students 表的 name 和 sex字段進行去重,SQL 語句和運行結果如下:
mysql> SELECT DISTINCT name,sex FROM tb_students;

對tb_students 表中的所有字段進行去重,SQL 語句和運行結果如下:
mysql> SELECT DISTINCT * FROM tb_students;

因為 DISTINCT 只能返回它的目標字段,而無法返回其它字段,所以在實際情況中,我們經常使用 DISTINCT 關鍵字來返回不重復字段的條數。
查詢tb_students 表中對 name 和 sex 字段去重之后記錄的條數,SQL 語句和運行結果如下:
mysql> SELECT COUNT(DISTINCT name,sex) FROM tb_students;

結果顯示,tb_students 表中對 name 和 sex 字段去重之后有 6條記錄。
4、AS:設置別名
為了查詢方便,MySQL 提供了 AS 關鍵字來為表和字段指定別名
(1)為表指定別名
當表名很長或者執行一些特殊查詢的時候,為了方便操作,可以為表指定一個別名,用這個別名代替表原來的名稱。
為表指定別名的基本語法格式為:
<表名> [AS] <別名>
其中各子句的含義如下:
<表名>:數據庫中存儲的數據表的名稱。<別名>:查詢時指定的表的新名稱。AS關鍵字可以省略,省略后需要將表名和別名用空格隔開。
注意:表的別名不能與該數據庫的其它表同名。字段的別名不能與該表的其它字段同名。
在條件表達式中不能使用字段的別名,否則會出現“ERROR 1054 (42S22): Unknown column”這樣的錯誤提示信息。
【例 1】下面為 tb_students表指定別名 stu,SQL 語句和運行結果如下。
mysql> SELECT stu.name,stu.height FROM tb_students AS stu;

(2)為字段指定別名
在使用 SELECT 語句查詢數據時,MySQL 會顯示每個 SELECT 后面指定輸出的字段。有時為了顯示結果更加直觀,我們可以為字段指定一個別名。
為字段指定別名的基本語法格式為:
<字段名> [AS] <別名>
其中,各子句的語法含義如下:
<字段名>:為數據表中字段定義的名稱。<字段別名>:字段新的名稱。AS關鍵字可以省略,省略后需要將字段名和別名用空格隔開。
【例 2】查詢 tb_students 表,為 name 指定別名 student_name,為 age 指定別名 student_age,SQL 語句和運行結果如下。
mysql> SELECT name AS student_name, age AS student_age FROM tb_students;

注意:表別名只在執行查詢時使用,並不在返回結果中顯示。而字段定義別名之后,會返回給客戶端顯示,顯示的字段為字段的別名。
5、LIMIT:限制查詢結果的條數
當數據表中有上萬條數據時,一次性查詢出表中的全部數據會降低數據返回的速度,同時給數據庫服務器造成很大的壓力。
這時就可以用 LIMIT 關鍵字來限制查詢結果返回的條數。
LIMIT 是 MySQL 中的一個特殊關鍵字,用於指定查詢結果從哪條記錄開始顯示,一共顯示多少條記錄。
LIMIT 關鍵字有 3 種使用方式,即指定初始位置、不指定初始位置以及與 OFFSET 組合使用。
(1)指定初始位置
LIMIT 關鍵字可以指定查詢結果從哪條記錄開始顯示,顯示多少條記錄。
LIMIT 指定初始位置的基本語法格式如下:
LIMIT 初始位置,記錄數
其中,“初始位置”表示從哪條記錄開始顯示;“記錄數”表示顯示記錄的條數。第一條記錄的位置是 0,第二條記錄的位置是 1。后面的記錄依次類推。
注意:LIMIT 后的兩個參數必須都是正整數。
【例 1】在 tb_students 表中,使用 LIMIT 子句返回從第 4 條記錄開始的行數為 2 的記錄,SQL 語句和運行結果如下。
mysql> SELECT * FROM tb_students LIMIT 3,2;

由結果可以看到,該語句返回的是從第 4 條記錄開始的之后的 2 條記錄。
LIMIT 關鍵字后的第一個數字“3”表示從第 4 行開始(記錄的位置從 0 開始,第 4 行的位置為 3),第二個數字 2 表示返回的行數。
(2)不指定初始位置
LIMIT 關鍵字不指定初始位置時,記錄從第一條記錄開始顯示。顯示記錄的條數由 LIMIT 關鍵字指定。
LIMIT 不指定初始位置的基本語法格式如下:
LIMIT 記錄數
其中,“記錄數”表示顯示記錄的條數。如果“記錄數”的值小於查詢結果的總數,則會從第一條記錄開始,顯示指定條數的記錄。如果“記錄數”的值大於查詢結果的總數,則會直接顯示查詢出來的所有記錄。
【例 2】顯示 tb_students 表查詢結果的前 4 行,SQL 語句和運行結果如下。
mysql> SELECT * FROM tb_students LIMIT 4;

結果中只顯示了 4 條記錄,說明“LIMIT 4”限制了顯示條數為 4。
【例 3】顯示 tb_students 表查詢結果的前 15 行,SQL 語句和運行結果如下。
mysql> SELECT * FROM tb_students LIMIT 15;

結果中只顯示了 10 條記錄。雖然 LIMIT 關鍵字指定了顯示 15 條記錄,但是查詢結果中只有 10 條記錄。因此,數據庫系統就將這 10 條記錄全部顯示出來。
帶一個參數的 LIMIT 指定從查詢結果的首行開始,唯一的參數表示返回的行數,即“LIMIT n”與“LIMIT 0,n”返回結果相同。
帶兩個參數的 LIMIT 可返回從任何位置開始指定行數的數據。
(3)LIMIT和OFFSET組合使用
LIMIT 可以和 OFFSET 組合使用,語法格式如下:
LIMIT 記錄數 OFFSET 初始位置
參數和 LIMIT 語法中參數含義相同,“初始位置”指定從哪條記錄開始顯示;“記錄數”表示顯示記錄的條數。
【例 4】在 tb_students 表中,使用 LIMIT OFFSET 返回從第 4 條記錄開始的行數為 2 的記錄,SQL 語句和運行結果如下。
mysql> SELECT * FROM tb_students LIMIT 2 OFFSET 3;

由結果可以看到,該語句返回的是從第 4 條記錄開始的之后的 2 條記錄。即“LIMIT 2 OFFSET 3”意思是獲取從第 4 條記錄開始的后面的 2 條記錄,和“LIMIT 3,2”返回的結果相同。
6、ORDER BY:對查詢結果排序
通過條件查詢語句可以查詢到符合用戶需求的數據,但是查詢到的數據一般都是按照數據最初被添加到表中的順序來顯示。
為了使查詢結果的順序滿足用戶的要求,MySQL 提供了 ORDER BY 關鍵字來對查詢結果進行排序。
在實際應用中經常需要對查詢結果進行排序,比如,在網上購物時,可以將商品按照價格進行排序;在醫院的掛號系統中,可以按照掛號的先后順序進行排序等。
ORDER BY 關鍵字主要用來將查詢結果中的數據按照一定的順序進行排序。其語法格式如下:
ORDER BY <字段名> [ASC|DESC]
語法說明如下:
- 字段名:表示需要排序的字段名稱,多個字段時用逗號隔開。
- ASC|DESC:
ASC表示字段按升序排序;DESC表示字段按降序排序。其中ASC為默認值。
使用 ORDER BY 關鍵字應該注意以下幾個方面:
- ORDER BY 關鍵字后可以跟子查詢(子查詢后面就會詳細講到)。
- 當排序的字段中存在空值時,ORDER BY 會將該空值作為最小值來對待。
- ORDER BY 指定多個字段進行排序時,MySQL 會按照字段的順序從左到右依次進行排序。
(1)單字段排序
下面通過一個具體的實例來說明當 ORDER BY 指定單個字段時,MySQL 如何對查詢結果進行排序。
【例 1】下面查詢 tb_students 表的所有記錄,並對 height 字段進行排序,SQL 語句和運行結果如下。
mysql> SELECT * FROM tb_students ORDER BY height;

由結果可以看到,MySQL 對查詢的 height 字段的數據按數值的大小進行了升序排序。
(2)多字段排序
下面通過一個具體的實例來說明當 ORDER BY 指定多個字段時,MySQL 如何對查詢結果進行排序。
【例 2】查詢 tb_students 表中的 name 和 height 字段,先按 height 排序,再按 name 排序,SQL 語句和運行結果如下。
mysql> SELECT name,height FROM tb_students ORDER BY height,name;

注意:在對多個字段進行排序時,排序的第一個字段必須有相同的值,才會對第二個字段進行排序。
如果第一個字段數據中所有的值都是唯一的,MySQL 將不再對第二個字段進行排序。
默認情況下,查詢數據按字母升序進行排序(A~Z),但數據的排序並不僅限於此,還可以使用 ORDER BY 中的 DESC 對查詢結果進行降序排序(Z~A)。
【例 3】查詢 tb_students 表,先按 height 降序排序,再按 name 升序排序,SQL 語句和運行結果如下。
mysql> SELECT name,height FROM tb_students ORDER BY height DESC,name ASC;

DESC 關鍵字只對前面的列進行降序排列,在這里只對 height 字段進行降序。
因此,height 按降序排序,而 name 仍按升序排序。如果想在多個列上進行降序排序,必須對每個列指定 DESC 關鍵字。
7、WHERE:條件查詢數據
在 MySQL 中,如果需要有條件的從數據表中查詢數據,可以使用 WHERE 關鍵字來指定查詢條件。
使用 WHERE 關鍵字的語法格式如下:
WHERE 查詢條件
查詢條件可以是:
- 帶比較運算符和邏輯運算符的查詢條件
- 帶 BETWEEN AND 關鍵字的查詢條件
- 帶 IS NULL 關鍵字的查詢條件
- 帶 IN 關鍵字的查詢條件
- 帶 LIKE 關鍵字的查詢條件
(1)單一條件的查詢語句
單一條件指的是在 WHERE 關鍵字后只有一個查詢條件。
【例 1】在 tb_students 數據表中查詢身高為 170cm 的學生姓名,SQL 語句和運行結果如下。
mysql> SELECT name,height FROM tb_students WHERE height=170;

可以看到,查詢結果中記錄的 height 字段的值等於 170。如果根據指定的條件進行查詢時,數據表中沒有符合查詢條件的記錄,系統會提示“Empty set(0.00sec)”。
【例 2】在 tb_students 數據表中查詢年齡小於 20 的學生姓名,SQL 語句和運行結果如下。
mysql> SELECT name,age FROM tb_students WHERE age<20;

可以看到,查詢結果中所有記錄的 age 字段的值均小於 20 歲,而大於或等於 20 歲的記錄沒有被返回。
(2)多條件的查詢語句
在 WHERE 關鍵詞后可以有多個查詢條件,這樣能夠使查詢結果更加精確。多個查詢條件時用邏輯運算符 AND(&&)、OR(||)或 XOR 隔開。
- AND:記錄滿足所有查詢條件時,才會被查詢出來。
- OR:記錄滿足任意一個查詢條件時,才會被查詢出來。
- XOR:記錄滿足其中一個條件,並且不滿足另一個條件時,才會被查詢出來。
【例 3】在 tb_students 表中查詢 age 大於 19,並且 height 大於等於 170 的學生信息,SQL 語句和運行結果如下。
mysql> SELECT name,age,height FROM tb_students WHERE age>19 AND height>=170;

可以看到,查詢結果中所有記錄的 age 字段都大於19 且 height 字段都大於等於 170。
【例 4】在 tb_students 表中查詢 age 大於 19,或者 height 大於等於 170 的學生信息,SQL 語句和運行結果如下。
mysql> SELECT name,age,height FROM tb_students WHERE age>19 OR height>=170;

可以看到,查詢結果中所有記錄的 age 字段都大於 19 或者 height 字段都大於等於 170。
【例 5】在 tb_students 表中查詢 age 大於 19,並且 height 小於 173 的學生信息
和 age 小於等於 19,並且 height 大於等於 173 的學生信息,SQL 語句和運行結果如下。(好好理解,有點難!!!)
mysql> SELECT name,age,height FROM tb_students WHERE age>19 XOR height>=173;

可以看到,查詢結果中所有記錄的 age 字段都大於 19 且 height 字段都小於 173
和 age 字段小於等於 19 且 height 字段大於等於 173 的記錄。
注意:OR、AND 和 XOR 可以一起使用,但是在使用時要注意運算符的優先級。
8、LIKE:模糊查詢
在 MySQL 中,LIKE 關鍵字主要用於搜索匹配字段中的指定內容。其語法格式如下:
[NOT] LIKE '字符串'
其中:
- NOT :可選參數,字段中的內容與指定的字符串不匹配時滿足條件。
- 字符串:指定用來匹配的字符串。“字符串”可以是一個很完整的字符串,也可以包含通配符。
LIKE 關鍵字支持百分號“%”和下划線“_”通配符。
通配符是一種特殊語句,主要用來模糊查詢。當不知道真正字符或者懶得輸入完整名稱時,可以使用通配符來代替一個或多個真正的字符。
(1)帶有“%”通配符的查詢
“%”是 MySQL 中最常用的通配符,它能代表任何長度的字符串,字符串的長度可以為 0。
例如,a%b表示以字母 a 開頭,以字母 b 結尾的任意長度的字符串。該字符串可以代表 ab、acb、accb、accrb 等字符串。
【例 1】在 tb_students 表中,查找所有以字母“Z”開頭的學生姓名(默認情況下,LIKE 關鍵字匹配字符的時候是不區分大小寫的),SQL 語句和運行結果如下。
mysql> SELECT name FROM tb_students WHERE name LIKE 'Z%';

可以看到,查詢結果中只返回了以字母“Z”開頭的學生姓名。
注意:匹配的字符串必須加單引號或雙引號。
NOT LIKE 表示字符串不匹配時滿足條件。
【例 2】在 tb_students 表中,查找所有不以字母“Z”開頭的學生姓名,SQL 語句和運行結果如下。
mysql> SELECT NAME FROM tb_students WHERE NAME NOT LIKE 'Z%';

可以看到,查詢結果中返回了不以字母“Z”開頭的學生姓名。
【例 3】在 tb_students 表中,查找所有包含字母“L”的學生姓名,SQL 語句和運行結果如下。
mysql> SELECT name FROM tb_students WHERE name LIKE '%L%';

可以看到,查詢結果中返回了所有包含字母“e”的學生姓名。
(2)帶有“_”通配符的查詢
“_”只能代表單個字符,字符的長度不能為 0。例如,a_b可以代表 acb、adb、aub 等字符串。
【例 4】在 tb_students 表中,查找所有以字母“U”結尾,且“U”前面只有 5 個字母的學生姓名,SQL 語句和運行結果如下。
mysql> SELECT name FROM tb_students WHERE name LIKE '_____U';

(3)LIKE 區分大小寫
默認情況下,LIKE 關鍵字匹配字符的時候是不區分大小寫的。如果需要區分大小寫,可以加入 BINARY 關鍵字。
【例 5】在 tb_students 表中,查找所有以字母“t”開頭的學生姓名,區分大小寫和不區分大小寫的 SQL 語句和運行結果如下。
mysql> SELECT name FROM tb_students WHERE name LIKE 'Z%';

mysql> SELECT name FROM tb_students WHERE name LIKE BINARY 'Z%';
Empty set (0.01 sec)
由結果可以看到,區分大小寫后,“zhangsan”和“zhaoliu”等記錄就不會被匹配到了。
(3)使用通配符的注意事項和技巧
下面是使用通配符的一些注意事項:
- 注意大小寫。MySQL 默認是不區分大小寫的。如果區分大小寫,像“zhangsan”這樣的數據就不能被“Z%”所匹配到。
- 注意尾部空格。尾部空格會干擾通配符的匹配。例如,“Z% ”就不能匹配到“zhangsan”。
- 注意 NULL。“%”通配符可以到匹配任意字符,但是不能匹配 NULL。也就是說 “%”匹配不到 tb_students 數據表中值為 NULL 的記錄。
下面是一些使用通配符要記住的技巧:
- 不要過度使用通配符。如果其它操作符能達到相同的目的,應該使用其它操作符。因為 MySQL 對通配符的處理一般會比其他操作符花費更長的時間。
- 在確定使用通配符后,除非絕對有必要,否則不要把它們用在字符串的開始處。把通配符置於搜索模式的開始處,搜索起來是最慢的。
- 仔細注意通配符的位置。如果放錯地方,可能不會返回想要的數據。
總之,通配符是一種極其重要和有用的搜索工具,以后我們會經常用到它。
(4)拓展
如果查詢內容中包含通配符,可以使用“\”轉義符。
例如,在 tb_students 表中,將學生姓名“zhaoliu”修改為“zhaoliu%”后,查詢以“%”結尾的學生姓名,SQL 語句和運行結果如下:
mysql> SELECT NAME FROM tb_students WHERE NAME LIKE '%\%';

9、BETWEEN AND:范圍查詢
MySQL 提供了 BETWEEN AND 關鍵字,用來判斷字段的數值是否在指定范圍內。
BETWEEN AND 需要兩個參數,即范圍的起始值和終止值。如果字段值在指定的范圍內,則這些記錄被返回。如果不在指定范圍內,則不會被返回。
使用 BETWEEN AND 的基本語法格式如下:
[NOT] BETWEEN 取值1 AND 取值2
其中:
- NOT:可選參數,表示指定范圍之外的值。如果字段值不滿足指定范圍內的值,則這些記錄被返回。
- 取值1:表示范圍的起始值。
- 取值2:表示范圍的終止值。
BETWEEN AND 和 NOT BETWEEN AND 關鍵字在查詢指定范圍內的記錄時很有用。例如,查詢學生的年齡段、出生日期,員工的工資水平等。
【例 1】在表 tb_students 中查詢年齡在 20 到 23 之間的學生姓名和年齡,SQL 語句和運行結果如下。
mysql> SELECT name,age FROM tb_students WHERE age BETWEEN 19 AND 23;

查詢結果中包含學生年齡為 19 和 23 的記錄,這就說明,在 MySQL 中,BETWEEN AND 能匹配指定范圍內的所有值,包括起始值和終止值。
【例 2】在表 tb_students 中查詢年齡不在 19 到 23 之間的學生姓名和年齡,SQL 語句和運行結果如下。
mysql> SELECT name,age FROM tb_students WHERE age NOT BETWEEN 19 AND 23;

10、IS NULL:空值查詢
MySQL 提供了 IS NULL 關鍵字,用來判斷字段的值是否為空值(NULL)。空值不同於 0,也不同於空字符串。
如果字段的值是空值,則滿足查詢條件,該記錄將被查詢出來。如果字段的值不是空值,則不滿足查詢條件。
使用 IS NULL 的基本語法格式如下:
IS [NOT] NULL
其中,“NOT”是可選參數,表示字段值不是空值時滿足條件。
准備工作:在 tb_students 表中增加 birthday字段。
mysql> ALTER TABLE tb_students ADD birthday DATE;

【例 1】下面使用 IS NULL 關鍵字來查詢 tb_students 表中 birthday字段是 NULL 的記錄。
mysql> SELECT name,birthday FROM tb_students WHERE birthday IS NULL;

注意:IS NULL 是一個整體,不能將 IS 換成“=”。
如果將 IS 換成“=”將不能查詢出任何結果,數據庫系統會出現“Empty set (0.00 sec)”這樣的提示。
同理,IS NOT NULL 中的 IS NOT 不能換成“!=”或“<>”。
IS NOT NULL 表示查詢字段值不為空的記錄。
【例 2】下面使用 IS NOT NULL 關鍵字來查詢 tb_students 表中 birthday 字段不為空的記錄。
mysql> SELECT name,birthday FROM tb_students WHERE birthday IS NOT NULL;
Empty set (0.00 sec)
11、使用GROUP BY分組查詢
在 MySQL 中,GROUP BY 關鍵字可以根據一個或多個字段對查詢結果進行分組。
使用 GROUP BY 關鍵字的語法格式如下:
GROUP BY <字段名>
其中,“字段名”表示需要分組的字段名稱,多個字段時用逗號隔開。
(1)GROUP BY單獨使用
單獨使用 GROUP BY 關鍵字時,要注意,如果在SELECT中的列,沒有在GROUP BY中出現,那么這個SQL是不合法的。
【例 1】下面根據 tb_students 表中的 sex 字段進行分組查詢,SQL 語句和運行結果如下:
mysql> SELECT name,sex FROM tb_students GROUP BY sex;

ONLY_FULL_GROUP_BY的意思是:對於GROUP BY聚合操作,如果在SELECT中的列不在GROUP BY從句中,那么這個字段就應該出現在聚合函數里面。
也就是,在SELECT指定的字段要么包含在GROUP BY語句的后面,作為分組的依據;要么就要被包含在聚合函數中。
mysql> SELECT name,sex FROM tb_students GROUP BY name,sex;

將SELECT查詢的字段都放到GROUP BY語句后,這樣SQL語句是正確的,但是這樣的查詢結果意義不大。
(2)GROUP BY 與 GROUP_CONCAT()
GROUP BY 關鍵字可以和 GROUP_CONCAT() 函數一起使用。GROUP_CONCAT() 函數會把每個分組的字段值都顯示出來。
【例 2】下面根據 tb_students 表中的 sex 字段進行分組查詢,使用 GROUP_CONCAT() 函數將每個分組的 name 字段的值都顯示出來。SQL 語句和運行結果如下:
mysql> SELECT sex, GROUP_CONCAT(name) FROM tb_students GROUP BY sex;

由結果可以看到,查詢結果分為兩組,sex 字段值為“F”(女)的是一組,值為“M”(男)的是一組,且每組的學生姓名都顯示出來了。
【例 3】下面根據 tb_students 表中的 age 和 sex 字段進行分組查詢。SQL 語句和運行結果如下:
mysql> SELECT age,sex,GROUP_CONCAT(name) FROM tb_students GROUP BY age,sex;

上面實例在分組過程中,先按照 age 字段進行分組,當 age 字段值相等時,再把 age 字段值相等的記錄按照 sex 字段進行分組。
多個字段分組查詢時,會先按照第一個字段進行分組。如果第一個字段中有相同的值,MySQL 才會按照第二個字段進行分組。
如果第一個字段中的數據都是唯一的,那么 MySQL 將不再對第二個字段進行分組。
(3)GROUP BY 與聚合函數
在數據統計時,GROUP BY 關鍵字經常和聚合函數一起使用。
聚合函數包括 COUNT(),SUM(),AVG(),MAX() 和 MIN()。
其中,COUNT() 用來統計記錄的條數;
SUM() 用來計算字段值的總和;
AVG() 用來計算字段值的平均值;
MAX() 用來查詢字段的最大值;
MIN() 用來查詢字段的最小值。
【例 4】下面根據 tb_students 表的 sex 字段進行分組查詢,使用 COUNT() 函數計算每一組的記錄數。SQL 語句和運行結果如下:
mysql> SELECT sex,COUNT(sex) FROM tb_students GROUP BY sex;

結果顯示,sex 字段值為“F”(女)的記錄是一組,有 4 條記錄;sex 字段值為“M”(男)的記錄是一組,有 3 條記錄。
(4)GROUP BY 與 WITH ROLLUP
WITH POLLUP 關鍵字用來在所有記錄的最后加上一條記錄,這條記錄是上面所有記錄的總和,即統計記錄數量。
【例 5】下面對【例2】的 sex 字段進行分組查詢,並使用 WITH ROLLUP 顯示記錄的總和。
mysql> SELECT sex,GROUP_CONCAT(name) FROM tb_students GROUP BY sex WITH ROLLUP;

查詢結果顯示,GROUP_CONCAT(name) 顯示了每個分組的 name 字段值。同時,最后一條記錄的 GROUP_CONCAT(name) 字段的值剛好是上面分組 name 字段值的總和。
【例 6】下面對【例4】的 sex 字段進行分組查詢,並使用 WITH ROLLUP 顯示記錄的總和。
mysql> SELECT sex,COUNT(sex) FROM tb_students GROUP BY sex WITH ROLLUP;

查詢結果顯示,COUNT(sex) 顯示了每個分組的 sex的記錄數(每個性別的人數)。同時,最后一條記錄的 COUNT(sex) 字段的值剛好是上面分組 人數的總和。
12、HAVING:過濾分組
在 MySQL 中,可以使用 HAVING 關鍵字對分組后的數據進行過濾。
使用 HAVING 關鍵字的語法格式如下:
HAVING <查詢條件>
HAVING 關鍵字和 WHERE 關鍵字都可以用來過濾數據,且 HAVING 支持 WHERE 關鍵字中所有的操作符和語法。
但是 WHERE 和 HAVING 關鍵字也存在以下幾點差異:
- 一般情況下,WHERE 用於過濾數據行,而 HAVING 用於過濾分組。
- WHERE 查詢條件中不可以使用聚合函數,而 HAVING 查詢條件中可以使用聚合函數。
- WHERE 在數據分組前進行過濾,而 HAVING 在數據分組后進行過濾 。
- WHERE 針對數據庫文件進行過濾,而 HAVING 針對查詢結果進行過濾。也就是說,WHERE 根據數據表中的字段直接進行過濾,而 HAVING 是根據前面已經查詢出的字段進行過濾。
- WHERE 查詢條件中不可以使用字段別名,而 HAVING 查詢條件中可以使用字段別名。
下面通過實例讓大家更直觀的了解 WHERE 和 HAVING 關鍵字的相同點和不同點。
【例 1】分別使用 HAVING 和 WHERE 關鍵字查詢出 tb_students 表中身高大於 150 的學生姓名,性別和身高。SQL 語句和運行結果如下。
mysql> SELECT name,sex,height FROM tb_students HAVING height>150;
mysql> SELECT name,sex,height FROM tb_students WHERE height>150;

上述實例中,因為在 SELECT 關鍵字后已經查詢出了 height 字段,所以 HAVING 和 WHERE 都可以使用。
但是如果 SELECT 關鍵字后沒有查詢出 height 字段,MySQL 就會報錯。
【例 2】使用 HAVING 和 WHERE 關鍵字分別查詢出 tb_students 表中身高大於 150 的學生姓名和性別(與例 1 相比,這次沒有查詢 height 字段)。SQL 語句和運行結果如下。
mysql> SELECT name,sex FROM tb_students WHERE height>150;

mysql> SELECT name,sex FROM tb_students HAVING height>150; ERROR 1054 (42S22): Unknown column 'height' in 'having clause'
![]()
由結果可以看出,如果 SELECT 關鍵字后沒有查詢出 HAVING 查詢條件中使用的 height 字段,MySQL 會提示錯誤信息:“having子句”中的列“height”未知”。
【例 3】根據 height 字段對 tb_students 表中的數據進行分組,並使用 HAVING 和 WHERE 關鍵字分別查詢出分組后平均身高大於 170 的學生姓名、性別和身高。SQL 語句和運行結果如下。
mysql> SELECT GROUP_CONCAT(name),sex,height FROM tb_students GROUP BY sex,height HAVING AVG(height)>170;

mysql> SELECT GROUP_CONCAT(name),sex,height FROM tb_students WHERE AVG(height)>170 GROUP BY sex,height;
ERROR 1111 (HY000): Invalid use of group function
![]()
由結果可以看出,如果在 WHERE 查詢條件中使用聚合函數,MySQL 會提示錯誤信息:無效使用組函數。
13、CROSS JOIN:交叉連接
前面所講的查詢語句都是針對一個表的,但是在關系型數據庫中,表與表之間是有聯系的,所以在實際應用中,經常使用多表查詢。
多表查詢就是同時查詢兩個或兩個以上的表。
在 MySQL 中,多表查詢主要有交叉連接、內連接和外連接。
交叉連接(CROSS JOIN)一般用來返回連接表的笛卡爾積。
本段的末尾介紹了笛卡爾積,不了解笛卡爾積的同學可以先閱讀本段末尾部分,然后再回來學習交叉連接。
交叉連接的語法格式如下:
SELECT <字段名> FROM <表1> CROSS JOIN <表2> [WHERE子句]
或
SELECT <字段名> FROM <表1>, <表2> [WHERE子句]
語法說明如下:
- 字段名:需要查詢的字段名稱。
- <表1><表2>:需要交叉連接的表名。
- WHERE 子句:用來設置交叉連接的查詢條件。
注意:多個表交叉連接時,在 FROM 后連續使用 CROSS JOIN 或,即可。以上兩種語法的返回結果是相同的,但是第一種語法才是官方建議的標准寫法。
當連接的表之間沒有關系時,我們會省略掉 WHERE 子句,這時返回結果就是兩個表的笛卡爾積,返回結果數量就是兩個表的數據行相乘。
需要注意的是,如果每個表有 1000 行,那么返回結果的數量就有 1000×1000 = 1000000 行,數據量是非常巨大的。
交叉連接可以查詢兩個或兩個以上的表,為了讓讀者更好的理解,下面先講解兩個表的交叉連接查詢。
准備工作:在tb_students表中增加course_id字段,並且,給該字段賦上幾個值。
mysql> ALTER TABLE tb_students ADD course_id INT;
mysql> UPDATE tb_students SET course_id=1 WHERE deptId=360101;
mysql> UPDATE tb_students SET course_id=2 WHERE deptId=360202;
mysql> UPDATE tb_students SET course_id=3 WHERE deptId=360201 OR deptId=360102;

【例 1】查詢學生信息表和科目信息表,並得到一個笛卡爾積。
為了方便觀察學生信息表和科目表交叉連接后的運行結果,我們先分別查詢出這兩個表的數據,再進行交叉連接查詢。
1)查詢 tb_students 表中的數據,SQL 語句和運行結果如下:
mysql> SELECT * FROM tb_students;

2)查詢 tb_courses 表中的數據,SQL 語句和運行結果如下:
mysql> SELECT * FROM tb_courses;

3)使用 CROSS JOIN 查詢出兩張表中的笛卡爾積,SQL 語句和運行結果如下:
mysql> SELECT * FROM tb_courses CROSS JOIN tb_students;

由運行結果可以看出,tb_courses 和 tb_students 表交叉連接查詢后,返回了 21 條記錄。
可以想象,當表中的數據較多時,得到的運行結果會非常長,而且得到的運行結果也沒太大的意義。
所以,通過交叉連接的方式進行多表查詢的這種方法並不常用,我們應該盡量避免這種查詢。
【例 2】查詢 tb_courses 表中的 id 字段和 tb_students 表中的 course_id 字段相等的內容, SQL 語句和運行結果如下:
mysql> SELECT * FROM tb_courses CROSS JOIN tb_students WHERE tb_students.course_id = tb_courses.course_id;

如果在交叉連接時使用 WHERE 子句,MySQL 會先生成兩個表的笛卡爾積,然后再選擇滿足 WHERE 條件的記錄。
因此,表的數量較多時,交叉連接會非常非常慢。一般情況下不建議使用交叉連接。
在 MySQL 中,多表查詢一般使用內連接和外連接,它們的效率要高於交叉連接。
笛卡爾積
笛卡爾積(Cartesian product)是指兩個集合 X 和 Y 的乘積。
例如,有 A 和 B 兩個集合,它們的值如下:
A = {1,2}
B = {3,4,5}
集合 A×B 和 B×A 的結果集分別表示為:
A×B={(1,3), (1,4), (1,5), (2,3), (2,4), (2,5) };
B×A={(3,1), (3,2), (4,1), (4,2), (5,1), (5,2) };
以上 A×B 和 B×A 的結果就叫做兩個集合的笛卡爾積。
並且,從以上結果我們可以看出:
- 兩個集合相乘,不滿足交換率,即 A×B≠B×A。
- A 集合和 B 集合的笛卡爾積是 A 集合的元素個數 × B 集合的元素個數。
多表查詢遵循的算法就是以上提到的笛卡爾積,表與表之間的連接可以看成是在做乘法運算。
在實際應用中,應避免使用笛卡爾積,因為笛卡爾積中容易存在大量的不合理數據,簡單來說就是容易導致查詢結果重復、混亂。
14、INNER JOIN:內連接
內連接(INNER JOIN)主要通過設置連接條件的方式,來移除查詢結果中某些數據行的交叉連接。簡單來說,就是利用條件表達式來消除交叉連接的某些數據行。
內連接使用 INNER JOIN 關鍵字連接兩張表,並使用 ON 子句來設置連接條件。如果沒有連接條件,INNER JOIN 和 CROSS JOIN 在語法上是等同的,兩者可以互換。
內連接的語法格式如下:
SELECT <字段名> FROM <表1> INNER JOIN <表2> [ON子句]
語法說明如下。
- 字段名:需要查詢的字段名稱。
- <表1><表2>:需要內連接的表名。
- INNER JOIN :內連接中可以省略 INNER 關鍵字,只用關鍵字 JOIN。
- ON 子句:用來設置內連接的連接條件。
INNER JOIN 也可以使用 WHERE 子句指定連接條件,但是 INNER JOIN ... ON 語法是官方的標准寫法,而且 WHERE 子句在某些時候會影響查詢的性能。
多個表內連接時,在 FROM 后連續使用 INNER JOIN 或 JOIN 即可。
內連接可以查詢兩個或兩個以上的表。為了讓大家更好的理解,暫時只講解兩個表的連接查詢。
【例 1】在 tb_students 表和 tb_courses 表之間,使用內連接查詢學生姓名和相對應的課程名稱,SQL 語句和運行結果如下。
mysql> SELECT s.name,c.course_name FROM tb_students s INNER JOIN tb_courses c ON s.course_id = c.course_id;

在這里的查詢語句中,兩個表之間的關系通過 INNER JOIN 指定,連接的條件使用 ON 子句給出。
注意:當對多個表進行查詢時,要在 SELECT 語句后面指定字段是來源於哪一張表。
因此,在多表查詢時,SELECT 語句后面的寫法是表名.列名。
另外,如果表名非常長的話,也可以給表設置別名,這樣就可以直接在 SELECT 語句后面寫上表的別名.列名。
15、LEFT/RIGHT JOIN:外連接
內連接的查詢結果都是符合連接條件的記錄,而外連接會先將連接的表分為基表和參考表,再以基表為依據返回滿足和不滿足條件的記錄。
外連接可以分為左外連接和右外連接,下面根據實例分別介紹左外連接和右外連接。
左連接
左外連接又稱為左連接,使用 LEFT OUTER JOIN 關鍵字連接兩個表,並使用 ON 子句來設置連接條件。
左連接的語法格式如下:
SELECT <字段名> FROM <表1> LEFT OUTER JOIN <表2> <ON子句>
語法說明如下。
- 字段名:需要查詢的字段名稱。
- <表1><表2>:需要左連接的表名。
- LEFT OUTER JOIN:左連接中可以省略 OUTER 關鍵字,只使用關鍵字 LEFT JOIN。
- ON 子句:用來設置左連接的連接條件,不能省略。
上述語法中,“表1”為基表,“表2”為參考表。左連接查詢時,可以查詢出“表1”中的所有記錄和“表2”中匹配連接條件的記錄。
如果“表1”的某行在“表2”中沒有匹配行,那么在返回結果中,“表2”的字段值均為空值(NULL)。
【例 1】在 tb_students 表和 tb_courses 表中查詢所有學生姓名和相對應的課程名稱,包括沒有課程的學生,SQL 語句和運行結果如下。
mysql> SELECT s.name,c.course_name FROM tb_students s LEFT OUTER JOIN tb_courses c ON s.course_id=c.course_id;

可以看到,運行結果顯示了 7 條記錄。
如果出現某個學生沒有對應課程,那是因為對應的 tb_courses 表中沒有該學生的課程信息,所以該條記錄只取出了 tb_students 表中相應的值,而從 tb_courses 表中取出的值為 NULL。
右連接
右外連接又稱為右連接,右連接是左連接的反向連接。使用 RIGHT OUTER JOIN 關鍵字連接兩個表,並使用 ON 子句來設置連接條件。
右連接的語法格式如下:
SELECT <字段名> FROM <表1> RIGHT OUTER JOIN <表2> <ON子句>
語法說明如下。
- 字段名:需要查詢的字段名稱。
- <表1><表2>:需要右連接的表名。
- RIGHT OUTER JOIN:右連接中可以省略 OUTER 關鍵字,只使用關鍵字 RIGHT JOIN。
- ON 子句:用來設置右連接的連接條件,不能省略。
與左連接相反,右連接以“表2”為基表,“表1”為參考表。右連接查詢時,可以查詢出“表2”中的所有記錄和“表1”中匹配連接條件的記錄。
如果“表2”的某行在“表1”中沒有匹配行,那么在返回結果中,“表1”的字段值均為空值(NULL)。
【例 2】在 tb_students 表和 tb_courses 表中查詢所有課程,包括沒有學生的課程,SQL 語句和運行結果如下。
mysql> SELECT s.name,c.course_name FROM tb_students s RIGHT OUTER JOIN tb_courses c ON s.course_id=c.course_id;

可以看到,結果顯示了 7 條記錄。
如果某門課程沒有對應的學生,是因為對應的 tb_students 表中並沒有該學生的信息,所以該條記錄只取出了 tb_courses 表中相應的值,而從 tb_students 表中取出的值為 NULL。
多個表左/右連接時,在 ON 子句后連續使用 LEFT/RIGHT OUTER JOIN 或 LEFT/RIGHT JOIN 即可。
使用外連接查詢時,一定要分清需要查詢的結果,是需要顯示左表的全部記錄還是右表的全部記錄,然后選擇相應的左連接和右連接。
16、子查詢
通過子查詢可以實現多表查詢。子查詢指將一個查詢語句嵌套在另一個查詢語句中。
子查詢可以在 SELECT、UPDATE 和 DELETE 語句中使用,而且可以進行多層嵌套。
在實際開發時,子查詢經常出現在 WHERE 子句中。
子查詢在 WHERE 中的語法格式如下:
WHERE <表達式> <操作符> (子查詢)
其中,操作符可以是比較運算符和 IN、NOT IN、EXISTS、NOT EXISTS 等關鍵字。
(1)IN | NOT IN
當表達式與子查詢返回的結果集中的某個值相等時,返回 TRUE,否則返回 FALSE;若使用關鍵字 NOT,則返回值正好相反。
【例 1】使用子查詢在 tb_students 表和 tb_courses 表中查詢學習 Java 課程的學生姓名,SQL 語句和運行結果如下。
mysql> SELECT name FROM tb_students WHERE course_id IN (SELECT course_id FROM tb_courses WHERE course_name = 'Java');

結果顯示,學習 Java 課程的有 zhangsan和 zhaoliu%。
上述查詢過程也可以分為以下 2 步執行,實現效果是相同的。
1)首先單獨執行內查詢,查詢出 tb_course 表中課程為 Java 的 id,SQL 語句和運行結果如下。
mysql> SELECT course_id FROM tb_courses WHERE course_name = 'Java';

可以看到,符合條件的course_id 字段的值為 3。
2)然后執行外層查詢,在 tb_students 表中查詢 course_id 等於 3 的學生姓名。SQL 語句和運行結果如下。
mysql> SELECT name FROM tb_students WHERE course_id IN (3);

習慣上,外層的 SELECT 查詢稱為父查詢,圓括號中嵌入的查詢稱為子查詢(子查詢必須放在圓括號內)。
MySQL 在處理上例的 SELECT 語句時,執行流程為:先執行子查詢,再執行父查詢。
【例 2】與例 1 類似,在 SELECT 語句中使用 NOT IN 關鍵字,查詢沒有學習 Java 課程的學生姓名,SQL 語句和運行結果如下。
mysql> SELECT name FROM tb_students WHERE course_id NOT IN (SELECT course_id FROM tb_courses WHERE course_name = 'Java');

可以看出,運行結果與例 1 剛好相反,沒有學習 Java 課程的學生。
【例 3】使用=運算符,來解決例1問題,在 tb_courses 表和 tb_students 表中查詢出所有學習 Java課程的學生姓名,SQL 語句和運行結果如下。
mysql> SELECT name FROM tb_students WHERE course_id = (SELECT course_id FROM tb_courses WHERE course_name = 'Java');

結果顯示,學習 Java 課程的有 zhangsan和 zhaoliu%。結果與例1一樣。
【例 4】使用<>運算符,來解決例2問題,在 tb_courses 表和 tb_students 表中查詢出沒有學習 Java課程的學生姓名,SQL 語句和運行結果如下。
mysql> SELECT name FROM tb_students WHERE course_id <> (SELECT course_id FROM tb_courses WHERE course_name = 'Java');

可以看出,運行結果與例 3 剛好相反,沒有學習 Java課程的學生。結果與例2一樣。
(2)EXISTS | NOT EXISTS
用於判斷子查詢的結果集是否為空(是否存在),若子查詢的結果集不為空,返回 TRUE,否則返回 FALSE;若使用關鍵字 NOT,則返回的值正好相反。
【例 5】查詢 tb_courses 表中是否存在 id=1 的課程,如果存在,就查詢出 tb_students 表中的記錄,SQL 語句和運行結果如下。
mysql> SELECT * FROM tb_students WHERE EXISTS(SELECT course_name FROM tb_courses WHERE id=1);

由結果可以看到,tb_course 表中存在 id=1 的記錄,因此 EXISTS 表達式返回 TRUE,外層查詢語句接收 TRUE 之后對表 tb_students 進行查詢,返回所有的記錄。
EXISTS 關鍵字可以和其它查詢條件一起使用,條件表達式與 EXISTS 關鍵字之間用 AND 和 OR 連接。
【例 6】查詢 tb_course 表中是否存在 id=1 的課程,如果存在,就查詢出 tb_students 表中 age 字段小於19 的記錄,SQL 語句和運行結果如下。
mysql> SELECT * FROM tb_students WHERE age<19 AND EXISTS(SELECT course_name FROM tb_courses WHERE id=1);

結果顯示,從 tb_students 表中查詢出了一條記錄,這條記錄的 age 字段取值為 18。
內層查詢語句從 tb_courses 表中查詢到記錄,返回 TRUE。
外層查詢語句開始進行查詢。根據查詢條件,從 tb_students 表中查詢 age 小於 19 的記錄。
17、子查詢注意事項
在完成較復雜的數據查詢時,經常會使用到子查詢,編寫子查詢語句時,要注意如下事項。
(1)子查詢語句可以嵌套在 SQL 語句中任何表達式出現的位置
在 SELECT 語句中,子查詢可以被嵌套在 SELECT 語句的列、表和查詢條件中,即 SELECT 子句,FROM 子句、WHERE 子句、GROUP BY 子句和 HAVING 子句。
前面已經介紹了 WHERE 子句中嵌套子查詢的使用方法,下面是子查詢在 SELECT 子句和 FROM 子句中的使用語法。
嵌套在 SELECT 語句的 SELECT 子句中的子查詢語法格式如下。
SELECT (子查詢) FROM 表名;
提示:子查詢結果為單行單列,但不必指定列別名。
嵌套在 SELECT 語句的 FROM 子句中的子查詢語法格式如下。
SELECT * FROM (子查詢) AS 表的別名;
注意:必須為表指定別名。一般返回多行多列數據記錄,可以當作一張臨時表。
(2)只出現在子查詢中而沒有出現在父查詢中的表不能包含在輸出列中
多層嵌套子查詢的最終數據集只包含父查詢(即最外層的查詢)的 SELECT 子句中出現的字段,而子查詢的輸出結果通常會作為其外層子查詢數據源或用於數據判斷匹配。
常見錯誤如下:
SELECT * FROM (SELECT * FROM result);
這個子查詢語句產生語法錯誤的原因在於主查詢語句的 FROM 子句是一個子查詢語句,因此應該為子查詢結果集指定別名。正確代碼如下。
SELECT * FROM (SELECT * FROM result) AS Temp;
18、怎樣將子查詢修改為表連接
子查詢如遞歸函數一樣,有時侯能達到事半功倍的效果,但是其執行效率較低。
與表連接相比,子查詢比較靈活,方便,形式多樣,適合作為查詢的篩選條件,而表連接更適合查看多表的數據。
一般情況下,子查詢會產生笛卡兒積,表連接的效率要高於子查詢。因此在編寫 SQL 語句時應盡量使用連接查詢。
我們在前面《16、子查詢》部分介紹表連接(內連接和外連接等)都可以用子查詢替換,但反過來卻不一定,有的子查詢不能用表連接來替換。
下面我們介紹哪些子查詢的查詢命令可以改寫為表連接。
在檢查那些傾向於編寫成子查詢的查詢語句時,可以考慮將子查詢替換為表連接,看看連接的效率是不是比子查詢更好些。
同樣,如果某條使用子查詢的 SELECT 語句需要花費很長時間才能執行完畢,那么可以嘗試把它改寫為表連接,看看執行效果是否有所改善。
(1)改寫用來查詢匹配值的子查詢
下面這條示例語句包含一個子查詢,使用子查詢在 tb_students 表和 tb_courses 表中查詢學習 Java 課程的學生,SQL 語句和運行結果如下。
mysql> SELECT * FROM tb_students WHERE course_id IN (SELECT course_id FROM tb_courses WHERE course_name = 'Java');

在編寫以上語句時,可以不使用子查詢,而是把它轉換為一個簡單的連接:
mysql> SELECT tb_students.* FROM tb_students INNER JOIN tb_courses ON tb_students.course_id=tb_courses.course_id WHERE tb_courses.course_name = 'Java';

我們可以發現這些子查詢語句都遵從這樣一種形式:
SELECT * FROM table1 WHERE column1 IN (SELECT column2a FROM table2 WHERE column2b = value);
其中,column1 代表 table1 中的字段,column2a 和 column2b 代表 table2 表中的字段。這類查詢都可以被轉換為下面這種形式的連接查詢:
SELECT table1. * FROM table1 INNER JOIN table2 ON table1. column1 = table. column2a WHERE table2. column2b = value;
在某些場合,子查詢和關聯查詢可能會返回不同的結果。
比如,當 table2 包含 column2a 的多個實例時,就會發生這種情況。
這種形式的子查詢只會為每個 column2a 值生成一個實例,而連接操作會為所有值生成實例,並且其輸出會包含重復行。
如果想要防止這種重復記錄出現,就要在編寫連接查詢語句時使用 SELECT DISTINCT,而不能使用 SELECT。
(2)改寫用來查詢非匹配(缺失)值的子查詢
另一種常見的子查詢語句類型是:把存在於某個表里,但在另一個表里並不存在的那些值查找出來。“哪些值不存在”有關的問題通常都可以用 LEFT JOIN 來解決。
准備工作:創建一個記錄曠課同學的表tb_absence,並且添加一些數據。SQL 語句和運行結果如下。
mysql> CREATE TABLE tb_absence (id INT NOT NULL AUTO_INCREMENT, student_id INT NOT NULL, day DATE NOT NULL, PRIMARY KEY (id));
mysql> INSERT INTO tb_absence (student_id , day) VALUES(2, '2021-03-17');
mysql> INSERT INTO tb_absence (student_id , day) VALUES(3, '2021-04-08');
mysql> INSERT INTO tb_absence (student_id , day) VALUES(5, '2021-05-14');
mysql> INSERT INTO tb_absence (student_id , day) VALUES(2, '2021-05-14');

如下語句用來測試哪些學生沒有出現在 tb_absence 表里(用於查找全勤學生):
mysql> SELECT * FROM tb_students WHERE id NOT IN (SELECT student_id FROM tb_absence);

以上查詢語句可以使用 LEFT JOIN 來改寫:
mysql> SELECT tb_students.* FROM tb_students LEFT JOIN tb_absence ON tb_students.id = tb_absence.student_id WHERE tb_absence.student_id IS NULL;

通常情況下,如果子查詢語句符合如下所示的形式:
SELECT * FROM table1 WHERE column1 NOT IN ( SELECT column2 FROM table2) ;
那么可以把它改寫為下面這樣的連接查詢:
SELECT table1.* FROM table1 LEFT JOIN table2 ON table1.column1 = table2.column2 WHERE table2.column2 IS NULL;
這里需要假設 table2.column2 被定義成了 NOT NULL 的。
與 LEFT JOIN 相比,子查詢更加直觀。
大部分人都可以毫無困難地理解“沒被包含在...里面”的含義,因為它不是數據庫編程技術帶來的新概念。
而“左連接”有所不同,很難用自然語言直觀地描述出它的含義。
19、REGEXP:正則表達式
正則表達式主要用來查詢和替換符合某個模式(規則)的文本內容。
例如,從一個文件中提取電話號碼,查找一篇文章中重復的單詞、替換文章中的敏感語匯等,這些地方都可以使用正則表達式。
正則表達式強大且靈活,常用於非常復雜的查詢。
MySQL 中,使用 REGEXP 關鍵字指定正則表達式的字符匹配模式,其基本語法格式如下:
屬性名 REGEXP '匹配方式'
其中,“屬性名”表示需要查詢的字段名稱;“匹配方式”表示以哪種方式來匹配查詢。
“匹配方式”中有很多的模式匹配字符,它們分別表示不同的意思。下表列出了 REGEXP 操作符中常用的匹配方式。
| 選項 | 說明 | 例子 | 匹配值示例 |
|---|---|---|---|
| ^ | 匹配文本的開始字符 | '^b' 匹配以字母 b 開頭的字符串 | book、big、banana、bike |
| $ | 匹配文本的結束字符 | 'st$' 匹配以 st 結尾的字符串 | test、resist、persist |
| . | 匹配任何單個字符 | 'b.t' 匹配任何 b 和 t 之間有一個字符 | bit、bat、but、bite |
| * | 匹配零個或多個在它前面的字符 | 'f*n' 匹配字符 n 前面有任意個字符 f | fn、fan、faan、abcn |
| + | 匹配前面的字符 1 次或多次 | 'ba+' 匹配以 b 開頭,后面至少緊跟一個 a | ba、bay、bare、battle |
| <字符串> | 匹配包含指定字符的文本 | 'fa' 匹配包含‘fa’的文本 | fan、afa、faad |
| [字符集合] | 匹配字符集合中的任何一個字符 | '[xz]' 匹配 x 或者 z | dizzy、zebra、x-ray、extra |
| [^] | 匹配不在括號中的任何字符 | '[^abc]' 匹配任何不包含 a、b 或 c 的字符串 | desk、fox、f8ke |
| 字符串{n,} | 匹配前面的字符串至少 n 次 | 'b{2}' 匹配 2 個或更多的 b | bbb、bbbb、bbbbbbb |
| 字符串{n,m} | 匹配前面的字符串至少 n 次, 至多 m 次 | 'b{2,4}' 匹配最少 2 個,最多 4 個 b | bbb、bbbb |
MySQL 中的正則表達式與 Java 語言、PHP 語言等編程語言中的正則表達式基本一致。
(1)查詢以特定字符或字符串開頭的記錄
字符^用來匹配以特定字符或字符串開頭的記錄。
【例 1】在 tb_students 表中,查詢 name 字段以“w”開頭的記錄,SQL 語句和執行過程如下。
mysql> SELECT * FROM tb_students WHERE name REGEXP '^w';

【例 2】在 tb_students 表中,查詢 name 字段以“zhao”開頭的記錄,SQL 語句和執行過程如下。
mysql> SELECT * FROM tb_students WHERE name REGEXP '^zhao';

(2)查詢以特定字符或字符串結尾的記錄
字符$用來匹配以特定字符或字符串結尾的記錄。
【例 3】在 tb_students 表中,查詢 name 字段以“u”結尾的記錄,SQL 語句和執行過程如下。
mysql> SELECT * FROM tb_students WHERE name REGEXP 'u$';

【例 4】在 tb_students 表中,查詢 name 字段以“iu”結尾的記錄,SQL 語句和執行過程如下。
mysql> SELECT * FROM tb_students WHERE name REGEXP 'iu$';

(3)替代字符串中的任意一個字符
字符.用來替代字符串中的任意一個字符。
【例 5】在 tb_students 表中,查詢 name 字段值包含“i”和“i”,且兩個字母之間只有一個字母的記錄,SQL 語句和執行過程如下。
mysql> SELECT * FROM tb_students WHERE name REGEXP 'i.i';

(4)匹配多個字符
字符*和+都可以匹配多個該符號之前的字符。不同的是,+表示至少一個字符,而*可以表示 0 個字符。
【例 6】在 tb_students 表中,查詢 name 字段值包含字母“a”,且“a”后面出現字母“o”(0次、1次或多次)的記錄,SQL 語句和執行過程如下。
mysql> SELECT * FROM tb_students WHERE name REGEXP 'ao*';

【例 7】在 tb_students 表中,查詢 name 字段值包含字母“a”,且“o”后面至少出現“o”一次的記錄,SQL 語句和執行過程如下。
mysql> SELECT * FROM tb_students WHERE name REGEXP 'ao+';

(5)匹配指定字符串
正則表達式可以匹配字符串。當表中的記錄包含這個字符串時,就可以將該記錄查詢出來。
指定多個字符串時,需要用|隔開。只要匹配這些字符串中的任意一個即可。
【例 8】在 tb_students 表中,查詢 name 字段值包含字符串“an”的記錄,SQL 語句和執行過程如下。
mysql> SELECT * FROM tb_students WHERE name REGEXP 'an';

【例 9】在 tb_students 表中,查詢 name 字段值包含字符串“an”或“en”的記錄,SQL 語句和執行過程如下。
mysql> SELECT * FROM tb_students WHERE name REGEXP 'an|ao';

注意:字符串與|之間不能有空格。因為,查詢過程中,數據庫系統會將空格也當作一個字符,這樣就查詢不出想要的結果。
(6)匹配指定字符串中的任意一個
使用方括號[ ]可以將需要查詢的字符組成一個字符集合。
只要記錄中包含方括號中的任意字符,該記錄就會被查詢出來。
例如,通過“[abc]”可以查詢包含 a、b 和 c 等 3 個字母中任意一個的記錄。
【例 10】在 tb_students 表中,查詢 name 字段值包含字母“i”或“u”的記錄,SQL 語句和執行過程如下。
mysql> SELECT * FROM tb_students WHERE name REGEXP '[iu]';

從查詢結果可以看到,所有返回記錄的 name 字段值都包含字母 i 或 u,或者兩個都有。
方括號[ ]還可以指定集合的區間。
例如,“[a-z]”表示從 a~z 的所有字母;“[0-9]”表示從 0~9 的所有數字;“[a-z0-9]”表示包含所有的小寫字母和數字;“[a-zA-Z]”表示匹配所有字符。
【例 11】在 tb_students 表中,查詢 stuNo 字段值中包含數字3、4 或 5 的記錄,指定集合區間,SQL 語句和執行過程如下。
mysql> SELECT * FROM tb_students WHERE stuNo REGEXP '[3-5]';

(7)匹配指定字符以外的字符
[^字符集合]用來匹配不在指定集合中的任何字符。
【例 12】在 tb_students 表中,查詢 name 字段值包含字母 a~z 以外的字符的記錄,SQL 語句和執行過程如下。
mysql> SELECT * FROM tb_students WHERE name REGEXP '[^a-z]';

(8)使用{n,}或者{n,m}來指定字符串連續出現的次數
字符串{n,}表示字符串連續出現 n 次;字符串{n,m}表示字符串連續出現至少 n 次,最多 m 次。
例如,a{2,} 表示字母 a 連續出現至少 2 次,也可以大於 2 次;a{2,4} 表示字母 a 連續出現最少 2 次,最多不能超過 4 次。
【例 13】在 tb_students 表中,查詢 name 字段值出現字母‘a’ 至少 2 次的記錄,SQL 語句如下:
mysql> SELECT * FROM tb_students WHERE name REGEXP 'a{2,}';
【例 14】在 tb_students 表中,查詢 name 字段值出現字符串“a” 最少 1 次,最多 3 次的記錄,SQL 語句如下:
mysql> SELECT * FROM tb_students WHERE name REGEXP 'a{1,3}';

