二級MySQL數據庫程序設計(五)

課程目錄
第1章 數據庫的基本概念與設計方法
第2章 MySQL簡介
第3章 數據庫和表
第4章 表數據的基本操作
第5章 數據庫的查詢
第6章 索引
第7章 視圖
第8章 數據完整性約束與表維護語句
第9章 觸發器
第10章 事件
第11章 存儲過程與存儲函數
第12章 訪問控制與安全管理
第13章 備份與恢復
第14章 PHP和MySQL數據庫編程
第15章 開發實例

本章學習流程圖

在這裏插入圖片描述

本章學習大綱

在MySQL中,查詢操作時使用SELECT語句實現的。SELECT語句的數學理論基礎是關係模型中對錶對象的一組關係運算,即選擇、投影和連接。
在這裏插入圖片描述

5.1 SELECT語句

使用SELECT語句可以從MySQL數據中方便快捷地檢索、統計或者輸出數據。該語句的執行過程是從數據庫中選取匹配的特定行和列,並將這些數據組織成一個結果集,然後以一張臨時表的形式返回。

語法格式:

SELECT <列名1,列名2...> FROM <表名> [WHERE子句] [GROUP子句] [HAVING子句] [ORDER BY子句] [LIMIT子句]

語法說明:

  • <表名>:要進行查詢的表的名稱。
  • <列名1,列名2…>:用於指定需要查詢的字段名。
  • FROM子句、WHERE子句、HAVING子句、ORDER BY子句、LIMIT子句:均爲可選項。這些子句必須按照SELECT語句的語法格式羅列的順序來使用。例如,WHERE子句必須位於GROUP子句之前,GROUP子句必須位於HAVING子句之前。

5.2 列的選擇和指定

由SELECT語句語法可知,最簡單的SELECT語句形式是“SELECT select_expr”。使用這種SELECT語句可以進行MYSQL所支持的任何運算。例如,執行語句“SELECT 1+4-2”,系統會返回3。

【例5-1】在MySQL數據庫中執行“SELECT 1+4-2”運算。

mysql> select 1+4-2;
+-------+
| 1+4-2 |
+-------+
|     3 |
+-------+
1 row in set (0.00 sec)

選擇指定的列
數據查詢時,可以選擇一個或多個表的某個或某些列作爲SELECT語句的查詢列。如果有多個列,則各個列用逗號分隔開,且返回結果集時,各列的次序是按照SELECT語句中指定的次序給出。若要查詢一個表中的所有列,則直接用(*)通配符即可,不必列出所有的列名。另外,列名的指定可以採用直接給出列名的方式,也可以使用完全限定的列名方式,即“tbl_name.col_name”的列名格式。

注意:使用(*)可以返回所有列的數值,但是如果不需要返回所有列值的時候,爲了提高效率,一般採用SELECT字段名列表的形式。

【例5-2】查詢數據庫 my_test 中表 students 中學生的姓名、年齡和專業信息。

mysql> select student_name,student_age,student_major
    -> from my_test.students;
+--------------+-------------+---------------+
| student_name | student_age | student_major |
+--------------+-------------+---------------+
| 李明         |          22 | 數學專業      |
| 張三         |          24 | 化學專業      |
| 王五         |          23 | 數學專業      |
| 趙柳         |          23 | 物理專業      |
+--------------+-------------+---------------+
4 rows in set (0.00 sec)

語句執行後,會返回一個原始的,無格式的數據集。

【例5-3】查詢數據庫 my_test 中表 students 學生所有信息。

mysql> select * from students;
+------------+--------------+-------------+-------------+---------------+-----------------+
| student_id | student_name | student_sex | student_age | student_major | student_contact |
+------------+--------------+-------------+-------------+---------------+-----------------+
|       1321 | 李明         | 1           |          22 | 數學專業      | NULL            |
|       1322 | 張三         | 1           |          24 | 化學專業      | 139xxxxxxxx     |
|       1323 | 王五         | 1           |          23 | 數學專業      | NULL            |
|       1324 | 趙柳         | 1           |          23 | 物理專業      | NULL            |
+------------+--------------+-------------+-------------+---------------+-----------------+
4 rows in set (0.34 sec)

語句執行後,返回表students的所有記錄。

定義並使用列的別名

在系統輸出查詢結果集中某些列或所有列名稱時,如果希望這些列的名稱顯示爲自定義列名,而非原表的列名,則可以在SELECT語句添加AS子句,用於修改查詢結果集中的別名。

別名:數據庫對象正式的或規範的名稱以外的名稱。

語法格式:

<列名>[AS]<列名>

【例5-4】查詢數據庫 my_test 中表 students 的 student_name 和 student_contact 字段,並且要求 student_contact 列用“聯繫方式”來顯示。

mysql> select student_name,student_contact as '聯繫方式' from my_test.students;
+--------------+-------------+
| student_name | 聯繫方式    |
+--------------+-------------+
| 李明         | NULL        |
| 張三         | 139xxxxxxxx |
| 王五         | NULL        |
| 趙柳         | NULL        |
+--------------+-------------+
4 rows in set (0.00 sec)

如果要將 student_name 替換成 “姓名”,代碼如下:

mysql> select student_name as '姓名',student_contact as '聯繫方式' from my_test.students;
+------+-------------+
| 姓名 | 聯繫方式    |
+------+-------------+
| 李明 | NULL        |
| 張三 | 139xxxxxxxx |
| 王五 | NULL        |
| 趙柳 | NULL        |
+------+-------------+
4 rows in set (0.00 sec)

注意:列別名不允許出現在WHERE子句中。

計算列值
使用SELECT語句對列進行查詢時,可以對列進行計算,在結果集中輸出計算結果。

【例5-5】查詢數據庫 my_test 中表 students,輸出每個學生的 student_name 和 student_id 列,同時要求輸出 student_id 加上數字100後構成新列的值。

mysql> select student_name,student_id,student_id+100 from my_test.students;
+--------------+------------+----------------+
| student_name | student_id | student_id+100 |
+--------------+------------+----------------+
| 李明         |       1321 |           1421 |
| 張三         |       1322 |           1422 |
| 王五         |       1323 |           1423 |
| 趙柳         |       1324 |           1424 |
+--------------+------------+----------------+
4 rows in set (0.00 sec)

新列 student_id+100 是列 student_id 的數值加100後的結果。

替換查詢結果集中的數據
在對錶進行查詢時,如果希望得到某些列的分析結果,而不僅僅是查詢到的原始值,則可以在SELECT語句中替換這些列。這裏可以使用CASE表達式。

語法格式:

CASE
    WHEN 條件1 THEN 表達式1
    WHEN 條件2 THEN 表達式2
    ...
    ELSE 表達式 
END[AS<列表名>]

【例5-6】查詢數據庫 my_test 中表 students,輸出 student_name 和 student_sex 列,判斷 student_sex,如果爲0,則顯示“男”,否則顯示“女”,並在結果集中用“性別”來標註該列。

mysql> select student_name,
    -> case
    -> when student_sex='0'then'男'
    -> else'女'
    -> end as'性別'
    -> from my_test.students;
+--------------+------+
| student_name | 性別 |
+--------------+------+
| 李明         ||
| 張三         ||
| 王五         ||
| 趙柳         ||
+--------------+------+
4 rows in set (0.00 sec)

聚合函數
SELECT語句可以指定爲聚合函數。聚合函數是MySQL系統內置函數。常用語對一組值進行計算,然後返回單個值。

聚合函數通常與GROUP BY子句一起使用,如果SELECT語句中有一個GROUP BY子句,則聚合函數對所有列起作用;如果沒有,則SELECT語句只產生一行作爲結果。注意,除COUNT( )函數外,聚合函數都會忽略空值。表5-1列出了MySQL中常用的聚合函數。

聚合函數:MySQL的內置函數,常常用於對一組值進行計算或者統計,然後返回計算或者統計結果。

表5-1 MySQL中常用的聚合函數

函數名 說明
COUNT 求組中項數,返回INT整數類型
MAX 求最大值
MIN 求最小值
SUM 求所有值的和
AVG 求平均值
STD或STDDEV 求所有值的標準值
VARIANCE 求所有值的方差
CROUP_CONCAT 求屬於一組的列值連接而成的結果
BIT_AND 邏輯與
BIT_OR 邏輯或
BIT_XOR 邏輯異或

例如,查詢表students,輸出年齡最大值。
這是,在MySQL命令行客戶端輸入:select max (student_age) from students 即可。聚合函數通常與group by子句結合使用。

5.3 FROM子句與連接表

前面講的內容都是SELECT語句查詢列的選擇與指定方法,下面討論SELECT語句中查詢對象(數據源)的構成形式。

FROM子句
SELECT語句查詢對象是由FROM子句指定的。

語法格式:

FROM <表名>

語法說明:
<表名>:指定要查詢的表名。與列別名一樣,可以使用AS關鍵字爲表格指定別名。表別名主要用於相關子查詢或者鏈接查詢。如果在FROM子句中指定了表別名,那麼它所在的SELECT語句中其他句子都必須使用表別名代替原始表名。其中,<表名>可以使用單表的名稱,也可以使用聯合表。當同一個表在SELECT語句中被多次引用時,必須使用表別名加以區分。

連接表
在關係數據庫設計中,爲了減少數據的冗餘,並增強數據庫的穩定性和靈活性,通常會基於關係規範化原則將物理世界中的數據信息分解成多個表,實現一類數據一個表,在表與表之間通過設置“鍵”(如主鍵、外鍵)的方式來保持多表之間的關聯關係。
相反,在關係數據庫存的應用中,可通過對錶對象的連接(join)運算,實現數據庫中數據信息的組合。這種分解與組合數據的方法,是的數據庫系統能夠更有效地存儲數據,更方便地處理數據,獲得更大的可伸縮性。
注意:連接查詢的類型和具體使用方法,是考試重點內容。

(1)交叉連接
交叉連接又被稱爲笛卡爾積,返回連接表中所有數據行的笛卡爾積,其結果集合中的數據行數等於第一個表中符合查詢條件的數據行數乘以第二個表中符合查詢條件的數據行數。在FROM子句中使用關鍵字CROSS JOIN連接兩張表,用於實現一張表的每一行與另一張表的每一行的笛卡爾積,返回兩張表的每一行相乘的所有可能的搭配結果。

【例5-7】假設數據庫中有2張表,分別是a和b,要求查詢這2張表的交叉連接後的結果集。
首先查看a表中的數據:

mysql> select * from a;
+------+------+
| Id   | name |
+------+------+
|    1 | a1   |
|    2 | a2   |
+------+------+
2 rows in set (0.00 sec)

接着查看b表中的數據:

mysql> select * from b;
+------+------+
| Id   | name |
+------+------+
|    1 | b1   |
|    2 | b2   |
|    3 | b3   |
+------+------+
3 rows in set (0.00 sec)

計算a表和b表交叉連接的結果:

mysql> select * from a cross join b;
+------+------+------+------+
| Id   | name | Id   | name |
+------+------+------+------+
|    1 | a1   |    1 | b1   |
|    2 | a2   |    1 | b1   |
|    1 | a1   |    2 | b2   |
|    2 | a2   |    2 | b2   |
|    1 | a1   |    3 | b3   |
|    2 | a2   |    3 | b3   |
+------+------+------+------+
6 rows in set (0.00 sec)

從上面的結果可以看出,交叉連接返回的結果集的記錄行數是兩張表的記錄行數相乘。若a表記錄行數爲100條,b表記錄行數爲200條,則a表和b表交叉連接返回的是100×200=20000條。因此倘若關聯的兩張表的記錄數很多,交叉連接的結果集會非常龐大,所以**對於存在大量數據的表,應該避免使用交叉連接。**也可以通過添加WHERE子句設置判斷條件,來過濾返回的結果集。

(2)內連接
內連接是通過在查詢中設置條件的方式,來移除查詢結果集中某些數據行後的交叉連接。簡單來說,就是利用條件表達式來消除交叉連結的某些數據行,在FROM字句中使用關鍵字INNER JOIN連接兩張表,並使用ON子句來設置連接條件。如果沒有任何條件的話,INNER JOINCROSS JOIN在語法上是等同的,兩者可以互換。

語法格式:

SELECT <列名1,列名2...> FROM <表名1> INNER JOIN <表名2> [on子句]

語法說明:

  • <列名1,列名2…>:需要檢索的列名。
  • <表名1><表名2>:進行內連接的兩張表表名。

內連接是系統默認的表連接,所以在FROM子句後可以省略INNER關鍵字,只用關鍵字JOIN。使用內連接後,FROM子句中的ON子句可用來設置連接表的條件。在FROM子句中可以在多個表之間連續使用INNER JOINJOIN,如此可以同時實現多個表的內連接。

【例5-8】在例5-7的表中,利用內連接查詢出 a 表 Id 大於 b 表 Id 的結果集。

mysql> select * from a inner join b on a.Id>b.Id;
+------+------+------+------+
| Id   | name | Id   | name |
+------+------+------+------+
|    2 | a2   |    1 | b1   |
+------+------+------+------+
1 row in set (0.00 sec)

在內連接語句中使用ON關鍵字設置條件。

(3)相等連接
相等連接是內連接的一種,用於關聯具有一對一關係的兩張表,即進行相等性測試的內連接。它實質上是內連接的一種特殊情況,在FROM子句中用INNER JOIN或者JOIN關鍵字來進行連接,在ON子句的連接條件中使用運算符“=”,通常這樣的條件會包含一個主鍵和一個外鍵。

【例5-9】在例5-7的表中,利用內連接查詢出 a 表 Id 等於 b 表 Id 的結果集。

mysql> select * from a inner join b on a.Id=b.Id;
+------+------+------+------+
| Id   | name | Id   | name |
+------+------+------+------+
|    1 | a1   |    1 | b1   |
|    2 | a2   |    2 | b2   |
+------+------+------+------+
2 rows in set (0.00 sec)

(4)不等連接
不等連接也是內連接的一種,與相等連接相對應,即進行不相等性測試的內連接。也是用INNER JOIN或者JOIN關鍵字來連接兩張表,只是在ON子句中的連接條件使用除“=”的其他運算符。

(5)自連接
自連接是將一個表和它自身進行連接。它也是內連接的一種,同樣是使用INNER JOIN或者JOIN關鍵字來進行連接。如果需要在一個表中查找具有相同列值的行,則可以考慮用自連接。注意,在使用自連接的時候,需要爲表指定兩個不同的列名,且對所有查詢列的引用必須使用表別名限定,否則SELECT操作會失敗。

(6)自然連接
自然連接只有在連接的列在兩張表中的名稱都相同時纔會有用,否則返回的是笛卡爾積。自然連接在FROM子句中使用關鍵字NATURAL JOIN

(7)外連接
內連接是在交叉連接的記過集上返回滿足條件的記錄;而外連接首先將連接的表分爲基表和參考表,然後再以基表爲依據返回滿足和不滿足條件的記錄。
外連接更加註重兩張表之間的關係。按照連接表的順序,可以分爲左外連接和右外連接。

①左外連接
左外連接又稱爲左連接。它在FROM子句中使用關鍵字LEFT OUTER JOIN或者LEFT JOIN,用於接收該關鍵字左表(基表)的所有行,並用這些行與該關鍵字右表(參考表)中的行進行匹配,即匹配左表中的每一行及右表中符合條件的行。在左外連接的結果集中除了匹配的行之外,還包括左表中有但在右表中不匹配的行,對於這樣的行,從右表中被選擇的列的值被設置爲NULL,即左邊連接的結果集中在NULL值表示右表中沒有找到與左表相符的記錄。

②右外連接
右外連接也稱爲右連接。它在FROM子句中使用RIGHT OUTER ON或者RIGHT JOIN。與左外連接相反,右外連接是以右表爲基表,連接方法和左外連接相同。在右外連接結果集中除了匹配的行,還包括由表中有但是左表中不匹配的行,這樣的行,從左表被選擇的值被設置爲NULL。

5.4 WHERE子句

在SELECT語句中,可以使用WHERE子句來指定查詢條件,從FROM子句的中間結果中選取適當的數據行,達到數據過濾的效果。

語法格式:

WHERE<查詢條件>{<判定運算>1<判定運算>2...}

語法說明:

<判定運算>:判定運算,其結果取值爲TRUE、FALSE和UNKNOWN。<判定結果>語法分類如下:

<表達式1>:{= | < | <= | > | >= | <=> | <>|!= } <表達式2>
<表達式1> [NOT] LIKE <表達式2>
<表達式1> [NOt] [REGEXP | RELIKE] <表達式2>
<表達式1> [NOT] BETWEEN <表達式2> AND <表達式3>
<表達式> IS [NOT] TRUE

下面對條件<判定運算>進行解釋:

比較運算
語法格式:

<表達式1> {= | < | <= | > | >= | <=> | !=} <表達式2>

MySQL支持的比較運算符見表5-2

表5-2 比較運算符

比較運算符 說明
= 等於
< 小於
<= 小於等於
> 大於
>= 大於等於
<=> 不會返回UNKNOWN
<> 不等於
!= 不等於

比較運算用於比較兩個表達式的值。當兩個表達式中有一個值爲空值或者都爲空值時,將返回UNKNOWN。對於運算符“<=>”,當兩個表達式彼此相等或都等於空值時,比較的結果值爲TRUE;若其中一個是空值或者都是非空值但卻不相等時,則爲FALSE,不會出現UNKNOWN的情況。

【例5-10】查找數據庫 my_test 的表 students,輸出所有女生的信息。

mysql> select * from my_test.students where student_sex = '1';
+------------+--------------+-------------+-------------+---------------+-----------------+
| student_id | student_name | student_sex | student_age | student_major | student_contact |
+------------+--------------+-------------+-------------+---------------+-----------------+
|       1321 | 李明         | 1           |          22 | 數學專業      | NULL            |
|       1322 | 張三         | 1           |          24 | 化學專業      | 139xxxxxxxx     |
|       1323 | 王五         | 1           |          23 | 數學專業      | NULL            |
|       1324 | 趙柳         | 1           |          23 | 物理專業      | NULL            |
+------------+--------------+-------------+-------------+---------------+-----------------+
4 rows in set (0.00 sec)

字符串匹配

語法格式:

<表達式1> [NOT] LIKE <表達式2>

字符串匹配是一種模式匹配,使用運算符LIKE設置過濾條件,過濾條件使用通用匹配符進行匹配運算,而不是判斷是否相等進行比較。相互間進行匹配運算的對象可以是CHAR,VARCHAR,TEXT,DATETIME等數據類型。運算返回的結果是TRUE或者FALSE。

利用通配符可以在不完全確定比較值的情形下,創建一個比較特定數據的搜索模式,並置於關鍵字LIKE之後。可以在搜索模式中任意位置使用通配符,並且可以使用多個通配符。MySQL支持的通配符有以下兩種:

(1)百分號
可以表示任何字符串,並且可以出現任意次數。

【例5-11】查找數據庫 my_test 的表 students,輸出所有姓“李”的學生id和姓名。
在做這道題之前,我就往庫里加了幾個學生的信息,然後我們輸入代碼:

mysql> select * from students;
+------------+--------------+-------------+-------------+---------------+-----------------+
| student_id | student_name | student_sex | student_age | student_major | student_contact |
+------------+--------------+-------------+-------------+---------------+-----------------+
|       1321 | 李明         | 1           |          22 | 數學專業      | NULL            |
|       1322 | 張三         | 1           |          24 | 化學專業      | 139xxxxxxxx     |
|       1323 | 王五         | 1           |          23 | 數學專業      | NULL            |
|       1324 | 趙柳         | 1           |          23 | 物理專業      | NULL            |
|       1325 | 李曉麗       | 1           |          22 | 英語專業      | 13799876543     |
|       1326 | 李玩         | 0           |          26 | 體育專業      | 13466543889     |
|       1327 | 馬丁令       | 0           |          24 | 化學專業      | 13876544678     |
|       1328 | 王槓鈴       | 0           |          22 | 體育專業      | 15877890990     |
+------------+--------------+-------------+-------------+---------------+-----------------+
8 rows in set (0.00 sec)

mysql> select student_id,student_name from students
    -> where student_name like '李%';
+------------+--------------+
| student_id | student_name |
+------------+--------------+
|       1321 | 李明         |
|       1325 | 李曉麗       |
|       1326 | 李玩         |
+------------+--------------+
3 rows in set (0.34 sec)

注意事項:

  • MySQL默認是不區分大小寫的,如果要區分大小寫,則需要更換字符集的校對規則。
  • 百分號不匹配空值NULL
  • 百分號可以代表搜索模式中給定位置的0個、1個或多個字符。
  • 尾空格可能會干擾通配符的匹配,一般可以在搜索模式的最後附加一個百分號。

(2)下劃線
下劃線通配符和百分號通配符用途一樣,下劃線只匹配單個字符,而不是多個字符,也不是0個字符。

【例5-12】查找數據庫 my_test 的表 students,輸出所有姓“李”並且姓名只有兩個中文字符的學生id和姓名。

mysql> select student_id,student_name from students
    -> where student_name like '李_';
+------------+--------------+
| student_id | student_name |
+------------+--------------+
|       1321 | 李明         |
|       1326 | 李玩         |
+------------+--------------+
2 rows in set (0.00 sec)

注意:不要過度使用通配符,對通配符檢索的處理一般會比其他檢索方式花費更長時間。

文本匹配
文本匹配也是一種模式匹配,使用正則表達式進行文本串的匹配,滿足一些複雜過濾條件的要求。正則表達式是用來匹配文本的特殊串或字符集合,是文本匹配運算中的一種搜索模式。正則表達式需要使用正則表達式語句來建立。MySQL允許使用REGEXP指定正則表達式過濾SELECT語句查詢的數據。

WHERE子句中使用正則表達式進行文本匹配的語法格式:

<表達式1>[NOT][REGEXP|RLIKE]<表達式2>

其中,RLIKE是REGEXP的同義詞。在不使用數據庫表的情況下,將用於文本匹配的語法置於SELECT關鍵字之後,進行簡單的正則表達式測試。如果返回1,則表示匹配成功,如果返回0,則表示沒有匹配。

(1)基本字符匹配
使用正則表達式可以匹配任意一個字符,進行基本字符的匹配索引。

【例5-13】查找數據庫 my_test 的表 students,分別使用字符串匹配和文本匹配的方式,輸出專業含有。
我們先查看一下數據庫中 students 表的信息:

mysql> select * from students;
+------------+--------------+-------------+-------------+---------------+-----------------+
| student_id | student_name | student_sex | student_age | student_major | student_contact |
+------------+--------------+-------------+-------------+---------------+-----------------+
|       1321 | 李明         | 1           |          22 | 數學專業      | NULL            |
|       1322 | 張三         | 1           |          24 | 化學專業      | 139xxxxxxxx     |
|       1323 | 王五         | 1           |          23 | 數學專業      | NULL            |
|       1324 | 趙柳         | 1           |          23 | 物理專業      | NULL            |
|       1325 | 李曉麗       | 1           |          22 | 英語專業      | 13799876543     |
|       1326 | 李玩         | 0           |          26 | 體育專業      | 13466543889     |
|       1327 | 馬丁令       | 0           |          24 | 化學專業      | 13876544678     |
|       1328 | 王槓鈴       | 0           |          22 | 體育專業      | 15877890990     |
|       1329 | 周明明       | 0           |          23 | 中文專業      | 13477890009     |
|       1330 | 王小胖       | 0           |          25 | 數學專業      | NULL            |
|       1331 | 張玲玲       | 1           |          25 | 英語專業      | 13455909877     |
|       1332 | 馮曉華       | 1           |          24 | 物理專業      | 15899900009     |
+------------+--------------+-------------+-------------+---------------+-----------------+
12 rows in set (0.00 sec)

①直接匹配

mysql> select student_name,student_age,student_major from students where student_major like'物';
Empty set (0.00 sec)

沒有查到匹配的行。

②採用百分號匹配

mysql> select student_name,student_age,student_major from students where student_major like'%物%';
+--------------+-------------+---------------+
| student_name | student_age | student_major |
+--------------+-------------+---------------+
| 趙六         |          23 | 物理專業      |
| 馬丁令       |          24 | 生物專業      |
| 馮曉華       |          24 | 物理專業      |
+--------------+-------------+---------------+
3 rows in set (0.00 sec)

③採用正則表達式REGEXP匹配

mysql> select student_name,student_age,student_major from students where student_major regexp '物';
+--------------+-------------+---------------+
| student_name | student_age | student_major |
+--------------+-------------+---------------+
| 趙六         |          23 | 物理專業      |
| 馬丁令       |          24 | 生物專業      |
| 馮曉華       |          24 | 物理專業      |
+--------------+-------------+---------------+
3 rows in set (0.40 sec)

mysql> select student_name,student_age,student_major from students where student_major rlike '物';
+--------------+-------------+---------------+
| student_name | student_age | student_major |
+--------------+-------------+---------------+
| 趙六         |          23 | 物理專業      |
| 馬丁令       |          24 | 生物專業      |
| 馮曉華       |          24 | 物理專業      |
+--------------+-------------+---------------+
3 rows in set (0.00 sec)

關鍵字LIKE和REGEXP存在一個重要區別。LIKE用於匹配整個列,如果不適用通配符,LIKE會嚴格按照單引號之間的內容查詢,例如LIKE‘物’,那麼僅僅會返回列值爲‘物’的記錄行,而‘物理’這樣的值不會被返回。而REGEXP在列值內進行匹配,被匹配的文本在列值中出現,REGEXP將會找到它,比如只要列值中含有‘物’的相應行就會被返回。

(2)選擇匹配
正則表達式還可以達到待搜索對象的選擇性匹配,即使用“|”分隔符提供選擇匹配的字符串,該分隔符類似於在SELECT語句中使用OR子句。多個OR條件可以併入單個正則表達式。

【例5-14】查找數據庫 my_test 的表 students,輸出含有“自動化專業”或者“數學專業”的學生姓名。

mysql> select student_name,student_major from students
    -> where student_major regexp '自動化專業|數學專業';
+--------------+---------------+
| student_name | student_major |
+--------------+---------------+
| 李明         | 數學專業      |
| 王五         | 數學專業      |
| 王小胖       | 數學專業      |
| 王青青       | 自動化專業    |
+--------------+---------------+
4 rows in set (0.00 sec)

(3)範圍匹配
正則表達式還可以在某一個範圍裏對數據進行過濾。使用“[ ]”包含字符或數字集合,用於在這個集合範圍內查找某個匹配字符或數字。例如“[1-9]”表示列值在1到9之間的記錄。

【例5-15】查找數據庫 my_test 的表 students,輸出年齡中有4或5的學生姓名和年齡。

mysql> select student_name,student_age from students
    -> where student_age regexp '[4-5]';
+--------------+-------------+
| student_name | student_age |
+--------------+-------------+
| 張三         |          24 |
| 馬丁令       |          24 |
| 王小胖       |          25 |
| 張玲玲       |          25 |
| 馮曉華       |          24 |
+--------------+-------------+
5 rows in set (0.00 sec)

(4)特殊字符匹配
正則表達式語言是由一些具有特殊含義的字符組成的,如“|”、“[ ]”以及“_”等。如果要在列值中查找具有這些特殊含義的字符的時候,需要用到轉義符“\\”。具體方法是在這些特殊字符前使用“\\”作爲前導,例如,正則表達式中如果出現“\\_”,則表示查找字符“_”,而爲了查找匹配反斜槓“\”字符本身,則需要在正則表達式中使用“\\”。
另外,“\\”也可以用來引用空白元字符(即含有特殊含義的字符)。例如“\\f”表示換頁,“\\n”表示換行,“\\r”表示回車,“\\t”表示製表,“\\v”表示縱向製表。

(5)重複匹配
正則表達式支持重複元素匹配。即用某些字符來表示要匹配的元素重複的次數。表5-3列出了這些重複元字符。

表5-3 重複元字符

元字符 說明
* 0個或多個匹配
+ 1個或多個匹配
? 0個或1個匹配
{n} 指定n個匹配
{n,} 不少於n個匹配
{n,m} 匹配的數目在n和m之間(m不可超過255)

【例5-16】查找數據庫 my_test 的表 students,輸出學生名字含有兩個“明”的學生的姓名、年齡和專業。

mysql> select student_name,student_age,student_major from students
    -> where student_name regexp '[明]{2}';
+--------------+-------------+---------------+
| student_name | student_age | student_major |
+--------------+-------------+---------------+
| 周明明       |          23 | 中文專業      |
+--------------+-------------+---------------+
1 row in set (0.00 sec)

(6)字符類匹配
爲更方便地查找,可以將經常使用的數字、字符等定義成一個預定義的字符集,然後在正則表達式中直接使用。例如,字符類“[:upper:]”表示任意大寫字母,如同在正則表達式中使用“[A-Z]”。

(7)使用定位符匹配
爲了匹配處於特定位置的文本,可以在正則表達式中使用定位符,這些定位符見表5-4。

表5-4 定位符

定位符 說 明
^ 文本開始
$ 文本結尾
[[:<:]] 詞的開始
[[:>:]] 詞的結尾

【例5-17】查找數據庫 my_test 的表 students,輸出“生”字開頭的專業名稱的學生姓名和專業。

mysql> select student_name,student_major from students
    -> where student_major regexp '生';
+--------------+---------------+
| student_name | student_major |
+--------------+---------------+
| 馬丁令       | 生物專業      |
+--------------+---------------+
1 row in set (0.00 sec)

注意:MySQL的正則表達式,符號“^”有兩種用法:在“[ ]”用來表示否定該集合;而作爲定位符時,表示該字符串的開始。

判定範圍
在WHERE子句中,用於表示範圍的關鍵字有BETWEEN和IN兩個。

(1)BETWEEN…AND
當查詢的過濾條件被限定在某個範圍時,可以使用BETWEEN關鍵字。

語法格式:

<表達式1> [NOT] BETWEEN <表達式2> AND <表達式3>

當查詢的過濾條件被限定在某個範圍時,可以使用BETWEEN關鍵字。
其中<表達式2>的值不能大於<表達式3>的值。如果不使用NOT關鍵字,當<表達式1>的值在<表達式2>和<表達式3>值之間的時候,返回TRUE,否則返回FALSE。使用NOT關鍵字則返回值相反。

【例5-18】查找數據庫 my_test 的表 students,輸出年齡在20到23歲之間的學生姓名、專業。

mysql> select student_name,student_major from students
    -> where student_age between 20 and 23;
+--------------+---------------+
| student_name | student_major |
+--------------+---------------+
| 李明         | 數學專業      |
| 王五         | 數學專業      |
| 趙六         | 物理專業      |
| 李曉麗       | 英語專業      |
| 王槓鈴       | 體育專業      |
| 周明明       | 中文專業      |
| 張大慶       | 地質專業      |
| 王青青       | 自動化專業    |
+--------------+---------------+
8 rows in set (0.00 sec)

(2)IN
該關鍵字可以指定一個值的枚舉表,該表會列出所有可能的值。

語法格式:

<表達式1> IN ( <表達式2> [,...n] )

要判定的值與該表中的任意一個值匹配,則返回TRUE,否則返回FALSE。儘管關鍵字IN可用於範圍判定,但其主要作用是表達式子查詢。

【例5-19】查找數據庫 my_test 的表 students,輸出年齡在23到24歲之間的學生姓名和年齡。

mysql> select student_name,student_age from students
    -> where student_age in (23,24);
+--------------+-------------+
| student_name | student_age |
+--------------+-------------+
| 張三         |          24 |
| 王五         |          23 |
| 趙六         |          23 |
| 馬丁令       |          24 |
| 周明明       |          23 |
| 馮曉華       |          24 |
| 張大慶       |          23 |
| 王青青       |          23 |
+--------------+-------------+
8 rows in set (0.00 sec)

判定空值
關鍵字 IS NULL 可以用來盤點一個表達式的值是否爲空值。

語法格式:

<表達式> IS <NOT> NULL

其中,不適用關鍵字NOT時,<表達式>的值爲空值,則返回TRUE,否則返回FALSE;使用關鍵字NOT時,則相反。

【例5-20】查找數據庫 my_test 的表 students,輸出聯繫方式爲空學生姓名。

mysql> select student_name,student_contact from students
    -> where student_contact is null;
+--------------+-----------------+
| student_name | student_contact |
+--------------+-----------------+
| 李明         | NULL            |
| 王五         | NULL            |
| 趙六         | NULL            |
| 王小胖       | NULL            |
+--------------+-----------------+
4 rows in set (0.00 sec)

子查詢
在MySQL中,允許使用SELECT語句創建子查詢,即嵌套在其他SELECT查詢中的查詢。子查詢有以下4類:

  • 表子查詢:返回結果集是一個表。
  • 行子查詢:返回結果集時帶有一個或多個值的一行數據。
  • 列子查詢:返回結果集時一列數據,該列可以有一行或多行,但每行只有一個值。
  • 標量子查詢:返回結果集僅僅是一個值。

(1)IN 子查詢
結合關鍵字IN所使用的子查詢主要用於判斷一個給定值是否存在於查詢的結果集中。

語法格式:

<表達式> [NOT] IN <子查詢>

語法說明:

  • <表達式>:用於指定表達式。當<表達式>與子查詢返回的結果集中的某個值相等時,返回TRUE,否則返回FALSE;若使用關鍵字NOT,則返回的值正好相反。
  • <子查詢>:用於指定子查詢。這裏的子查詢只能返回一列數據。對於比較複雜的查詢要求,可以使用SELECT語句實現子查詢的多層嵌套。

(2)比較運算符子查詢
主要用於將表達式的值和子查詢返回的值進行比較運算。

語法格式:

<表達式> { = | < | <= | > | >= | <=> | != } {ALL | SOME | ANY} <子查詢>

語法說明:

  • <子查詢>:用於指定子查詢。
  • <表達式>:用於指定要進行比較的表達式。
  • ALL、SOME 和 ANY:可選項。用於指定對比較運算的限制。其中關鍵字ALL用於指定表達式需要與子查詢結果集中的每個值都進行比較,當表達式與每個值都滿足比較關係時,會返回TRUE,否則返回FALSE;關鍵字SOME和ANY是同義詞,表示表達式只要與子查詢結果集中的某個值滿足關係時,就返回TRUE,否則返回FALSE。

(3)EXIST子查詢
關鍵字EXIST所使用的子查詢主要用於判斷子查詢的結果集是否爲空。

語法格式:

EXIST <子查詢>

如果子查詢的結果集不能爲空,則返回TRUE,否則返回FALSE。

5.5 GROUP BY子句與分組數據

在SELECT語句中,允許使用GROUP BY子句,將結果集中的數據行根據選擇列的值進行邏輯分組,一遍能彙總表內容的子集,實現對每個組的聚集計算,這時對每個組而不是對整個結果集進行聚合。

語法格式:

GROUP BY {<列名> | <表達式> | <位置>}[ASC | DESC]

語法說明:

  • <列名>:指定用於分組的列。可以指定多個列,彼此間用逗號分隔。注意:GROUP BY子句中的各選項列必須也是SELECT語句的選擇列清單中的一項。
  • <表達式>:指定用於分組的表達式。通常與聚合函數一起使用,例如,可將表達式COUNT (*) AS'人數'作爲SELECT選擇列表清單中的一項。
  • <位置>:指定用於分組的選擇列在SELECT語句結果集中的位置,通常是一個正整數。例如GROUP BY 2表示根據SELECT語句列清單上的第2列的值進行邏輯分組。
  • ASC | DESC:關鍵字ASC表示按升序分組,關鍵字DESC表示按降序分組,其中ASC爲默認值,注意這兩個關鍵字必須位於對應的列名、表達式、列的位置之後。

【例5-21】查找數據庫 my_test 的表 students 中獲取一個數據結果集,要求該結果集以性別分組,並且統計男生和女生的人數。

mysql> select student_sex,count(*) as '人數'
    -> from students
    -> group by student_sex;
+-------------+------+
| student_sex | 人數 |
+-------------+------+
| 0           |    8 |
| 1           |    6 |
+-------------+------+
2 rows in set (0.38 sec)

從例子中可以看出,GROUP BY對性別進行分組,使用聚合函數count統計學生的人數。GROUP BY也可以結合使用其他聚合函數。

【例5-22】查找數據庫 my_test 的表 students,要求輸出每個專業學生的平均年齡和專業名稱。

mysql> select student_major,avg(student_age) as '平均年齡' from students group by student_major;
+---------------+----------+
| student_major | 平均年齡 |
+---------------+----------+
| 數學專業      |  23.3333 |
| 化學專業      |  24.0000 |
| 物理專業      |  23.5000 |
| 英語專業      |  23.5000 |
| 體育專業      |  24.0000 |
| 生物專業      |  24.0000 |
| 中文專業      |  23.0000 |
| 地質專業      |  23.0000 |
| 自動化專業    |  23.0000 |
+---------------+----------+
9 rows in set (0.12 sec)

使用GROUP BY需要注意以下幾點:

  • GROUP BY子句可以包含任意數目的列,是的其可以對分組進行嵌套,爲數據分組提供更加細緻的控制。
  • GROUP BY子句中列出的每個列都必須是檢索列或有效的表達式,但不能是聚合函數。如果在SELECT語句中使用表達式,則必須在GROUP BY子句中指定相同的表達式。注意,不能使用別名。
  • 除聚合函數之外,SELECT語句中的每個列都必須在GROUP BY子句中給出。
  • 如果用於分組的列中包含有NULL值,則NULL將作爲一個單獨的分組返回;如果該列中存在多個NULL值,則將這些NULL值所在的行分爲一組。

5.6 HAVING子句

在SELECT語句中,除了能使用GROUP BY子句分組數據還可以使用HAVING子句過濾,在結果集中規定包含哪些分組和排除哪些分組。

語法格式:

HAVING <條件>

語法說明:
<條件>:指定過濾條件。
HAVING子句和WHERE子句非常相似,HAVING子句支持WHERE子句中所有的操作符合語法,但是兩者存在幾點差異。

  • WHRER子句主要用於過濾數據行,而HAVING子句主要用於過濾分組,即HAVING子句基於分組的聚合值而不是特定行的值來過濾數據,主要用來過濾分組。
  • WHERE子句不可以包含聚合函數,HAVING子句中的條件可以包含聚合函數。
  • HAVING子句是在數據分組後進行過濾,WHERE子句會在數據分組前進行過濾。WHERE子句排除的行不包含在分組中,可能會影響HAVING子句基於這些值過濾掉的分組。

【例5-23】查找數據庫 my_test 的表 students,查找專業學生數量大於2的學生總數和專業名稱。

mysql> select student_major,count(*) as '總人數'
    -> from students
    -> group by student_major
    -> having count(*) > 2;
+---------------+--------+
| student_major | 總人數 |
+---------------+--------+
| 數學專業      |      3 |
+---------------+--------+
1 row in set (0.14 sec)

例子中,使用GROUP BY對學生專業進行分組,統計每組學生人數,再使用HAVING子句過濾掉學生小於等於2的數據行。

5.7 ORDER BY子句

SELECT語句中,ORDER BY子句主要用來將結果集中的數據按照一定的順序進行排序。

語法格式:

ORDER BY {<列名> | <表達式> | <位置>}[ASC|DESC]

語法說明:

  • <列名>:指定用於排序的列。可以指定多個列,列名之間用逗號分隔。
  • <表達式>:指定用於排序的表達式。
  • <位置>:指定用於排序的列在SELECT語句結果集中的位置,通常是一個正整數。
  • ASC|DESC:關鍵字ASC表示按升序分組,DESC表示按降序分組,其中ASC爲默認值。這兩個關鍵字必須位於對應的列名、表達式、列的位置之後。

【例5-24】查找數據庫 my_test 的表 students,按照學生年齡的降序方式,輸出學生姓名和年齡。

mysql> select student_name,student_age from students
    -> order by student_age desc;
+--------------+-------------+
| student_name | student_age |
+--------------+-------------+
| 李玩         |          26 |
| 王小胖       |          25 |
| 張玲玲       |          25 |
| 張三         |          24 |
| 馬丁令       |          24 |
| 馮曉華       |          24 |
| 王五         |          23 |
| 趙六         |          23 |
| 周明明       |          23 |
| 張大慶       |          23 |
| 王青青       |          23 |
| 李明         |          22 |
| 李曉麗       |          22 |
| 王槓鈴       |          22 |
+--------------+-------------+
14 rows in set (0.00 sec)

使用ORDER BY子句該注意以下幾個方面:

  • ORDER BY子句中可以包含子查詢。
  • 當排序的值中存在空值時,ORDER BY子句會將該空值作爲最小值來對待。
  • 當ORDER BY子句中指定多個列進行排序時,則MySQL會按照列的順序從左到右依次進行排序。

5.8 LIMIT子句

當SELECT語句返回的結果集行數很多時,便於用戶對結果集的瀏覽和操作,可以使用LIMIT子句限制SELECT語句返回的行數。這通常用於分頁程序中。

語法格式:

LIMIT {[標誌位置] <行數> | <行數> OFFSET <標誌位置> }

語法說明:

  • <標誌位置>:可選項。默認爲數字0,用於指定返回數據第一行在SELECT語句結果集中的偏移量,必須爲非負整數。注意,SELECT語句結果集第一行(初始行)的偏移量爲數字0,而不是1。
  • <行數>:用於指定返回數據的行數,必須爲非負整數常量。若這個數大於結果集總數,則返回實際的記錄行。
  • <行數>OFFSET<位置標誌>:從第<標誌位置>+1行開始取<行數>行數據。

【例5-25】查找數據庫 my_test 的表 students,查找從第5個學生開始的3個學生的 id 和姓名。

mysql> select student_id,student_name from students
    -> limit 4,3;
+------------+--------------+
| student_id | student_name |
+------------+--------------+
|       1325 | 李曉麗       |
|       1326 | 李玩         |
|       1327 | 馬丁令       |
+------------+--------------+
3 rows in set (0.00 sec)

注意,上述語句中的“LIMIT 4,3”表示從第5行開始取3行數據。因爲第一行下標識是從0開始。
上述例子也可以寫成如下的SQL語句:

mysql> select student_id,student_name from students
    -> order by student_id
    -> limit 3 offset 4;
+------------+--------------+
| student_id | student_name |
+------------+--------------+
|       1325 | 李曉麗       |
|       1326 | 李玩         |
|       1327 | 馬丁令       |
+------------+--------------+
3 rows in set (0.00 sec)

5.9 UNOIN語句與聯合查詢

聯合查詢:把來自多個SELECT語句查詢的結果組合到一個結果集中,並且作爲單個查詢結果集返回,這種查詢方式成爲並或聯合查詢。

以下兩種基本情況,特別適合使用聯合查詢來實現:

  • 在單個查詢中,需要從不同的表中返回相似結構的數據。
  • 對單個表執行多餘查詢時,需要以單條查詢的信息集返回。

語法格式:

SELECT...UNION [ALL | DISTINCT] SELECT...

語法說明:

  • SELECT…:表示SELECT語句返回的結果集,和通常使用的SELECT語句相同。
  • UNION:用於表示合併前後兩個SELECT語句返回的結果集。
  • ALL | DISTINCT:關鍵字ALL表示當兩個結果集有重複的記錄的時候,允許重複記錄存在;關鍵字DISTINCT表示去除兩個結果集中重複出現的記錄,默認是DISTINCT。

【例5-26】查找數據庫 my_test 的表 students,使用UNION關鍵字合併專業是“物理專業”和性別是“1”的學生姓名、性別和專業信息。

mysql> select student_name,student_major,student_sex from students
    -> where student_major='物理專業'
    -> union
    -> select student_name,student_major,student_sex from students
    -> where student_sex='1';
+--------------+---------------+-------------+
| student_name | student_major | student_sex |
+--------------+---------------+-------------+
| 趙六         | 物理專業      | 1           |
| 馮曉華       | 物理專業      | 1           |
| 王五         | 數學專業      | 1           |
| 李曉麗       | 英語專業      | 1           |
| 張玲玲       | 英語專業      | 1           |
| 王青青       | 自動化專業    | 1           |
+--------------+---------------+-------------+
6 rows in set (0.50 sec)

UNION語句的使用非常簡單,只需先給出每條SELECT語句,然後在各條SELECT語句之間加上關鍵字UNION即可。若希望聯合查詢的結果集中沒有重複的數據行,可在關鍵字UNION之後添加關鍵字DISTINCT,這也是UNION的默認行爲;若希望聯合查詢的結果集中允許存在重複的數據行,則可以在關鍵字UNION之後直接添加關鍵字ALL。

使用UNION子句的時候,需要注意以下幾點:

  • UNION語句至少由兩條或者兩條以上的SELECT語句組成,之間用UNION分隔。
  • UNION語句的每個SELECT查詢必須包含相同的列、表達式或者聚集函數。
  • UNION語句的每個SELECT對應的列數據類型必須兼容。即類型相同或者可以隱含轉換。
  • UNION語句中的第一個SELECT語句所用的列名會被當成整個結果集的列名。
  • UNION語句只使用一條ORDER BY子句或者LIMIT子句,且他們必須置於最後一條,SELECT語句之後。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章