2020重新出發(fā)拣挪,MySql基礎(chǔ)擦酌,MySql表數(shù)據(jù)操作

@[toc]

MySQL操作表中數(shù)據(jù)

MySQL 提供了功能豐富的數(shù)據(jù)庫(kù)管理語(yǔ)句,包括向數(shù)據(jù)庫(kù)中插入數(shù)據(jù)的 INSERT 語(yǔ)句媒吗,更新數(shù)據(jù)的 UPDATE 語(yǔ)句,以及當(dāng)數(shù)據(jù)不再使用時(shí)乙埃,刪除數(shù)據(jù)的 DELETE 語(yǔ)句闸英。

MySQL 數(shù)據(jù)表查詢語(yǔ)句

在 MySQL 中,使用 SELECT 語(yǔ)句來(lái)查詢數(shù)據(jù)介袜。查詢數(shù)據(jù)是指從數(shù)據(jù)庫(kù)中根據(jù)需求甫何,使用不同的查詢方式來(lái)獲取不同的數(shù)據(jù),是使用頻率最高遇伞、最重要的操作辙喂。

SELECT 的語(yǔ)法格式如下:

SELECT
{* | <字段列名>}
[
FROM <表 1>, <表 2>…
[WHERE <表達(dá)式>
[GROUP BY <group by definition>
[HAVING <expression> [{<operator> <expression>}…]]
[ORDER BY <order by definition>]
[LIMIT[<offset>,] <row count>]
]

其中,各條子句的含義如下:

  • {*|<字段列名>}包含星號(hào)通配符的字段列表鸠珠,表示所要查詢字段的名稱巍耗。
  • <表 1>,<表 2>…渐排,表 1 和表 2 表示查詢數(shù)據(jù)的來(lái)源炬太,可以是單個(gè)或多個(gè)。
  • WHERE <表達(dá)式>是可選項(xiàng)驯耻,如果選擇該項(xiàng)亲族,將限定查詢數(shù)據(jù)必須滿足該查詢條件。
  • GROUP BY< 字段 >可缚,該子句告訴 MySQL 如何顯示查詢出來(lái)的數(shù)據(jù)霎迫,并按照指定的字段分組。
  • [ORDER BY< 字段 >]帘靡,該子句告訴 MySQL 按什么樣的順序顯示查詢出來(lái)的數(shù)據(jù)知给,可以進(jìn)行的排序有升序(ASC)和降序(DESC),默認(rèn)情況下是升序描姚。
  • [LIMIT[<offset>炼鞠,]<row count>]缘滥,該子句告訴 MySQL 每次顯示查詢出來(lái)的數(shù)據(jù)條數(shù)。

下面先介紹一些簡(jiǎn)單的 SELECT 語(yǔ)句谒主,關(guān)于 WHERE朝扼、GROUP BY、ORDER BY 和 LIMIT 等限制條件霎肯,后面我們會(huì)一一講解擎颖。

查詢表中所有字段

查詢所有字段是指查詢表中所有字段的數(shù)據(jù)。MySQL 提供了以下 2 種方式查詢表中的所有字段观游。

  • 使用“*”通配符查詢所有字段
  • 列出表的所有字段

使用“*”查詢表的所有字段

SELECT 可以使用“*”查找表中所有字段的數(shù)據(jù)搂捧,語(yǔ)法格式如下:

SELECT * FROM 表名;

使用“*”查詢時(shí),只能按照數(shù)據(jù)表中字段的順序進(jìn)行排列懂缕,不能改變字段的排列順序允跑。

注意:一般情況下,除非需要使用表中所有的字段數(shù)據(jù)搪柑,否則最好不要使用通配符“ * ”聋丝。雖然使用通配符可以節(jié)省輸入查詢語(yǔ)句的時(shí)間,但是獲取不需要的列數(shù)據(jù)通常會(huì)降低查詢和所使用的應(yīng)用程序的效率工碾。使用“”的優(yōu)勢(shì)是弱睦,當(dāng)不知道所需列的名稱時(shí),可以通過(guò)“”獲取它們渊额。

列出表的所有字段

SELECT 關(guān)鍵字后面的字段名為需要查找的字段况木,因此可以將表中所有字段的名稱跟在 SELECT 關(guān)鍵字后面。

如果忘記了字段名稱旬迹,可以使用 DESC 命令查看表的結(jié)構(gòu)火惊。

這種查詢方式比較靈活,如果需要改變字段顯示的順序奔垦,只需調(diào)整 SELECT 關(guān)鍵字后面的字段列表順序即可矗晃。

雖然列出表的所有字段的方式比較靈活,但是查詢所有字段時(shí)通常使用“ * ”通配符宴倍。使用“*”這種方式比較簡(jiǎn)單张症,尤其是表中的字段很多的時(shí)候,這種方式的優(yōu)勢(shì)更加明顯鸵贬。當(dāng)然俗他,如果需要改變字段顯示的順序,可以選擇列出表的所有字段阔逼。

查詢表中指定的字段

查詢表中的某一個(gè)字段的語(yǔ)法格式為:

SELECT < 列名 > FROM < 表名 >;

使用 SELECT 聲明可以獲取多個(gè)字段下的數(shù)據(jù)兆衅,只需要在關(guān)鍵字 SELECT 后面指定要查找的字段名稱,不同字段名稱之間用逗號(hào)“,”分隔開(kāi)羡亩,最后一個(gè)字段后面不需要加逗號(hào)摩疑,語(yǔ)法格式如下:

SELECT <字段名1>,<字段名2>,…,<字段名n> FROM <表名>;

MySQL過(guò)濾重復(fù)數(shù)據(jù)

在 MySQL 中使用 SELECT 語(yǔ)句執(zhí)行簡(jiǎn)單的數(shù)據(jù)查詢時(shí),返回的是所有匹配的記錄畏铆。如果表中的某些字段沒(méi)有唯一性約束雷袋,那么這些字段就可能存在重復(fù)值。為了實(shí)現(xiàn)查詢不重復(fù)的數(shù)據(jù)辞居,MySQL 提供了 DISTINCT 關(guān)鍵字楷怒。

DISTINCT 關(guān)鍵字的主要作用就是對(duì)數(shù)據(jù)表中一個(gè)或多個(gè)字段重復(fù)的數(shù)據(jù)進(jìn)行過(guò)濾,只返回其中的一條數(shù)據(jù)給用戶瓦灶。

DISTINCT 關(guān)鍵字的語(yǔ)法格式為:

SELECT DISTINCT <字段名> FROM <表名>;

其中鸠删,“字段名”為需要消除重復(fù)記錄的字段名稱,多個(gè)字段時(shí)用逗號(hào)隔開(kāi)贼陶。

使用 DISTINCT 關(guān)鍵字時(shí)需要注意以下幾點(diǎn):

  • DISTINCT 關(guān)鍵字只能在 SELECT 語(yǔ)句中使用刃泡。
  • 在對(duì)一個(gè)或多個(gè)字段去重時(shí),DISTINCT 關(guān)鍵字必須在所有字段的最前面碉怔。
  • 如果 DISTINCT 關(guān)鍵字后有多個(gè)字段烘贴,則會(huì)對(duì)多個(gè)字段進(jìn)行組合去重,也就是說(shuō)眨层,只有多個(gè)字段組合起來(lái)完全是一樣的情況下才會(huì)被去重庙楚。

MySQL 設(shè)置別名

為了查詢方便上荡,MySQL 提供了 AS 關(guān)鍵字來(lái)為表和字段指定別名趴樱。

為表指定別名

當(dāng)表名很長(zhǎng)或者執(zhí)行一些特殊查詢的時(shí)候,為了方便操作酪捡,可以為表指定一個(gè)別名叁征,用這個(gè)別名代替表原來(lái)的名稱。

為表指定別名的基本語(yǔ)法格式為:

<表名> [AS] <別名>

其中各子句的含義如下:

  • <表名>:數(shù)據(jù)庫(kù)中存儲(chǔ)的數(shù)據(jù)表的名稱逛薇。
  • <別名>:查詢時(shí)指定的表的新名稱捺疼。
  • AS關(guān)鍵字可以省略,省略后需要將表名和別名用空格隔開(kāi)永罚。

注意:表的別名不能與該數(shù)據(jù)庫(kù)的其它表同名啤呼。字段的別名不能與該表的其它字段同名。在條件表達(dá)式中不能使用字段的別名呢袱,否則會(huì)出現(xiàn)“ERROR 1054 (42S22): Unknown column”這樣的錯(cuò)誤提示信息官扣。

為字段指定別名

在使用 SELECT 語(yǔ)句查詢數(shù)據(jù)時(shí),MySQL 會(huì)顯示每個(gè) SELECT 后面指定輸出的字段羞福。有時(shí)為了顯示結(jié)果更加直觀惕蹄,我們可以為字段指定一個(gè)別名。

為字段指定別名的基本語(yǔ)法格式為:

<字段名> [AS] <別名>

其中,各子句的語(yǔ)法含義如下:

  • <字段名>:為數(shù)據(jù)表中字段定義的名稱卖陵。
  • <字段別名>:字段新的名稱遭顶。
  • AS關(guān)鍵字可以省略,省略后需要將字段名和別名用空格隔開(kāi)泪蔫。

注意:表別名只在執(zhí)行查詢時(shí)使用棒旗,并不在返回結(jié)果中顯示。而字段定義別名之后鸥滨,會(huì)返回給客戶端顯示嗦哆,顯示的字段為字段的別名。

MySQL限制查詢結(jié)果的條數(shù)

當(dāng)數(shù)據(jù)表中有上萬(wàn)條數(shù)據(jù)時(shí)婿滓,一次性查詢出表中的全部數(shù)據(jù)會(huì)降低數(shù)據(jù)返回的速度老速,同時(shí)給數(shù)據(jù)庫(kù)服務(wù)器造成很大的壓力。這時(shí)就可以用 LIMIT 關(guān)鍵字來(lái)限制查詢結(jié)果返回的條數(shù)凸主。

LIMIT 是 MySQL 中的一個(gè)特殊關(guān)鍵字橘券,用于指定查詢結(jié)果從哪條記錄開(kāi)始顯示,一共顯示多少條記錄卿吐。

LIMIT 關(guān)鍵字有 3 種使用方式旁舰,即指定初始位置、不指定初始位置以及與 OFFSET 組合使用嗡官。

指定初始位置

LIMIT 關(guān)鍵字可以指定查詢結(jié)果從哪條記錄開(kāi)始顯示箭窜,顯示多少條記錄。

LIMIT 指定初始位置的基本語(yǔ)法格式如下:

LIMIT 初始位置衍腥,記錄數(shù)

其中磺樱,“初始位置”表示從哪條記錄開(kāi)始顯示;“記錄數(shù)”表示顯示記錄的條數(shù)婆咸。第一條記錄的位置是 0竹捉,第二條記錄的位置是 1。后面的記錄依次類推尚骄。

注意:LIMIT 后的兩個(gè)參數(shù)必須都是正整數(shù)块差。

不指定初始位置

LIMIT 關(guān)鍵字不指定初始位置時(shí),記錄從第一條記錄開(kāi)始顯示倔丈。顯示記錄的條數(shù)由 LIMIT 關(guān)鍵字指定憨闰。

LIMIT 不指定初始位置的基本語(yǔ)法格式如下:

LIMIT 記錄數(shù)

其中,“記錄數(shù)”表示顯示記錄的條數(shù)需五。如果“記錄數(shù)”的值小于查詢結(jié)果的總數(shù)鹉动,則會(huì)從第一條記錄開(kāi)始,顯示指定條數(shù)的記錄警儒。如果“記錄數(shù)”的值大于查詢結(jié)果的總數(shù)训裆,則會(huì)直接顯示查詢出來(lái)的所有記錄眶根。

LIMIT和OFFSET組合使用

LIMIT 可以和 OFFSET 組合使用,語(yǔ)法格式如下:

LIMIT 記錄數(shù) OFFSET 初始位置

參數(shù)和 LIMIT 語(yǔ)法中參數(shù)含義相同边琉,“初始位置”指定從哪條記錄開(kāi)始顯示属百;“記錄數(shù)”表示顯示記錄的條數(shù)。

MySQL 對(duì)查詢結(jié)果排序

通過(guò)條件查詢語(yǔ)句可以查詢到符合用戶需求的數(shù)據(jù)变姨,但是查詢到的數(shù)據(jù)一般都是按照數(shù)據(jù)最初被添加到表中的順序來(lái)顯示族扰。為了使查詢結(jié)果的順序滿足用戶的要求,MySQL 提供了 ORDER BY 關(guān)鍵字來(lái)對(duì)查詢結(jié)果進(jìn)行排序定欧。

在實(shí)際應(yīng)用中經(jīng)常需要對(duì)查詢結(jié)果進(jìn)行排序渔呵,比如,在網(wǎng)上購(gòu)物時(shí)砍鸠,可以將商品按照價(jià)格進(jìn)行排序扩氢;在醫(yī)院的掛號(hào)系統(tǒng)中,可以按照掛號(hào)的先后順序進(jìn)行排序等爷辱。

ORDER BY 關(guān)鍵字主要用來(lái)將查詢結(jié)果中的數(shù)據(jù)按照一定的順序進(jìn)行排序录豺。其語(yǔ)法格式如下:

ORDER BY <字段名> [ASC|DESC]

語(yǔ)法說(shuō)明如下。

  • 字段名:表示需要排序的字段名稱饭弓,多個(gè)字段時(shí)用逗號(hào)隔開(kāi)双饥。
  • ASC|DESC:ASC表示字段按升序排序;DESC表示字段按降序排序弟断。其中ASC為默認(rèn)值咏花。

使用 ORDER BY 關(guān)鍵字應(yīng)該注意以下幾個(gè)方面:

  • ORDER BY 關(guān)鍵字后可以跟子查詢(關(guān)于子查詢后面教程會(huì)詳細(xì)講解,這里了解即可)阀趴。
  • 當(dāng)排序的字段中存在空值時(shí)昏翰,ORDER BY 會(huì)將該空值作為最小值來(lái)對(duì)待。
  • ORDER BY 指定多個(gè)字段進(jìn)行排序時(shí)舍咖,MySQL 會(huì)按照字段的順序從左到右依次進(jìn)行排序矩父。

單字段排序

下面通過(guò)一個(gè)具體的實(shí)例來(lái)說(shuō)明當(dāng) ORDER BY 指定單個(gè)字段時(shí)锉桑,MySQL 如何對(duì)查詢結(jié)果進(jìn)行排序排霉。

例子:下面查詢 tb_students_info 表的所有記錄,并對(duì) height 字段進(jìn)行排序民轴,SQL 語(yǔ)句和運(yùn)行結(jié)果如下攻柠。

mysql> SELECT * FROM tb_students_info ORDER BY height;
+----+--------+---------+------+------+--------+------------+
| id | name   | dept_id | age  | sex  | height | login_date |
+----+--------+---------+------+------+--------+------------+
|  2 | Green  |       3 |   23 | F    |    158 | 2016-10-22 |
|  1 | Dany   |       1 |   25 | F    |    160 | 2015-09-10 |
|  4 | Jane   |       1 |   22 | F    |    162 | 2016-12-20 |
|  7 | Lily   |       6 |   22 | F    |    165 | 2016-02-26 |
| 10 | Tom    |       4 |   23 | M    |    165 | 2016-08-05 |
|  8 | Susan  |       4 |   23 | F    |    170 | 2015-10-01 |
|  6 | John   |       2 |   21 | M    |    172 | 2015-11-11 |
|  5 | Jim    |       1 |   24 | M    |    175 | 2016-01-15 |
|  9 | Thomas |       3 |   22 | M    |    178 | 2016-06-07 |
|  3 | Henry  |       2 |   23 | M    |    185 | 2015-05-31 |
+----+--------+---------+------+------+--------+------------+
10 rows in set (0.08 sec)

由結(jié)果可以看到,MySQL 對(duì)查詢的 height 字段的數(shù)據(jù)按數(shù)值的大小進(jìn)行了升序序后裸。

多字段排序

下面通過(guò)一個(gè)具體的實(shí)例來(lái)說(shuō)明當(dāng) ORDER BY 指定多個(gè)字段時(shí)瑰钮,MySQL 如何對(duì)查詢結(jié)果進(jìn)行排序。

例子:查詢 tb_students_info 表中的 name 和 height 字段微驶,先按 height 排序浪谴,再按 name 排序开睡,SQL 語(yǔ)句和運(yùn)行結(jié)果如下。

mysql> SELECT name,height FROM tb_students_info ORDER BY height,name;
+--------+--------+
| name   | height |
+--------+--------+
| Green  |    158 |
| Dany   |    160 |
| Jane   |    162 |
| Lily   |    165 |
| Tom    |    165 |
| Susan  |    170 |
| John   |    172 |
| Jim    |    175 |
| Thomas |    178 |
| Henry  |    185 |
+--------+--------+
10 rows in set (0.09 sec)

注意:在對(duì)多個(gè)字段進(jìn)行排序時(shí)苟耻,排序的第一個(gè)字段必須有相同的值篇恒,才會(huì)對(duì)第二個(gè)字段進(jìn)行排序。如果第一個(gè)字段數(shù)據(jù)中所有的值都是唯一的凶杖,MySQL 將不再對(duì)第二個(gè)字段進(jìn)行排序胁艰。

默認(rèn)情況下,查詢數(shù)據(jù)按字母升序進(jìn)行排序(A~Z)智蝠,但數(shù)據(jù)的排序并不僅限于此腾么,還可以使用 ORDER BY 中的 DESC 對(duì)查詢結(jié)果進(jìn)行降序排序(Z~A)。

MySQL 條件查詢數(shù)據(jù)

在 MySQL 中杈湾,如果需要有條件的從數(shù)據(jù)表中查詢數(shù)據(jù)解虱,可以使用 WHERE 關(guān)鍵字來(lái)指定查詢條件

使用 WHERE 關(guān)鍵字的語(yǔ)法格式如下:

WHERE 查詢條件

查詢條件可以是:

  • 帶比較運(yùn)算符和邏輯運(yùn)算符的查詢條件
  • 帶 BETWEEN AND 關(guān)鍵字的查詢條件
  • 帶 IS NULL 關(guān)鍵字的查詢條件
  • 帶 IN 關(guān)鍵字的查詢條件
  • 帶 LIKE 關(guān)鍵字的查詢條件

單一條件的查詢語(yǔ)句

單一條件指的是在 WHERE 關(guān)鍵字后只有一個(gè)查詢條件漆撞。

多條件的查詢語(yǔ)句

在 WHERE 關(guān)鍵詞后可以有多個(gè)查詢條件饭寺,這樣能夠使查詢結(jié)果更加精確。多個(gè)查詢條件時(shí)用邏輯運(yùn)算符 AND(&&)叫挟、OR(||)或 XOR 隔開(kāi)艰匙。

  • AND:記錄滿足所有查詢條件時(shí),才會(huì)被查詢出來(lái)抹恳。
  • OR:記錄滿足任意一個(gè)查詢條件時(shí)员凝,才會(huì)被查詢出來(lái)。
  • XOR:記錄滿足其中一個(gè)條件奋献,并且不滿足另一個(gè)條件時(shí)健霹,才會(huì)被查詢出來(lái)。

OR瓶蚂、AND 和 XOR 可以一起使用糖埋,但是在使用時(shí)要注意運(yùn)算符的優(yōu)先級(jí)

查詢條件越多,查詢出來(lái)的記錄就會(huì)越少窃这。因?yàn)橥穑O(shè)置的條件越多,查詢語(yǔ)句的限制就更多杭攻,能夠滿足所有條件的記錄就更少祟敛。為了使查詢出來(lái)的記錄正是自己想要的,可以在 WHERE 語(yǔ)句中將查詢條件設(shè)置的更加具體兆解。

MySQL 模糊查詢

在 MySQL 中馆铁,LIKE 關(guān)鍵字主要用于搜索匹配字段中的指定內(nèi)容。其語(yǔ)法格式如下:

[NOT] LIKE '字符串'

其中:

  • NOT :可選參數(shù)锅睛,字段中的內(nèi)容與指定的字符串不匹配時(shí)滿足條件埠巨。
  • 字符串:指定用來(lái)匹配的字符串历谍。“字符串”可以是一個(gè)很完整的字符串辣垒,也可以包含通配符扮饶。

LIKE 關(guān)鍵字支持百分號(hào)“%”和下劃線“_”通配符。

  • 通配符是一種特殊語(yǔ)句乍构,主要用來(lái)模糊查詢甜无。當(dāng)不知道真正字符或者懶得輸入完整名稱時(shí),可以使用通配符來(lái)代替一個(gè)或多個(gè)真正的字符哥遮。

帶有“%”通配符的查詢

“%”是 MySQL 中最常用的通配符岂丘,它能代表任何長(zhǎng)度的字符串,字符串的長(zhǎng)度可以為 0眠饮。

  • 例如奥帘,a%b表示以字母 a 開(kāi)頭,以字母 b 結(jié)尾的任意長(zhǎng)度的字符串仪召。該字符串可以代表 ab寨蹋、acb、accb扔茅、accrb 等字符串已旧。

注意:匹配的字符串必須加單引號(hào)或雙引號(hào)。

NOT LIKE 表示字符串不匹配時(shí)滿足條件召娜。

帶有“_”通配符的查詢

“_”只能代表單個(gè)字符运褪,字符的長(zhǎng)度不能為 0。

  • 例如玖瘸,a_b可以代表 acb秸讹、adb、aub 等字符串雅倒。

LIKE 區(qū)分大小寫

默認(rèn)情況下璃诀,LIKE 關(guān)鍵字匹配字符的時(shí)候是不區(qū)分大小寫的。如果需要區(qū)分大小寫蔑匣,可以加入 BINARY 關(guān)鍵字劣欢。

使用通配符的注意事項(xiàng)和技巧

下面是使用通配符的一些注意事項(xiàng):

  • 注意大小寫。MySQL 默認(rèn)是不區(qū)分大小寫的殖演。如果區(qū)分大小寫氧秘,像“Tom”這樣的數(shù)據(jù)就不能被“t%”所匹配到年鸳。
  • 注意尾部空格趴久,尾部空格會(huì)干擾通配符的匹配。例如搔确,“T% ”就不能匹配到“Tom”彼棍。
  • 注意 NULL灭忠。“%”通配符可以到匹配任意字符座硕,但是不能匹配 NULL弛作。也就是說(shuō) “%”匹配不到 tb_students_info 數(shù)據(jù)表中值為 NULL 的記錄。

下面是一些使用通配符要記住的技巧华匾。

  • 不要過(guò)度使用通配符映琳,如果其它操作符能達(dá)到相同的目的,應(yīng)該使用其它操作符蜘拉。因?yàn)?MySQL 對(duì)通配符的處理一般會(huì)比其他操作符花費(fèi)更長(zhǎng)的時(shí)間萨西。
  • 在確定使用通配符后,除非絕對(duì)有必要旭旭,否則不要把它們用在字符串的開(kāi)始處谎脯。把通配符置于搜索模式的開(kāi)始處,搜索起來(lái)是最慢的持寄。
  • 仔細(xì)注意通配符的位置源梭。如果放錯(cuò)地方,可能不會(huì)返回想要的數(shù)據(jù)稍味。

總之废麻,通配符是一種極其重要和有用的搜索工具,以后我們會(huì)經(jīng)常用到它模庐。

注意:如果查詢內(nèi)容中包含通配符脑溢,可以使用“\”轉(zhuǎn)義符。例如赖欣,在 tb_students_info 表中屑彻,將學(xué)生姓名“Dany”修改為“Dany%”后,查詢以“%”結(jié)尾的學(xué)生姓名顶吮,SQL 語(yǔ)句和運(yùn)行結(jié)果如下:

mysql> SELECT NAME FROM test.`tb_students_info` WHERE NAME LIKE '%\%';
+-------+
| NAME  |
+-------+
| Dany% |
+-------+
1 row in set (0.00 sec)

MySQL 范圍查詢

MySQL 提供了 BETWEEN AND 關(guān)鍵字社牲,用來(lái)判斷字段的數(shù)值是否在指定范圍內(nèi)。

BETWEEN AND 需要兩個(gè)參數(shù)悴了,即范圍的起始值和終止值搏恤。如果字段值在指定的范圍內(nèi),則這些記錄被返回湃交。如果不在指定范圍內(nèi)熟空,則不會(huì)被返回。

使用 BETWEEN AND 的基本語(yǔ)法格式如下:

[NOT] BETWEEN 取值1 AND 取值2

其中:

  • NOT:可選參數(shù)搞莺,表示指定范圍之外的值息罗。如果字段值不滿足指定范圍內(nèi)的值,則這些記錄被返回才沧。
  • 取值1:表示范圍的起始值迈喉。
  • 取值2:表示范圍的終止值绍刮。

BETWEEN AND 和 NOT BETWEEN AND 關(guān)鍵字在查詢指定范圍內(nèi)的記錄時(shí)很有用。例如挨摸,查詢學(xué)生的年齡段孩革、出生日期,員工的工資水平等得运。

例子:在表 tb_students_info 中查詢年齡在 20 到 23 之間的學(xué)生姓名和年齡膝蜈,SQL 語(yǔ)句和運(yùn)行結(jié)果如下。

mysql> SELECT name,age FROM tb_students_info 
    -> WHERE age BETWEEN 20 AND 23;
+--------+------+
| name   | age  |
+--------+------+
| Green  |   23 |
| Henry  |   23 |
| Jane   |   22 |
| John   |   21 |
| Lily   |   22 |
| Susan  |   23 |
| Thomas |   22 |
| Tom    |   23 |
+--------+------+
8 rows in set (0.00 sec)

查詢結(jié)果中包含學(xué)生年齡為 20 和 23 的記錄,這就說(shuō)明,在 MySQL 中盗胀,BETWEEN AND 能匹配指定范圍內(nèi)的所有值涯穷,包括起始值和終止值

MySQL空值查詢

MySQL 提供了 IS NULL 關(guān)鍵字,用來(lái)判斷字段的值是否為空值(NULL)。空值不同于 0坤学,也不同于空字符串。

如果字段的值是空值报慕,則滿足查詢條件深浮,該記錄將被查詢出來(lái)。如果字段的值不是空值眠冈,則不滿足查詢條件飞苇。

使用 IS NULL 的基本語(yǔ)法格式如下:

IS [NOT] NULL

其中,“NOT”是可選參數(shù)蜗顽,表示字段值不是空值時(shí)滿足條件布卡。

注意:IS NULL 是一個(gè)整體,不能將 IS 換成“=”雇盖。如果將 IS 換成“=”將不能查詢出任何結(jié)果忿等,數(shù)據(jù)庫(kù)系統(tǒng)會(huì)出現(xiàn)“Empty set(0.00 sec)”這樣的提示。同理崔挖,IS NOT NULL 中的 IS NOT 不能換成“!=”或“<>”贸街。

IS NOT NULL 表示查詢字段值不為空的記錄。

MySQL分組查詢

在 MySQL 中狸相,GROUP BY 關(guān)鍵字可以根據(jù)一個(gè)或多個(gè)字段對(duì)查詢結(jié)果進(jìn)行分組薛匪。

使用 GROUP BY 關(guān)鍵字的語(yǔ)法格式如下

GROUP BY <字段名>

其中,“字段名”表示需要分組的字段名稱脓鹃,多個(gè)字段時(shí)用逗號(hào)隔開(kāi)逸尖。

GROUP BY單獨(dú)使用

單獨(dú)使用 GROUP BY 關(guān)鍵字時(shí),查詢結(jié)果會(huì)只顯示每個(gè)分組的第一條記錄。

GROUP BY 與 GROUP_CONCAT()

GROUP BY 關(guān)鍵字可以和 GROUP_CONCAT() 函數(shù)一起使用冷溶。GROUP_CONCAT() 函數(shù)會(huì)把每個(gè)分組的字段值都顯示出來(lái)渐白。

例子:下面根據(jù) tb_students_info 表中的 sex 字段進(jìn)行分組查詢尊浓,使用 GROUP_CONCAT() 函數(shù)將每個(gè)分組的 name 字段的值都顯示出來(lái)逞频。

SQL 語(yǔ)句和運(yùn)行結(jié)果如下:

mysql> SELECT `sex`, GROUP_CONCAT(name) FROM tb_students_info 
    -> GROUP BY sex;
+------+----------------------------+
| sex  | GROUP_CONCAT(name)         |
+------+----------------------------+
| 女   | Henry,Jim,John,Thomas,Tom  |
| 男   | Dany,Green,Jane,Lily,Susan |
+------+----------------------------+
2 rows in set (0.00 sec)

由結(jié)果可以看到,查詢結(jié)果分為兩組栋齿,sex 字段值為“女”的是一組苗胀,值為“男”的是一組,且每組的學(xué)生姓名都顯示出來(lái)了瓦堵。

注意:多個(gè)字段分組查詢時(shí)基协,會(huì)先按照第一個(gè)字段進(jìn)行分組。如果第一個(gè)字段中有相同的值菇用,MySQL 才會(huì)按照第二個(gè)字段進(jìn)行分組澜驮。如果第一個(gè)字段中的數(shù)據(jù)都是唯一的,那么 MySQL 將不再對(duì)第二個(gè)字段進(jìn)行分組惋鸥。

GROUP BY 與聚合函數(shù)

在數(shù)據(jù)統(tǒng)計(jì)時(shí)杂穷,GROUP BY 關(guān)鍵字經(jīng)常和聚合函數(shù)一起使用

聚合函數(shù)包括 COUNT()卦绣,SUM()耐量,AVG(),MAX() 和 MIN()滤港。其中廊蜒,COUNT() 用來(lái)統(tǒng)計(jì)記錄的條數(shù);SUM() 用來(lái)計(jì)算字段值的總和溅漾;AVG() 用來(lái)計(jì)算字段值的平均值山叮;MAX() 用來(lái)查詢字段的最大值;MIN() 用來(lái)查詢字段的最小值添履。

例子:下面根據(jù) tb_students_info 表的 sex 字段進(jìn)行分組查詢聘芜,使用 COUNT() 函數(shù)計(jì)算每一組的記錄數(shù)。SQL 語(yǔ)句和運(yùn)行結(jié)果如下:

mysql> SELECT sex,COUNT(sex) FROM tb_students_info 
    -> GROUP BY sex;
+------+------------+
| sex  | COUNT(sex) |
+------+------------+
| 女   |          5 |
| 男   |          5 |
+------+------------+
2 rows in set (0.00 sec)

結(jié)果顯示缝龄,sex 字段值為“女”的記錄是一組汰现,有 5 條記錄;sex 字段值為“男”的記錄是一組叔壤,有 5 條記錄瞎饲。

GROUP BY 與 WITH ROLLUP

WITH POLLUP 關(guān)鍵字用來(lái)在所有記錄的最后加上一條記錄,這條記錄是上面所有記錄的總和炼绘,即統(tǒng)計(jì)記錄數(shù)量嗅战。

例子:下面根據(jù) tb_students_info 表中的 sex 字段進(jìn)行分組查詢,并使用 WITH ROLLUP 顯示記錄的總和。

mysql> SELECT sex,GROUP_CONCAT(name) FROM tb_students_info 
    ->GROUP BY sex WITH ROLLUP;
+------+------------------------------------------------------+
| sex  | GROUP_CONCAT(name)                                   |
+------+------------------------------------------------------+
| 女   | Henry,Jim,John,Thomas,Tom                            |
| 男   | Dany,Green,Jane,Lily,Susan                           |
| NULL | Henry,Jim,John,Thomas,Tom,Dany,Green,Jane,Lily,Susan |
+------+------------------------------------------------------+
3 rows in set (0.00 sec)

查詢結(jié)果顯示驮捍,GROUP_CONCAT(name) 顯示了每個(gè)分組的 name 字段值疟呐。同時(shí),最后一條記錄的 GROUP_CONCAT(name) 字段的值剛好是上面分組 name 字段值的總和东且。

MySQL 過(guò)濾分組

在 MySQL 中启具,可以使用 HAVING 關(guān)鍵字對(duì)分組后的數(shù)據(jù)進(jìn)行過(guò)濾

使用 HAVING 關(guān)鍵字的語(yǔ)法格式如下:

HAVING <查詢條件>

HAVING 關(guān)鍵字和 WHERE 關(guān)鍵字都可以用來(lái)過(guò)濾數(shù)據(jù)珊泳,且 HAVING 支持 WHERE 關(guān)鍵字中所有的操作符和語(yǔ)法鲁冯。

但是 WHERE 和 HAVING 關(guān)鍵字也存在以下幾點(diǎn)差異:

  • 一般情況下,WHERE 用于過(guò)濾數(shù)據(jù)行色查,而 HAVING 用于過(guò)濾分組薯演。
  • WHERE 查詢條件中不可以使用聚合函數(shù),而 HAVING 查詢條件中可以使用聚合函數(shù)秧了。
  • WHERE 在數(shù)據(jù)分組前進(jìn)行過(guò)濾跨扮,而 HAVING 在數(shù)據(jù)分組后進(jìn)行過(guò)濾 。
  • WHERE 針對(duì)數(shù)據(jù)庫(kù)文件進(jìn)行過(guò)濾验毡,而 HAVING 針對(duì)查詢結(jié)果進(jìn)行過(guò)濾衡创。也就是說(shuō),WHERE 根據(jù)數(shù)據(jù)表中的字段直接進(jìn)行過(guò)濾米罚,而 HAVING 是根據(jù)前面已經(jīng)查詢出的字段進(jìn)行過(guò)濾钧汹。
  • WHERE 查詢條件中不可以使用字段別名,而 HAVING 查詢條件中可以使用字段別名录择。

例子:分別使用 HAVING 和 WHERE 關(guān)鍵字查詢出 tb_students_info 表中身高大于 150 的學(xué)生姓名拔莱,性別和身高。SQL 語(yǔ)句和運(yùn)行結(jié)果如下隘竭。

mysql> SELECT name,sex,height FROM tb_students_info 
    -> HAVING height>150;
+--------+------+--------+
| name   | sex  | height |
+--------+------+--------+
| Dany   | 男   |    160 |
| Green  | 男   |    158 |
| Henry  | 女   |    185 |
| Jane   | 男   |    162 |
| Jim    | 女   |    175 |
| John   | 女   |    172 |
| Lily   | 男   |    165 |
| Susan  | 男   |    170 |
| Thomas | 女   |    178 |
| Tom    | 女   |    165 |
+--------+------+--------+
10 rows in set (0.00 sec)

mysql> SELECT name,sex,height FROM tb_students_info 
    -> WHERE height>150;
+--------+------+--------+
| name   | sex  | height |
+--------+------+--------+
| Dany   | 男   |    160 |
| Green  | 男   |    158 |
| Henry  | 女   |    185 |
| Jane   | 男   |    162 |
| Jim    | 女   |    175 |
| John   | 女   |    172 |
| Lily   | 男   |    165 |
| Susan  | 男   |    170 |
| Thomas | 女   |    178 |
| Tom    | 女   |    165 |
+--------+------+--------+
10 rows in set (0.00 sec)

上述實(shí)例中塘秦,因?yàn)樵?SELECT 關(guān)鍵字后已經(jīng)查詢出了 height 字段,所以 HAVING 和 WHERE 都可以使用动看。但是如果 SELECT 關(guān)鍵字后沒(méi)有查詢出 height 字段尊剔,MySQL 就會(huì)報(bào)錯(cuò)。

MySQL 交叉連接

前面所講的查詢語(yǔ)句都是針對(duì)一個(gè)表的菱皆,但是在關(guān)系型數(shù)據(jù)庫(kù)中须误,表與表之間是有聯(lián)系的,所以在實(shí)際應(yīng)用中仇轻,經(jīng)常使用多表查詢京痢。多表查詢就是同時(shí)查詢兩個(gè)或兩個(gè)以上的表。

在 MySQL 中篷店,多表查詢主要有交叉連接祭椰、內(nèi)連接和外連接。

笛卡爾積

笛卡爾積(Cartesian product)是指兩個(gè)集合 X 和 Y 的乘積。

例如方淤,有 A 和 B 兩個(gè)集合钉赁,它們的值如下:

A = {1,2}
B = {3,4,5}

集合 A×B 和 B×A 的結(jié)果集分別表示為:

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 的結(jié)果就叫做兩個(gè)集合的笛卡爾積。

并且携茂,從以上結(jié)果我們可以看出:

  • 兩個(gè)集合相乘你踩,不滿足交換率,即 A×B≠B×A邑蒋。
  • A 集合和 B 集合的笛卡爾積是 A 集合的元素個(gè)數(shù) × B 集合的元素個(gè)數(shù)姓蜂。

多表查詢遵循的算法就是以上提到的笛卡爾積按厘,表與表之間的連接可以看成是在做乘法運(yùn)算医吊。在實(shí)際應(yīng)用中,應(yīng)避免使用笛卡爾積逮京,因?yàn)榈芽柗e中容易存在大量的不合理數(shù)據(jù)卿堂,簡(jiǎn)單來(lái)說(shuō)就是容易導(dǎo)致查詢結(jié)果重復(fù)、混亂懒棉。

交叉連接

交叉連接(CROSS JOIN)一般用來(lái)返回連接表的笛卡爾積草描。

交叉連接的語(yǔ)法格式如下:

SELECT <字段名> FROM <表1> CROSS JOIN <表2> [WHERE子句]

SELECT <字段名> FROM <表1>, <表2> [WHERE子句] 

語(yǔ)法說(shuō)明如下:

  • 字段名:需要查詢的字段名稱。
  • <表1><表2>:需要交叉連接的表名策严。
  • WHERE 子句:用來(lái)設(shè)置交叉連接的查詢條件穗慕。

注意:多個(gè)表交叉連接時(shí),在 FROM 后連續(xù)使用 CROSS JOIN 或,即可妻导。以上兩種語(yǔ)法的返回結(jié)果是相同的逛绵,但是第一種語(yǔ)法才是官方建議的標(biāo)準(zhǔn)寫法

當(dāng)連接的表之間沒(méi)有關(guān)系時(shí)倔韭,我們會(huì)省略掉 WHERE 子句术浪,這時(shí)返回結(jié)果就是兩個(gè)表的笛卡爾積,返回結(jié)果數(shù)量就是兩個(gè)表的數(shù)據(jù)行相乘寿酌。需要注意的是胰苏,如果每個(gè)表有 1000 行,那么返回結(jié)果的數(shù)量就有 1000×1000 = 1000000 行醇疼,數(shù)據(jù)量是非常巨大的硕并。

交叉連接可以查詢兩個(gè)或兩個(gè)以上的表,為了讓讀者更好的理解秧荆,下面先講解兩個(gè)表的交叉連接查詢倔毙。

例子:查詢學(xué)生信息表和科目信息表,并得到一個(gè)笛卡爾積辰如。

為了方便觀察學(xué)生信息表和科目表交叉連接后的運(yùn)行結(jié)果普监,我們先分別查詢出這兩個(gè)表的數(shù)據(jù),再進(jìn)行交叉連接查詢。

1)查詢 tb_students_info 表中的數(shù)據(jù)凯正,SQL 語(yǔ)句和運(yùn)行結(jié)果如下:

mysql> SELECT * FROM tb_students_info;
+----+--------+------+------+--------+-----------+
| id | name   | age  | sex  | height | course_id |
+----+--------+------+------+--------+-----------+
|  1 | Dany   |   25 | 男   |    160 |         1 |
|  2 | Green  |   23 | 男   |    158 |         2 |
|  3 | Henry  |   23 | 女   |    185 |         1 |
|  4 | Jane   |   22 | 男   |    162 |         3 |
|  5 | Jim    |   24 | 女   |    175 |         2 |
|  6 | John   |   21 | 女   |    172 |         4 |
|  7 | Lily   |   22 | 男   |    165 |         4 |
|  8 | Susan  |   23 | 男   |    170 |         5 |
|  9 | Thomas |   22 | 女   |    178 |         5 |
| 10 | Tom    |   23 | 女   |    165 |         5 |
+----+--------+------+------+--------+-----------+
10 rows in set (0.00 sec)

2)查詢 tb_course 表中的數(shù)據(jù)毙玻,SQL 語(yǔ)句和運(yùn)行結(jié)果如下:

mysql> SELECT * FROM tb_course;
+----+-------------+
| id | course_name |
+----+-------------+
|  1 | Java        |
|  2 | MySQL       |
|  3 | Python      |
|  4 | Go          |
|  5 | C++         |
+----+-------------+
5 rows in set (0.00 sec)

3)使用 CROSS JOIN 查詢出兩張表中的笛卡爾積,SQL 語(yǔ)句和運(yùn)行結(jié)果如下:

mysql> SELECT * FROM tb_course CROSS JOIN tb_students_info;
+----+-------------+----+--------+------+------+--------+-----------+
| id | course_name | id | name   | age  | sex  | height | course_id |
+----+-------------+----+--------+------+------+--------+-----------+
|  1 | Java        |  1 | Dany   |   25 | 男   |    160 |         1 |
|  2 | MySQL       |  1 | Dany   |   25 | 男   |    160 |         1 |
|  3 | Python      |  1 | Dany   |   25 | 男   |    160 |         1 |
|  4 | Go          |  1 | Dany   |   25 | 男   |    160 |         1 |
|  5 | C++         |  1 | Dany   |   25 | 男   |    160 |         1 |
|  1 | Java        |  2 | Green  |   23 | 男   |    158 |         2 |
|  2 | MySQL       |  2 | Green  |   23 | 男   |    158 |         2 |
|  3 | Python      |  2 | Green  |   23 | 男   |    158 |         2 |
|  4 | Go          |  2 | Green  |   23 | 男   |    158 |         2 |
|  5 | C++         |  2 | Green  |   23 | 男   |    158 |         2 |
|  1 | Java        |  3 | Henry  |   23 | 女   |    185 |         1 |
|  2 | MySQL       |  3 | Henry  |   23 | 女   |    185 |         1 |
|  3 | Python      |  3 | Henry  |   23 | 女   |    185 |         1 |
|  4 | Go          |  3 | Henry  |   23 | 女   |    185 |         1 |
|  5 | C++         |  3 | Henry  |   23 | 女   |    185 |         1 |
|  1 | Java        |  4 | Jane   |   22 | 男   |    162 |         3 |
|  2 | MySQL       |  4 | Jane   |   22 | 男   |    162 |         3 |
|  3 | Python      |  4 | Jane   |   22 | 男   |    162 |         3 |
|  4 | Go          |  4 | Jane   |   22 | 男   |    162 |         3 |
|  5 | C++         |  4 | Jane   |   22 | 男   |    162 |         3 |
|  1 | Java        |  5 | Jim    |   24 | 女   |    175 |         2 |
|  2 | MySQL       |  5 | Jim    |   24 | 女   |    175 |         2 |
|  3 | Python      |  5 | Jim    |   24 | 女   |    175 |         2 |
|  4 | Go          |  5 | Jim    |   24 | 女   |    175 |         2 |
|  5 | C++         |  5 | Jim    |   24 | 女   |    175 |         2 |
|  1 | Java        |  6 | John   |   21 | 女   |    172 |         4 |
|  2 | MySQL       |  6 | John   |   21 | 女   |    172 |         4 |
|  3 | Python      |  6 | John   |   21 | 女   |    172 |         4 |
|  4 | Go          |  6 | John   |   21 | 女   |    172 |         4 |
|  5 | C++         |  6 | John   |   21 | 女   |    172 |         4 |
|  1 | Java        |  7 | Lily   |   22 | 男   |    165 |         4 |
|  2 | MySQL       |  7 | Lily   |   22 | 男   |    165 |         4 |
|  3 | Python      |  7 | Lily   |   22 | 男   |    165 |         4 |
|  4 | Go          |  7 | Lily   |   22 | 男   |    165 |         4 |
|  5 | C++         |  7 | Lily   |   22 | 男   |    165 |         4 |
|  1 | Java        |  8 | Susan  |   23 | 男   |    170 |         5 |
|  2 | MySQL       |  8 | Susan  |   23 | 男   |    170 |         5 |
|  3 | Python      |  8 | Susan  |   23 | 男   |    170 |         5 |
|  4 | Go          |  8 | Susan  |   23 | 男   |    170 |         5 |
|  5 | C++         |  8 | Susan  |   23 | 男   |    170 |         5 |
|  1 | Java        |  9 | Thomas |   22 | 女   |    178 |         5 |
|  2 | MySQL       |  9 | Thomas |   22 | 女   |    178 |         5 |
|  3 | Python      |  9 | Thomas |   22 | 女   |    178 |         5 |
|  4 | Go          |  9 | Thomas |   22 | 女   |    178 |         5 |
|  5 | C++         |  9 | Thomas |   22 | 女   |    178 |         5 |
|  1 | Java        | 10 | Tom    |   23 | 女   |    165 |         5 |
|  2 | MySQL       | 10 | Tom    |   23 | 女   |    165 |         5 |
|  3 | Python      | 10 | Tom    |   23 | 女   |    165 |         5 |
|  4 | Go          | 10 | Tom    |   23 | 女   |    165 |         5 |
|  5 | C++         | 10 | Tom    |   23 | 女   |    165 |         5 |
+----+-------------+----+--------+------+------+--------+-----------+
50 rows in set (0.00 sec)

由運(yùn)行結(jié)果可以看出廊散,tb_course 和 tb_students_info 表交叉連接查詢后桑滩,返回了 50 條記錄≡识茫可以想象运准,當(dāng)表中的數(shù)據(jù)較多時(shí),得到的運(yùn)行結(jié)果會(huì)非常長(zhǎng)缭受,而且得到的運(yùn)行結(jié)果也沒(méi)太大的意義胁澳。所以,通過(guò)交叉連接的方式進(jìn)行多表查詢的這種方法并不常用米者,我們應(yīng)該盡量避免這種查詢韭畸。

注意:在 MySQL 中,多表查詢一般使用內(nèi)連接和外連接蔓搞,它們的效率要高于交叉連接胰丁。

MySQL 內(nèi)連接

內(nèi)連接(INNER JOIN)主要通過(guò)設(shè)置連接條件的方式,來(lái)移除查詢結(jié)果中某些數(shù)據(jù)行的交叉連接喂分。簡(jiǎn)單來(lái)說(shuō)锦庸,利用條件表達(dá)式來(lái)消除交叉連接的某些數(shù)據(jù)行。

內(nèi)連接用 INNER JOIN 關(guān)鍵字連接兩張表蒲祈,使用ON子句來(lái)設(shè)置連接條件甘萧。如果沒(méi)有連接條件,INNER JOIN 和 CROSS JOIN 在語(yǔ)法上是等同的讳嘱,兩者可以互換幔嗦。

內(nèi)連接的語(yǔ)法格式如下:

SELECT <字段名> FROM <表1> INNER JOIN <表2> [ON子句]

語(yǔ)法說(shuō)明如下。

  • 字段名:需要查詢的字段名稱沥潭。
  • <表1><表2>:需要內(nèi)連接的表名邀泉。
  • INNER JOIN :內(nèi)連接中可以省略 INNER 關(guān)鍵字,只用關(guān)鍵字 JOIN钝鸽。
  • ON 子句:用來(lái)設(shè)置內(nèi)連接的連接條件汇恤。

注意:INNER JOIN 也可以使用 WHERE 子句指定連接條件,但是 INNER JOIN ... ON 語(yǔ)法是官方的標(biāo)準(zhǔn)寫法拔恰,而且 WHERE 子句在某些時(shí)候會(huì)影響查詢的性能因谎。

多個(gè)表內(nèi)連接時(shí),在 FROM 后連續(xù)使用 INNER JOIN 或 JOIN 即可颜懊。

內(nèi)連接可以查詢兩個(gè)或兩個(gè)以上的表财岔。為了讓大家更好的理解风皿,暫時(shí)只講解兩個(gè)表的連接查詢。

例子:在 tb_students_info 表和 tb_course 表之間匠璧,使用內(nèi)連接查詢學(xué)生姓名和相對(duì)應(yīng)的課程名稱桐款,SQL 語(yǔ)句和運(yùn)行結(jié)果如下。

mysql> SELECT s.name,c.course_name FROM tb_students_info s INNER JOIN tb_course c 
    -> ON s.course_id = c.id;
+--------+-------------+
| name   | course_name |
+--------+-------------+
| Dany   | Java        |
| Green  | MySQL       |
| Henry  | Java        |
| Jane   | Python      |
| Jim    | MySQL       |
| John   | Go          |
| Lily   | Go          |
| Susan  | C++         |
| Thomas | C++         |
| Tom    | C++         |
+--------+-------------+
10 rows in set (0.00 sec)

在這里的查詢語(yǔ)句中夷恍,兩個(gè)表之間的關(guān)系通過(guò) INNER JOIN 指定魔眨,連接的條件使用 ON 子句給出。

注意:當(dāng)對(duì)多個(gè)表進(jìn)行查詢時(shí)酿雪,要在 SELECT 語(yǔ)句后面指定字段是來(lái)源于哪一張表遏暴。因此,在多表查詢時(shí)指黎,SELECT 語(yǔ)句后面的寫法是表名.列名朋凉。另外,如果表名非常長(zhǎng)的話袋励,也可以給表設(shè)置別名侥啤,這樣就可以直接在 SELECT 語(yǔ)句后面寫上表的別名.列名当叭。

MySQL 左外連接

內(nèi)連接的查詢結(jié)果都是符合連接條件的記錄茬故,而外連接會(huì)先將連接的表分為基表和參考表,再以基表為依據(jù)返回滿足和不滿足條件的記錄蚁鳖。

左外連接又稱為左連接磺芭,使用 LEFT OUTER JOIN 關(guān)鍵字連接兩個(gè)表,并使用 ON 子句來(lái)設(shè)置連接條件醉箕。

左連接的語(yǔ)法格式如下:

SELECT <字段名> FROM <表1> LEFT OUTER JOIN <表2> <ON子句>

語(yǔ)法說(shuō)明如下钾腺。

  • 字段名:需要查詢的字段名稱。
  • <表1><表2>:需要左連接的表名讥裤。
  • LEFT OUTER JOIN:左連接中可以省略 OUTER 關(guān)鍵字放棒,只使用關(guān)鍵字 LEFT JOIN。
  • ON 子句:用來(lái)設(shè)置左連接的連接條件己英,不能省略间螟。

上述語(yǔ)法中,“表1”為基表损肛,“表2”為參考表厢破。左連接查詢時(shí),可以查詢出“表1”中的所有記錄和“表2”中匹配連接條件的記錄治拿。如果“表1”的某行在“表2”中沒(méi)有匹配行摩泪,那么在返回結(jié)果中,“表2”的字段值均為空值(NULL)劫谅。

例子:在進(jìn)行左連接查詢之前见坑,我們先查看 tb_course 和 tb_students_info 兩張表中的數(shù)據(jù)嚷掠。SQL 語(yǔ)句和運(yùn)行結(jié)果如下。

mysql> SELECT * FROM tb_course;
+----+-------------+
| id | course_name |
+----+-------------+
|  1 | Java        |
|  2 | MySQL       |
|  3 | Python      |
|  4 | Go          |
|  5 | C++         |
|  6 | HTML        |
+----+-------------+
6 rows in set (0.00 sec)

mysql> SELECT * FROM tb_students_info;
+----+--------+------+------+--------+-----------+
| id | name   | age  | sex  | height | course_id |
+----+--------+------+------+--------+-----------+
|  1 | Dany   |   25 | 男   |    160 |         1 |
|  2 | Green  |   23 | 男   |    158 |         2 |
|  3 | Henry  |   23 | 女   |    185 |         1 |
|  4 | Jane   |   22 | 男   |    162 |         3 |
|  5 | Jim    |   24 | 女   |    175 |         2 |
|  6 | John   |   21 | 女   |    172 |         4 |
|  7 | Lily   |   22 | 男   |    165 |         4 |
|  8 | Susan  |   23 | 男   |    170 |         5 |
|  9 | Thomas |   22 | 女   |    178 |         5 |
| 10 | Tom    |   23 | 女   |    165 |         5 |
| 11 | LiMing |   22 | 男   |    180 |         7 |
+----+--------+------+------+--------+-----------+
11 rows in set (0.00 sec)

在 tb_students_info 表和 tb_course 表中查詢所有學(xué)生姓名和相對(duì)應(yīng)的課程名稱荞驴,包括沒(méi)有課程的學(xué)生叠国,SQL 語(yǔ)句和運(yùn)行結(jié)果如下。

mysql> SELECT s.name,c.course_name FROM tb_students_info s LEFT OUTER JOIN tb_course c 
    -> ON s.`course_id`=c.`id`;
+--------+-------------+
| name   | course_name |
+--------+-------------+
| Dany   | Java        |
| Henry  | Java        |
| NULL   | Java        |
| Green  | MySQL       |
| Jim    | MySQL       |
| Jane   | Python      |
| John   | Go          |
| Lily   | Go          |
| Susan  | C++         |
| Thomas | C++         |
| Tom    | C++         |
| LiMing | NULL        |
+--------+-------------+
12 rows in set (0.00 sec)

可以看到戴尸,運(yùn)行結(jié)果顯示了 12 條記錄粟焊,name 為 LiMing 的學(xué)生目前沒(méi)有課程,因?yàn)閷?duì)應(yīng)的 tb_course 表中沒(méi)有該學(xué)生的課程信息孙蒙,所以該條記錄只取出了 tb_students_info 表中相應(yīng)的值项棠,而從 tb_course 表中取出的值為 NULL。

MySQL 右外連接

內(nèi)連接的查詢結(jié)果都是符合連接條件的記錄挎峦,而外連接會(huì)先將連接的表分為基表和參考表香追,再以基表為依據(jù)返回滿足和不滿足條件的記錄。

右外連接又稱為右連接坦胶,右連接是左連接的反向連接透典。使用 RIGHT OUTER JOIN 關(guān)鍵字連接兩個(gè)表,并使用 ON 子句來(lái)設(shè)置連接條件顿苇。

右連接的語(yǔ)法格式如下:

SELECT <字段名> FROM <表1> RIGHT OUTER JOIN <表2> <ON子句>

語(yǔ)法說(shuō)明如下峭咒。

  • 字段名:需要查詢的字段名稱。
  • <表1><表2>:需要右連接的表名纪岁。
  • RIGHT OUTER JOIN:右連接中可以省略 OUTER 關(guān)鍵字凑队,只使用關(guān)鍵字 RIGHT JOIN。
  • ON 子句:用來(lái)設(shè)置右連接的連接條件幔翰,不能省略漩氨。

與左連接相反,右連接以“表2”為基表遗增,“表1”為參考表叫惊。右連接查詢時(shí),可以查詢出“表2”中的所有記錄和“表1”中匹配連接條件的記錄做修。如果“表2”的某行在“表1”中沒(méi)有匹配行霍狰,那么在返回結(jié)果中,“表1”的字段值均為空值(NULL)缓待。

例子:在 tb_students_info 表和 tb_course 表中查詢所有課程蚓耽,包括沒(méi)有學(xué)生的課程,SQL 語(yǔ)句和運(yùn)行結(jié)果如下旋炒。

mysql> SELECT s.name,c.course_name FROM tb_students_info s RIGHT OUTER JOIN tb_course c 
    -> ON s.`course_id`=c.`id`;
+--------+-------------+
| name   | course_name |
+--------+-------------+
| Dany   | Java        |
| Green  | MySQL       |
| Henry  | Java        |
| Jane   | Python      |
| Jim    | MySQL       |
| John   | Go          |
| Lily   | Go          |
| Susan  | C++         |
| Thomas | C++         |
| Tom    | C++         |
| NULL   | HTML        |
+--------+-------------+
11 rows in set (0.00 sec)

可以看到步悠,結(jié)果顯示了 11 條記錄,名稱為 HTML 的課程目前沒(méi)有學(xué)生瘫镇,因?yàn)閷?duì)應(yīng)的 tb_students_info 表中并沒(méi)有該學(xué)生的信息鼎兽,所以該條記錄只取出了 tb_course 表中相應(yīng)的值答姥,而從 tb_students_info 表中取出的值為 NULL。

注意:多個(gè)表左/右連接時(shí)谚咬,在 ON 子句后連續(xù)使用 LEFT/RIGHT OUTER JOIN 或 LEFT/RIGHT JOIN 即可鹦付。

使用外連接查詢時(shí),一定要分清需要查詢的結(jié)果择卦,是需要顯示左表的全部記錄還是右表的全部記錄敲长,然后選擇相應(yīng)的左連接和右連接。

MySQL子查詢

子查詢是 MySQL 中比較常用的查詢方法秉继,通過(guò)子查詢可以實(shí)現(xiàn)多表查詢祈噪。子查詢指將一個(gè)查詢語(yǔ)句嵌套在另一個(gè)查詢語(yǔ)句中。子查詢可以在 SELECT尚辑、UPDATE 和 DELETE 語(yǔ)句中使用辑鲤,而且可以進(jìn)行多層嵌套。在實(shí)際開(kāi)發(fā)時(shí)杠茬,子查詢經(jīng)常出現(xiàn)在 WHERE 子句中月褥。

子查詢?cè)?WHERE 中的語(yǔ)法格式如下:

WHERE <表達(dá)式> <操作符> (子查詢)

其中,操作符可以是比較運(yùn)算符和 IN瓢喉、NOT IN宁赤、EXISTS、NOT EXISTS 等關(guān)鍵字灯荧。

IN | NOT IN

當(dāng)表達(dá)式與子查詢返回的結(jié)果集中的某個(gè)值相等時(shí)礁击,返回 TRUE,否則返回 FALSE逗载;若使用關(guān)鍵字 NOT,則返回值正好相反链烈。

EXISTS | NOT EXISTS

用于判斷子查詢的結(jié)果集是否為空厉斟,若子查詢的結(jié)果集不為空,返回 TRUE强衡,否則返回 FALSE擦秽;若使用關(guān)鍵字 NOT,則返回的值正好相反漩勤。

實(shí)例演示

例子:使用子查詢?cè)?tb_students_info 表和 tb_course 表中查詢學(xué)習(xí) Java 課程的學(xué)生姓名感挥,SQL 語(yǔ)句和運(yùn)行結(jié)果如下。

mysql> SELECT name FROM tb_students_info 
    -> WHERE course_id IN (SELECT id FROM tb_course WHERE course_name = 'Java');
+-------+
| name  |
+-------+
| Dany  |
| Henry |
+-------+
2 rows in set (0.01 sec)

結(jié)果顯示越败,學(xué)習(xí) Java 課程的只有 Dany 和 Henry触幼。上述查詢過(guò)程也可以分為以下 2 步執(zhí)行,實(shí)現(xiàn)效果是相同的究飞。

1)首先單獨(dú)執(zhí)行內(nèi)查詢置谦,查詢出 tb_course 表中課程為 Java 的 id堂鲤,SQL 語(yǔ)句和運(yùn)行結(jié)果如下。

mysql> SELECT id FROM tb_course 
    -> WHERE course_name = 'Java';
+----+
| id |
+----+
|  1 |
+----+
1 row in set (0.00 sec)

可以看到媒峡,符合條件的 id 字段的值為 1瘟栖。

2)然后執(zhí)行外層查詢,在 tb_students_info 表中查詢 course_id 等于 1 的學(xué)生姓名谅阿。SQL 語(yǔ)句和運(yùn)行結(jié)果如下半哟。

mysql> SELECT name FROM tb_students_info 
    -> WHERE course_id IN (1);
+-------+
| name  |
+-------+
| Dany  |
| Henry |
+-------+
2 rows in set (0.00 sec)

習(xí)慣上,外層的 SELECT 查詢稱為父查詢签餐,圓括號(hào)中嵌入的查詢稱為子查詢(子查詢必須放在圓括號(hào)內(nèi))镜沽。MySQL 在處理上例的 SELECT 語(yǔ)句時(shí),執(zhí)行流程為:先執(zhí)行子查詢贱田,再執(zhí)行父查詢缅茉。

注意:not in 與 in 一樣,返回的值相反男摧。

例子:使用=運(yùn)算符蔬墩,在 tb_course 表和 tb_students_info 表中查詢出所有學(xué)習(xí) Python 課程的學(xué)生姓名,SQL 語(yǔ)句和運(yùn)行結(jié)果如下耗拓。

mysql> SELECT name FROM tb_students_info
    -> WHERE course_id = (SELECT id FROM tb_course WHERE course_name = 'Python');
+------+
| name |
+------+
| Jane |
+------+
1 row in set (0.00 sec)

結(jié)果顯示拇颅,學(xué)習(xí) Python 課程的學(xué)生只有 Jane。

注意:使用<>運(yùn)算符乔询,和 = 一樣樟插,結(jié)果剛好相反。

例子:查詢 tb_course 表中是否存在 id=1 的課程竿刁,如果存在黄锤,就查詢出 tb_students_info 表中的記錄,SQL 語(yǔ)句和運(yùn)行結(jié)果如下食拜。

mysql> SELECT * FROM tb_students_info
    -> WHERE EXISTS(SELECT course_name FROM tb_course WHERE id=1);
+----+--------+------+------+--------+-----------+
| id | name   | age  | sex  | height | course_id |
+----+--------+------+------+--------+-----------+
|  1 | Dany   |   25 | 男   |    160 |         1 |
|  2 | Green  |   23 | 男   |    158 |         2 |
|  3 | Henry  |   23 | 女   |    185 |         1 |
|  4 | Jane   |   22 | 男   |    162 |         3 |
|  5 | Jim    |   24 | 女   |    175 |         2 |
|  6 | John   |   21 | 女   |    172 |         4 |
|  7 | Lily   |   22 | 男   |    165 |         4 |
|  8 | Susan  |   23 | 男   |    170 |         5 |
|  9 | Thomas |   22 | 女   |    178 |         5 |
| 10 | Tom    |   23 | 女   |    165 |         5 |
| 11 | LiMing |   22 | 男   |    180 |         7 |
+----+--------+------+------+--------+-----------+
11 rows in set (0.01 sec)

由結(jié)果可以看到鸵熟,tb_course 表中存在 id=1 的記錄,因此 EXISTS 表達(dá)式返回 TRUE负甸,外層查詢語(yǔ)句接收 TRUE 之后對(duì)表 tb_students_info 進(jìn)行查詢流强,返回所有的記錄。

EXISTS 關(guān)鍵字可以和其它查詢條件一起使用呻待,條件表達(dá)式與 EXISTS 關(guān)鍵字之間用 AND 和 OR 連接打月。

子查詢的功能也可以通過(guò)表連接完成,但是子查詢會(huì)使 SQL 語(yǔ)句更容易閱讀和編寫蚕捉。

一般來(lái)說(shuō)奏篙,表連接(內(nèi)連接和外連接等)都可以用子查詢替換,但反過(guò)來(lái)卻不一定鱼冀,有的子查詢不能用表連接來(lái)替換报破。子查詢比較靈活悠就、方便、形式多樣充易,適合作為查詢的篩選條件梗脾,而表連接更適合于查看連接表的數(shù)據(jù)。

MySQL子查詢注意事項(xiàng)

在完成較復(fù)雜的數(shù)據(jù)查詢時(shí)盹靴,經(jīng)常會(huì)使用到子查詢炸茧,編寫子查詢語(yǔ)句時(shí),要注意如下事項(xiàng)稿静。

子查詢語(yǔ)句可以嵌套在 SQL 語(yǔ)句中任何表達(dá)式出現(xiàn)的位置

在 SELECT 語(yǔ)句中梭冠,子查詢可以被嵌套在 SELECT 語(yǔ)句的列、表和查詢條件中改备,即 SELECT 子句控漠,F(xiàn)ROM 子句、WHERE 子句悬钳、GROUP BY 子句和 HAVING 子句盐捷。

前面已經(jīng)介紹了 WHERE 子句中嵌套子查詢的使用方法,下面是子查詢?cè)?SELECT 子句和 FROM 子句中的使用語(yǔ)法默勾。

嵌套在 SELECT 語(yǔ)句的 SELECT 子句中的子查詢語(yǔ)法格式如下碉渡。

SELECT (子查詢) FROM 表名;

提示:子查詢結(jié)果為單行單列,但不必指定列別名母剥。

嵌套在 SELECT 語(yǔ)句的 FROM 子句中的子查詢語(yǔ)法格式如下滞诺。

SELECT * FROM (子查詢) AS 表的別名;

注意:必須為表指定別名。一般返回多行多列數(shù)據(jù)記錄环疼,可以當(dāng)作一張臨時(shí)表习霹。

只出現(xiàn)在子查詢中而沒(méi)有出現(xiàn)在父查詢中的表不能包含在輸出列中

多層嵌套子查詢的最終數(shù)據(jù)集只包含父查詢(即最外層的查詢)的 SELECT 子句中出現(xiàn)的字段,而子查詢的輸出結(jié)果通常會(huì)作為其外層子查詢數(shù)據(jù)源或用于數(shù)據(jù)判斷匹配秦爆。

常見(jiàn)錯(cuò)誤如下:

SELECT * FROM (SELECT * FROM result);

這個(gè)子查詢語(yǔ)句產(chǎn)生語(yǔ)法錯(cuò)誤的原因在于主查詢語(yǔ)句的 FROM 子句是一個(gè)子查詢語(yǔ)句序愚,因此應(yīng)該為子查詢結(jié)果集指定別名。正確代碼如下等限。

SELECT * FROM (SELECT * FROM result) AS Temp;

MySQL 插入數(shù)據(jù)

數(shù)據(jù)庫(kù)與表創(chuàng)建成功以后,需要向數(shù)據(jù)庫(kù)的表中插入數(shù)據(jù)芬膝。在 MySQL 中可以使用 INSERT 語(yǔ)句向數(shù)據(jù)庫(kù)已有的表中插入一行或者多行元組數(shù)據(jù)望门。

基本語(yǔ)法

INSERT 語(yǔ)句有兩種語(yǔ)法形式,分別是 INSERT…VALUES 語(yǔ)句和 INSERT…SET 語(yǔ)句锰霜。

INSERT…VALUES語(yǔ)句

INSERT VALUES 的語(yǔ)法格式為:

INSERT INTO <表名> [ <列名1> [ , … <列名n>] ]
VALUES (值1) [… , (值n) ];

語(yǔ)法說(shuō)明如下筹误。

  • <表名>:指定被操作的表名。
  • <列名>:指定需要插入數(shù)據(jù)的列名癣缅。若向表中的所有列插入數(shù)據(jù)厨剪,則全部的列名均可以省略哄酝,直接采用 INSERT<表名>VALUES(…) 即可。
  • VALUESVALUE 子句:該子句包含要插入的數(shù)據(jù)清單祷膳。數(shù)據(jù)清單中數(shù)據(jù)的順序要和列的順序相對(duì)應(yīng)陶衅。

INSERT…SET語(yǔ)句

語(yǔ)法格式為:

INSERT INTO <表名>
SET <列名1> = <值1>,
    <列名2> = <值2>,
    …

此語(yǔ)句用于直接給表中的某些列指定對(duì)應(yīng)的列值,即要插入的數(shù)據(jù)的列名在 SET 子句中指定直晨,col_name 為指定的列名搀军,等號(hào)后面為指定的數(shù)據(jù),而對(duì)于未指定的列勇皇,列值會(huì)指定為該列的默認(rèn)值罩句。

由 INSERT 語(yǔ)句的兩種形式可以看出:

  • 使用 INSERT…VALUES 語(yǔ)句可以向表中插入一行數(shù)據(jù)殴俱,也可以插入多行數(shù)據(jù)灭贷;
  • 使用 INSERT…SET 語(yǔ)句可以指定插入行中每列的值,也可以指定部分列的值逛球;
  • INSERT…SELECT 語(yǔ)句向表中插入其他表的數(shù)據(jù)兄淫。
  • 采用 INSERT…SET 語(yǔ)句可以向表中插入部分列的值屯远,這種方式更為靈活;
  • INSERT…VALUES 語(yǔ)句可以一次插入多條數(shù)據(jù)拖叙。

在 MySQL 中氓润,用單條 INSERT 語(yǔ)句處理多個(gè)插入要比使用多條 INSERT 語(yǔ)句更快。

當(dāng)使用單條 INSERT 語(yǔ)句插入多行數(shù)據(jù)的時(shí)候薯鳍,只需要將每行數(shù)據(jù)用圓括號(hào)括起來(lái)即可咖气。

新增表數(shù)據(jù)

插入數(shù)據(jù)時(shí),INSERT 語(yǔ)句后面的列名稱順序可以不需要按照表定義的順序插入挖滤,只要保證值的順序與列字段的順序相同就可以崩溪。

使用 INSERT 插入數(shù)據(jù)時(shí),允許列名稱列表 column_list 為空斩松,此時(shí)值列表中需要為表的每一個(gè)字段指定值伶唯,值的順序必須和數(shù)據(jù)表中字段定義時(shí)的順序相同。

INSERT 語(yǔ)句中沒(méi)有指定插入列表惧盹,只有一個(gè)值列表乳幸。在這種情況下,值列表為每一個(gè)字段列指定插入的值钧椰,并且這些值的順序必須和 tb_courses 表中字段定義的順序相同粹断。

注意:雖然使用 INSERT 插入數(shù)據(jù)時(shí)可以忽略插入數(shù)據(jù)的列名稱,若值不包含列名稱嫡霞,則 VALUES 關(guān)鍵字后面的值不僅要求完整瓶埋,而且順序必須和表定義時(shí)列的順序相同。如果表的結(jié)構(gòu)被修改,對(duì)列進(jìn)行增加养筒、刪除或者位置改變操作曾撤,這些操作將使得用這種方式插入數(shù)據(jù)時(shí)的順序也同時(shí)改變。如果指定列名稱晕粪,就不會(huì)受到表結(jié)構(gòu)改變的影響挤悉。

復(fù)制表數(shù)據(jù)

INSERT INTO…SELECT…FROM 語(yǔ)句用于快速地從一個(gè)或多個(gè)表中取出數(shù)據(jù),并將這些數(shù)據(jù)作為行數(shù)據(jù)插入另一個(gè)表中兵多。

SELECT 返回的是一個(gè)查詢到的結(jié)果集尖啡,INSERT 語(yǔ)句將這個(gè)結(jié)果集插入指定表中,結(jié)果集中的每行數(shù)據(jù)的字段數(shù)剩膘、字段的數(shù)據(jù)類型都必須與被操作的表完全一致衅斩。

MySQL 修改數(shù)據(jù)

在 MySQL 中,可以使用 UPDATE 語(yǔ)句來(lái)修改怠褐、更新一個(gè)或多個(gè)表的數(shù)據(jù)畏梆。

基本語(yǔ)法

使用 UPDATE 語(yǔ)句修改單個(gè)表,語(yǔ)法格式為:

UPDATE <表名> SET 字段 1=值 1 [,字段 2=值 2… ] [WHERE 子句 ]
[ORDER BY 子句] [LIMIT 子句]

語(yǔ)法說(shuō)明如下:

  • <表名>:用于指定要更新的表名稱奈懒。
  • SET 子句:用于指定表中要修改的列名及其列值奠涌。其中,每個(gè)指定的列值可以是表達(dá)式磷杏,也可以是該列對(duì)應(yīng)的默認(rèn)值溜畅。如果指定的是默認(rèn)值,可用關(guān)鍵字 DEFAULT 表示列值极祸。
  • WHERE 子句:可選項(xiàng)慈格。用于限定表中要修改的行。若不指定遥金,則修改表中所有的行浴捆。
  • ORDER BY 子句:可選項(xiàng)。用于限定表中的行被修改的次序稿械。
  • LIMIT 子句:可選項(xiàng)选泻。用于限定被修改的行數(shù)。

注意:修改一行數(shù)據(jù)的多個(gè)列值時(shí)美莫,SET 子句的每個(gè)值用逗號(hào)分開(kāi)即可页眯。

修改表中的數(shù)據(jù)

UPDATE <表名> SET 字段 1=值 1 [,字段 2=值 2… ]

根據(jù)條件修改表中的數(shù)據(jù)

UPDATE <表名> SET 字段 1=值 1 [,字段 2=值 2… ] [WHERE 子句 ]

注意:保證 UPDATE 以 WHERE 子句結(jié)束,通過(guò) WHERE 子句指定被更新的記錄所需要滿足的條件厢呵,如果忽略 WHERE 子句餐茵,MySQL 將更新表中所有的行。

MySQL 刪除數(shù)據(jù)

在 MySQL 中述吸,可以使用 DELETE 語(yǔ)句來(lái)刪除表的一行或者多行數(shù)據(jù)

刪除單個(gè)表中的數(shù)據(jù)

使用 DELETE 語(yǔ)句從單個(gè)表中刪除數(shù)據(jù),語(yǔ)法格式為:

DELETE FROM <表名> [WHERE 子句] [ORDER BY 子句] [LIMIT 子句]

語(yǔ)法說(shuō)明如下:

  • <表名>:指定要?jiǎng)h除數(shù)據(jù)的表名蝌矛。
  • ORDER BY 子句:可選項(xiàng)道批。表示刪除時(shí),表中各行將按照子句中指定的順序進(jìn)行刪除入撒。
  • WHERE 子句:可選項(xiàng)隆豹。表示為刪除操作限定刪除條件,若省略該子句茅逮,則代表刪除該表中的所有行璃赡。
  • LIMIT 子句:可選項(xiàng)。用于告知服務(wù)器在控制命令被返回到客戶端前被刪除行的最大值献雅。

注意:在不使用 WHERE 條件的時(shí)候碉考,將刪除所有數(shù)據(jù)。

刪除表中的全部數(shù)據(jù)

DELETE FROM <表名>

根據(jù)條件刪除表中的數(shù)據(jù)

DELETE FROM <表名> [WHERE 子句] 

MySQL 清空表記錄

MySQL 提供了 DELETE 和 TRUNCATE 關(guān)鍵字來(lái)刪除表中的數(shù)據(jù)挺身。

TRUNCATE 關(guān)鍵字用于完全清空一個(gè)表侯谁。其語(yǔ)法格式如下:

TRUNCATE [TABLE] 表名

其中,TABLE 關(guān)鍵字可省略章钾。

TRUNCATE 和 DELETE 的區(qū)別

從邏輯上說(shuō)墙贱,TRUNCATE 語(yǔ)句與 DELETE 語(yǔ)句作用相同,但是在某些情況下贱傀,兩者在使用上有所區(qū)別惨撇。

  • DELETE 是 DML 類型的語(yǔ)句;TRUNCATE 是 DDL 類型的語(yǔ)句府寒。它們都用來(lái)清空表中的數(shù)據(jù)魁衙。
  • DELETE 是逐行一條一條刪除記錄的;TRUNCATE 則是直接刪除原來(lái)的表椰棘,再重新創(chuàng)建一個(gè)一模一樣的新表纺棺,而不是逐行刪除表中的數(shù)據(jù),執(zhí)行數(shù)據(jù)比 DELETE 快邪狞。因此需要?jiǎng)h除表中全部的數(shù)據(jù)行時(shí)祷蝌,盡量使用 TRUNCATE 語(yǔ)句, 可以縮短執(zhí)行時(shí)間帆卓。
  • DELETE 刪除數(shù)據(jù)后巨朦,配合事件回滾可以找回?cái)?shù)據(jù);TRUNCATE 不支持事務(wù)的回滾剑令,數(shù)據(jù)刪除后無(wú)法找回糊啡。
  • DELETE 刪除數(shù)據(jù)后,系統(tǒng)不會(huì)重新設(shè)置自增字段的計(jì)數(shù)器吁津;TRUNCATE 清空表記錄后棚蓄,系統(tǒng)會(huì)重新設(shè)置自增字段的計(jì)數(shù)器堕扶。
  • DELETE 的使用范圍更廣,因?yàn)樗梢酝ㄟ^(guò) WHERE 子句指定條件來(lái)刪除部分?jǐn)?shù)據(jù)梭依;而 TRUNCATE 不支持 WHERE 子句稍算,只能刪除整體。
  • DELETE 會(huì)返回刪除數(shù)據(jù)的行數(shù)役拴,但是 TRUNCATE 只會(huì)返回 0糊探,沒(méi)有任何意義。

當(dāng)不需要該表時(shí)河闰,用 DROP科平;當(dāng)仍要保留該表,但要?jiǎng)h除所有記錄時(shí)姜性,用 TRUNCATE瞪慧;當(dāng)要?jiǎng)h除部分記錄時(shí),用 DELETE污抬。

MySQL處理無(wú)效數(shù)據(jù)值

MySQL處理數(shù)據(jù)的基本原則是“垃圾進(jìn)來(lái)汞贸,垃圾出去”,通俗一點(diǎn)說(shuō)就是你傳給 MySQL 什么樣的數(shù)據(jù)印机,它就會(huì)存儲(chǔ)什么樣的數(shù)據(jù)矢腻。如果在存儲(chǔ)數(shù)據(jù)時(shí)沒(méi)有對(duì)它們進(jìn)行驗(yàn)證,那么在把它們檢索出來(lái)時(shí)得到的就不一定是你所期望的內(nèi)容射赛。

有幾種 SQL 模式可以在遇到“非正扯喔蹋”值時(shí)拋出錯(cuò)誤,如果你對(duì)其他數(shù)據(jù)庫(kù)管理系統(tǒng)比較熟悉楣责,會(huì)發(fā)現(xiàn)這種行為和其他的數(shù)據(jù)庫(kù)管理系統(tǒng)很像竣灌。

下面介紹 MySQL 默認(rèn)情況下如何處理非正常數(shù)據(jù)和啟用各種 SQL 模式時(shí)會(huì)對(duì)數(shù)據(jù)處理產(chǎn)生哪些影響。

默認(rèn)情況下秆麸,MySQL 會(huì)按照以下規(guī)則來(lái)處理越界(即超出取值范圍)的值和其他非正常值:

  • 對(duì)于數(shù)值列或 TIME 列初嘹,超出合法取值范圍的那些值將被截?cái)嗟饺≈捣秶罱哪莻€(gè)端點(diǎn),并把結(jié)果值存儲(chǔ)起來(lái)沮趣。
  • 對(duì)于除 TIME 列以外的其他類型列屯烦,非法值會(huì)被轉(zhuǎn)換成與該類型一致的“零”值。
  • 對(duì)于字符串列(不包括 ENUM 或 SET)房铭,過(guò)長(zhǎng)的字符串將被截?cái)嗟皆摿械淖畲箝L(zhǎng)度驻龟。
  • 給 ENUM 或 SET 類型列進(jìn)行賦值時(shí),需要根據(jù)列定義里給出的合法取值列表進(jìn)行缸匪。如果把不是枚舉成員的值賦給 ENUM 列翁狐,那么列的值就會(huì)變成空字符串。如果把包含非集合成員的子字符串的值賦給 SET 列凌蔬,那么這些字符串會(huì)被清理露懒,剩余的成員才會(huì)被賦值給列闯冷。

如果在執(zhí)行增刪改查等語(yǔ)句時(shí)發(fā)生了上述轉(zhuǎn)換,那么 MySQL 會(huì)給出警告消息隐锭。在執(zhí)行完其中的某一條語(yǔ)句之后窃躲,可以使用 SHOW WARNINGS 語(yǔ)句來(lái)查看警告消息的內(nèi)容。

如果需要在插入或更新數(shù)據(jù)時(shí)執(zhí)行更嚴(yán)格的檢查钦睡,那么可以啟用以下兩種 SQL 模式中的一種:

SET sql_mode = 'STRICT_ALL_TABLES' ;
SET sql_mode = 'STRICT_TRANS_TABLES';

對(duì)于支持事務(wù)的表,這兩種模式都是一樣的躁倒。如果發(fā)現(xiàn)某個(gè)值無(wú)效或缺失荞怒,那么會(huì)產(chǎn)生一個(gè)錯(cuò)誤,并且語(yǔ)句會(huì)中止執(zhí)行秧秉,并進(jìn)行回滾褐桌,就像什么事都沒(méi)發(fā)生過(guò)一樣。

對(duì)于不支持事務(wù)的表象迎,這兩種模式有以下效果荧嵌。

  1. 對(duì)于這兩種模式,如果在插入或修改第一個(gè)行時(shí)砾淌,發(fā)現(xiàn)某個(gè)值無(wú)效或缺失啦撮,那么結(jié)果會(huì)產(chǎn)生一個(gè)錯(cuò)誤,語(yǔ)句會(huì)中止執(zhí)行汪厨,就像什么事都未發(fā)生過(guò)一樣赃春。 這跟事務(wù)表的行為很相似。

  2. 在用于插入或修改多個(gè)行的語(yǔ)句里劫乱,如果在第一行之后的某個(gè)行出現(xiàn)了錯(cuò)誤织中,那么會(huì)出現(xiàn)某些行被修改的情況。這兩種模式?jīng)Q定著衷戈,這條語(yǔ)句此時(shí)此刻是要停止執(zhí)行狭吼,還是要繼續(xù)執(zhí)行。

  • 在 STRICT_ALL_TABLES 模式下殖妇,會(huì)拋出一個(gè)錯(cuò)誤刁笙,并且語(yǔ)句會(huì)停止執(zhí)行。因?yàn)槭茉撜Z(yǔ)句影響的許多行都已被修改拉一,所以這將會(huì)導(dǎo)致“部分更新”問(wèn)題采盒。
  • 在 STRICT_TRANS_TABLES 模式下,對(duì)于非事務(wù)表蔚润,MySQL 會(huì)中止語(yǔ)句的執(zhí)行磅氨。只有這樣做,才能達(dá)到事務(wù)表那樣的效果嫡纠。只有當(dāng)?shù)谝恍邪l(fā)生錯(cuò)誤時(shí)烦租,才能達(dá)到這樣的效果延赌。如果錯(cuò)誤在后面的某個(gè)行上,那么就會(huì)出現(xiàn)某些行被修改的情況叉橱。由于對(duì)于非事務(wù)表挫以,那些修改是無(wú)法撤銷的,因此 MySQL 會(huì)繼續(xù)執(zhí)行該語(yǔ)句窃祝,以避免出現(xiàn)“部分更新”的問(wèn)題掐松。它會(huì)把所有的無(wú)效值轉(zhuǎn)換為與其最接近的合法值。對(duì)于缺失的值粪小,MySQL 會(huì)把該列設(shè)置成其數(shù)據(jù)類型的隱式默認(rèn)值大磺,

通過(guò)以下模式可以對(duì)輸入的數(shù)據(jù)進(jìn)行更加嚴(yán)格的檢查:

  • ERROR_ FOR_ DIVISION_ BY_ ZERO:在嚴(yán)格模式下,如果遇到以零為除數(shù)的情況探膊,它會(huì)阻止數(shù)值進(jìn)入數(shù)據(jù)庫(kù)杠愧。如果不在嚴(yán)格模式下,則會(huì)產(chǎn)生一條警告消息逞壁,并插入 NULL流济。
  • NO_ ZERO_ DATE:在嚴(yán)格模式下,它會(huì)阻止“零”日期值進(jìn)入數(shù)據(jù)庫(kù)腌闯。
  • NO_ ZERO_ IN_ DATE:在嚴(yán)格模式下绳瘟,它會(huì)阻止月或日部分為零的不完整日期值進(jìn)入數(shù)據(jù)庫(kù)。

簡(jiǎn)單來(lái)說(shuō)绑嘹,MySQL 的嚴(yán)格模式就是 MySQL 自身對(duì)數(shù)據(jù)進(jìn)行的嚴(yán)格校驗(yàn)稽荧,例如格式、長(zhǎng)度工腋、類型等姨丈。比如一個(gè)整型字段我們寫入一個(gè)字符串類型的數(shù)據(jù),在非嚴(yán)格模式下 MySQL 不會(huì)報(bào)錯(cuò)擅腰。如果定義了 char 或 varchar 類型的字段蟋恬,當(dāng)寫入或更新的數(shù)據(jù)超過(guò)了定義的長(zhǎng)度也不會(huì)報(bào)錯(cuò)。

雖然我們會(huì)在代碼中做數(shù)據(jù)校驗(yàn)趁冈,但一般認(rèn)為非嚴(yán)格模式對(duì)于編程來(lái)說(shuō)沒(méi)有任何好處歼争。MySQL開(kāi)啟嚴(yán)格模式從一定程序上來(lái)講也是對(duì)我們代碼的一種測(cè)試,如果我們沒(méi)有開(kāi)啟嚴(yán)格模式并且在開(kāi)發(fā)過(guò)程中也沒(méi)有遇到錯(cuò)誤渗勘,那么在上線或代碼移植的時(shí)候?qū)⒂锌赡艹霈F(xiàn)不兼容的情況沐绒,因此在開(kāi)發(fā)過(guò)程做最好開(kāi)啟 MySQL 的嚴(yán)格模式。

可通過(guò)select @@sql_mode;命令查看當(dāng)前是嚴(yán)格模式還是非嚴(yán)格模式旺坠。

例如乔遮,如果想讓所有的存儲(chǔ)引擎啟用嚴(yán)格模式,并對(duì)“被零除”錯(cuò)誤進(jìn)行檢查取刃,那么可以像下面這樣設(shè)置 SQL 模式:

SET sql_mode ‘STRICT_ALL_TABLES, ERROR_FOR_DIVISION_BY_ZERO' ;

如果想啟用嚴(yán)格模式蹋肮,以及所有的附加限制出刷,那么最為簡(jiǎn)單的辦法是啟用 TRADITIONAL 模式:

SET sql_ mode ‘TRADITIONAL' ;

TRADITIONAL 模式的含義是“啟用嚴(yán)格模式,當(dāng)向 MySQL 數(shù)據(jù)庫(kù)插入數(shù)據(jù)時(shí)坯辩,進(jìn)行數(shù)據(jù)的嚴(yán)格校驗(yàn)馁龟,保證錯(cuò)誤數(shù)據(jù)不能插入。用于事務(wù)表時(shí)漆魔,會(huì)進(jìn)行事務(wù)的回滾”坷檩。

可以選擇性地在某些方面弱化嚴(yán)格模式。如果啟用了 SQL 的 ALLOW_ INVALID_ DATES 模式有送,那么MySQL將不會(huì)對(duì)日期部分做全面檢查淌喻。相反,它只會(huì)要求月份值在 1~12 之間雀摘,而天數(shù)處于 1~31 之間,即允許像‘2000-02-30’或‘2000-06-31’這樣的無(wú)效值八拱。

另一個(gè)制止錯(cuò)誤的辦法是在 INSERT 或 UPDATE 語(yǔ)句里使用 IGNORE 關(guān)鍵字阵赠。這樣那些會(huì)因無(wú)效值而導(dǎo)致錯(cuò)誤的語(yǔ)句,將只會(huì)導(dǎo)致警告的出現(xiàn)肌稻。這些選項(xiàng)能讓你靈活地為你的應(yīng)用選擇正確的有效性檢查級(jí)別清蚀。

MySQL工作(執(zhí)行)流程

下面是一張簡(jiǎn)單的數(shù)據(jù)庫(kù)執(zhí)行流程圖:

MySQL工作流程圖

下面從數(shù)據(jù)庫(kù)架構(gòu)的角度介紹數(shù)據(jù)庫(kù)的工作流程:

連接層

連接處理

客戶端同數(shù)據(jù)庫(kù)服務(wù)層通過(guò)連接管理模塊建立 TCP 連接,并請(qǐng)求一個(gè)連接線程爹谭。如果連接池中有空閑的連接線程枷邪,則分配給這個(gè)連接,如果沒(méi)有诺凡,在沒(méi)有超過(guò)最大連接數(shù)的情況下东揣,創(chuàng)建新的連接線程負(fù)責(zé)這個(gè)客戶端。

  • 連接管理模塊負(fù)責(zé)監(jiān)聽(tīng)對(duì) MySQL Server 的各種請(qǐng)求腹泌,接收連接請(qǐng)求嘶卧,轉(zhuǎn)發(fā)所有連接請(qǐng)求到線程管理模塊。每一個(gè)連接上 MySQL Server 的客戶端請(qǐng)求都會(huì)被分配(或創(chuàng)建)一個(gè)連接線程為其單獨(dú)服務(wù)凉袱。而連接線程的主要工作就是負(fù)責(zé) MySQL Server 與客戶端的通信芥吟,接收客戶端的命令請(qǐng)求,傳遞 Server 端的結(jié)果信息等专甩。線程管理模塊則負(fù)責(zé)管理維護(hù)這些連接線程钟鸵。包括線程的創(chuàng)建,線程的緩存等涤躲。

授權(quán)認(rèn)證:

在真正的操作之前棺耍,還需要調(diào)用用戶模塊進(jìn)行授權(quán)檢查,來(lái)驗(yàn)證用戶是否有權(quán)限篓叶。通過(guò)后烈掠,連接線程開(kāi)始接收并處理來(lái)自客戶端的請(qǐng)求羞秤。

  • 用戶模塊所實(shí)現(xiàn)的功能,主要包括用戶的登錄連接權(quán)限控制和用戶的授權(quán)管理左敌。它就像 MySQL 的大門守衛(wèi)一樣瘾蛋,決定是否給來(lái)訪者“開(kāi)門”。

在 MySQL 中矫限,將客戶端請(qǐng)求分為了兩種類型:一種是 query(SQL語(yǔ)句)哺哼,需要調(diào)用 Parser(查詢解析器)才能夠執(zhí)行的請(qǐng)求;一種是 command(命令)叼风,不需要調(diào)用 Parser 就可以直接執(zhí)行的請(qǐng)求取董。

SQL層

連接線程接收到 SQL 語(yǔ)句之后,將語(yǔ)句交給 Parser 進(jìn)行語(yǔ)法分析和語(yǔ)義分析无宿。之后根據(jù)類型的不同茵汰,有些會(huì)直接處理,有些會(huì)分發(fā)給其他模塊來(lái)處理孽鸡。

如果是一個(gè) query 類型的請(qǐng)求蹂午,會(huì)將控制權(quán)交給 Query 解析器。

Query 解析器首先分析是不是一個(gè) Select 類型的 query彬碱。是則調(diào)用查詢緩存模塊豆胸,讓它檢查該 query 在 Query Cache(查詢緩存)中是否已經(jīng)存在,如果有結(jié)果可以直接返回給客戶端巷疼。沒(méi)有結(jié)果則將控制權(quán)交給 Optimizer(查詢優(yōu)化器)晚胡,進(jìn)行查詢的優(yōu)化。

如果是表變更語(yǔ)句嚼沿,則分別交給 Insert 處理器估盘、Delete 處理器、Update 處理器伏尼、Create 處理器忿檩,以及 Alter 處理器這些小模塊來(lái)負(fù)責(zé)。

存儲(chǔ)引擎層

在各個(gè)模塊收到 Query 解析或其它模塊分發(fā)過(guò)來(lái)的請(qǐng)求后爆阶,首先會(huì)通過(guò)訪問(wèn)控制模塊檢查連接用戶是否有訪問(wèn)目標(biāo)表以及目標(biāo)字段的權(quán)限燥透,如果有,就會(huì)調(diào)用表管理模塊請(qǐng)求相應(yīng)的表辨图,并獲取對(duì)應(yīng)的鎖班套。

  • 表變更管理模塊主要是負(fù)責(zé)完成一些 DML 和 DDL 的 query,如:update故河,delete吱韭,insert,create table,alter table 等語(yǔ)句的處理理盆。

當(dāng)表變更管理模塊“獲取”打開(kāi)的表之后痘煤,就會(huì)根據(jù)該表的相關(guān)信息,判斷表的存儲(chǔ)引擎類型和其他相關(guān)信息猿规。根據(jù)表的存儲(chǔ)引擎類型衷快,提交請(qǐng)求給存儲(chǔ)引擎接口模塊,調(diào)用對(duì)應(yīng)的存儲(chǔ)引擎實(shí)現(xiàn)模塊姨俩,進(jìn)行相應(yīng)處理蘸拔。

不過(guò),對(duì)于表變更管理模塊來(lái)說(shuō)环葵,可見(jiàn)的僅是存儲(chǔ)引擎接口模塊所提供的一系列“標(biāo)準(zhǔn)”接口调窍,底層存儲(chǔ)引擎實(shí)現(xiàn)模塊的具體實(shí)現(xiàn),對(duì)于表變更管理模塊來(lái)說(shuō)是透明的张遭。他只需要調(diào)用對(duì)應(yīng)的接口邓萨,并指明表類型,之后接口模塊會(huì)根據(jù)表類型調(diào)用正確的存儲(chǔ)引擎來(lái)進(jìn)行相應(yīng)的處理菊卷。

當(dāng)一條 query 或者一個(gè) command 處理完成(成功或者失斚扔)之后,控制權(quán)都會(huì)交還給連接線程模塊的烁。

如果處理成功,則將處理結(jié)果(可能是一個(gè) ResultSet诈闺,也可能是成功或者失敗的標(biāo)識(shí))通過(guò)連接線程反饋給客戶端渴庆。

如果處理過(guò)程中發(fā)生錯(cuò)誤,也會(huì)將相應(yīng)的錯(cuò)誤信息發(fā)送給客戶端雅镊,然后連接線程模塊會(huì)進(jìn)行相應(yīng)的清理工作襟雷,并繼續(xù)等待后面的請(qǐng)求。之后重復(fù)上面的過(guò)程仁烹,或者與客戶端斷開(kāi)連接耸弄,最后關(guān)閉連接,釋放連接線程卓缰。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末计呈,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子征唬,更是在濱河造成了極大的恐慌捌显,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,430評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件总寒,死亡現(xiàn)場(chǎng)離奇詭異扶歪,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)摄闸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門善镰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)妹萨,“玉大人,你說(shuō)我怎么就攤上這事炫欺『跬辏” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 167,834評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵竣稽,是天一觀的道長(zhǎng)囱怕。 經(jīng)常有香客問(wèn)我,道長(zhǎng)毫别,這世上最難降的妖魔是什么娃弓? 我笑而不...
    開(kāi)封第一講書人閱讀 59,543評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮岛宦,結(jié)果婚禮上台丛,老公的妹妹穿的比我還像新娘。我一直安慰自己砾肺,他們只是感情好挽霉,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,547評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著变汪,像睡著了一般侠坎。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上裙盾,一...
    開(kāi)封第一講書人閱讀 52,196評(píng)論 1 308
  • 那天实胸,我揣著相機(jī)與錄音,去河邊找鬼番官。 笑死庐完,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的徘熔。 我是一名探鬼主播门躯,決...
    沈念sama閱讀 40,776評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼酷师!你這毒婦竟也來(lái)了讶凉?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 39,671評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤窒升,失蹤者是張志新(化名)和其女友劉穎缀遍,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體饱须,經(jīng)...
    沈念sama閱讀 46,221評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡域醇,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,303評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片譬挚。...
    茶點(diǎn)故事閱讀 40,444評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡锅铅,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出减宣,到底是詐尸還是另有隱情盐须,我是刑警寧澤,帶...
    沈念sama閱讀 36,134評(píng)論 5 350
  • 正文 年R本政府宣布漆腌,位于F島的核電站贼邓,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏闷尿。R本人自食惡果不足惜塑径,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,810評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望填具。 院中可真熱鬧统舀,春花似錦、人聲如沸劳景。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,285評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)盟广。三九已至闷串,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間筋量,已是汗流浹背窿克。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,399評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留毛甲,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,837評(píng)論 3 376
  • 正文 我出身青樓具被,卻偏偏與公主長(zhǎng)得像玻募,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子一姿,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,455評(píng)論 2 359