DQL基本語法(查詢)
下面的查詢基于的表有:
- "Websites" 表:

- access_log表:

- students表:

1、DQL的基本介紹
DQL(Data Query Language,查詢數據):DQL就是用來查詢表中的數據的,為用戶提供查詢數據的能力,這也是通常最頻繁的數據庫日常操作。
2、基本查詢(select)
要查詢數據庫表的數據,我們使用如下的SQL語句:
SELECT * FROM <表名>; # 示例: SELECT * FROM students; # 查詢students表的所有數據
查詢結果也是一個二維表,它包含列名和每一行的數據。
SELECT語句其實并不要求一定要有FROM子句:
SELECT 100+200;
上述查詢會直接計算出表達式的結果。雖然SELECT可以用作計算,但它并不是SQL的強項。但是,不帶FROM子句的SELECT語句有一個有用的用途,就是用來判斷當前到數據庫的連接是否有效。許多檢測工具會執行一條SELECT 1;來測試數據庫連接。
2.1、起別名(AS或者空格)
當我們想給查詢出來的字段另起一個名字時,可以用 AS 關鍵字或者直接在該字段后面加空格然后加別名的方式來給查詢出的字段重新命名:
SELECT name as my_name from websites; -- as 關鍵字起別名 SELECT name my_name from websites; -- 直接用空格添加別名也行
3、條件查詢(where、AND、OR、NOT、<>)
條件查詢語法:
SELECT * FROM <表名> WHERE <條件表達式> # 示例: SELECT * FROM students WHERE score >= 80;
常用的條件表達式有:
=、>、>=、<、<=、<>(不等于,在 SQL 的一些版本中,不等于可被寫成 !=)、like(相似)

3.1、AND(并且)
條件表達式可以用<條件1> AND <條件2>表達滿足條件1并且滿足條件2,代碼示例:
SELECT * FROM students WHERE score >= 80 AND gender = 'M'; # 假設gender列存儲的是字符串,那就需要用單引號括起來
3.2、OR(或者)
也可以用<條件1> OR <條件2>來表示滿足條件1或者滿足條件2,代碼示例:
SELECT * FROM students WHERE score >= 80 OR gender = 'M';
3.3、<>、NOT(不等于)
還有NOT <條件>,表示“不符合該條件”的記錄。NOT條件其實等價于<>,因此,NOT查詢不是很常用。代碼示例:
SELECT * FROM students WHERE NOT class_id = 2; # 等價于: SELECT * FROM students WHERE class_id <> 2;
3.4、小括號()
要組合三個或者更多的條件,就需要用小括號()表示如何進行條件運算。例如,編寫一個復雜的條件:分數在80以下或者90以上,并且是男生:
SELECT * FROM students WHERE (score < 80 OR score > 90) AND gender = 'M';
如果不加括號,條件運算按照 NOT > AND > OR 的優先級進行,即 NOT 優先級最高,其次是 AND,最后是 OR。加上括號可以改變優先級。
3.5、between...and...(查詢在某個區間的值)
between and 可以查詢在某個區間之間的值:
Select * from access_log where count between 10 and 100;
查詢結果:

3.6、in(查詢屬于某個集合內的值)
可以用 in 列出一個集合,查詢字段的值屬于該集合內的行:
SELECT * FROM access_log WHERE count IN (45, 10);
查詢結果:

3.7、exists(過濾符合條件的數據)
exists 關鍵字該語法可以理解為:將主查詢的數據,放到子查詢中做條件驗證,根據驗證結果(TRUE或FALSE)來決定主查詢的數據結果是否得以保留。(子查詢里面應該用到外面的表SQL才能正常執行)
比如查詢為:
SELECT a,b FROM table1 WHERE EXISTS( SELECT c FROM table2 WHERE t1.id=table2.id )
這里面的EXISTS是如何運作呢?子查詢返回的是 c 字段,可是外面的查詢要找的是 a 和 b 字段,這兩個字段肯定不在 c 里面啊,這是如何匹配的呢?
實際上 EXISTS 用于指定一個子查詢,在該子查詢里面過濾外面表的符合條件的數據,該子查詢實際上并不返回任何數據,而是返回值True或False。也就是說,實際上是在子查詢里面過濾外面的表里屬于 true 的數據,而子查詢返回什么并不重要,比如可以是 select *、select 1、select 'xxx',官方說法是實際執行時會忽略 select 返回的值,因此返回什么并無區別。
上面的 SQL 等價于:
SELECT a,b FROM table1 t1 WHERE EXISTS( SELECT * FROM table2 WHERE t1.id=table2.id )
exists 語句的特點:
- EXISTS(subquey)只返回TRUE或FALSE,因此子查詢中的SELECT * 也可以是 SELECT 1 或select ‘X’,官方說法是實際執行時會忽略SELECT清單,因此沒有區別。
- EXISTS子查詢的實際執行過程可能經過了優化而不是我們理解上的逐條對比,如果擔憂效率問題,可進行實際檢驗以確定是否有效率問題。
- EXISTS子查詢往往也可以用條件表達式,其他子查詢或者JOIN來替代,何種最優需要具體問題具體分析
3.8、LIKE(模糊查詢)
可以使用 LIKE 進行模糊查詢,比如:LIKE '%abc%'、LIKE '_abc_',其中占位符 _ 表示任意單個字符,% 表示任意多個(即0或者多個)字符。
SELECT * FROM apps WHERE url LIKE '%qq%';
查詢結果:

SELECT * FROM apps WHERE app_name LIKE '_寶%';
查詢結果:

4、去除重復(SELECT DISTINCT)
在表中,一個列可能會包含多個重復值,我們可以使用 SELECT DISTINCT 語句來去除重復值,返回某個字段的所有唯一值。注意,distinct 必須緊跟在 select 后面,否則語法會報錯,且 distinct 是作用于其后的所有列的。
-- 根據A、B、C的組合來判斷重復 select distinct A,B,C from tablename; -- 下面是錯誤的寫法,會直接報錯 select A,B, distinct C from tablename;
比如查詢 website 表中 country 字段的所有值并去除重復:
SELECT DISTINCT country FROM Websites;
查詢結果:

當用 distinct 來查詢多列時,是查詢多列組合起來沒有重復的,如果指定的列當中有一列不一樣,則認為不是重復,也會查詢出來。比如:
SELECT DISTINCT country,name FROM Websites;
此時認為只有當 country 和 name 字段的值都一樣才認為是重復,否則不認為是重復。如果有多組不重復的則都會被查出來。
5、排序查詢(ORDER BY)
可以用 ORDER BY 關鍵字來對查詢出來的結果集進行排序,可以對一個列或者多個列進行排序。ORDER BY 關鍵字默認按照升序(ASC)對記錄進行排序,如果需要降序,可以使用 DESC 關鍵字。
如果對多個字段進行排序時,先比較字段1,如果字段1的值一樣就會比較字段2的值,以此類推。
語法:
ORDER BY 字段1 排序方式1, 字段2 排序方式2... -- 示例 SELECT * FROM access_log ORDER BY count ASC;
查詢結果:

6、聚合函數(COUNT、MAX、MIN、SUM、AVG)
SQL 提供的聚合函數:
- COUNT:計算個數
- MAX:計算最大值
- MIN:計算最小值
- SUM:計算和
- AVG:計算平均值
聚合函數的查詢結果仍然是一個二維表,只是這個二維表只有一行一列,并且列名是 關鍵字(字段名),類似于 SUM(num)
注意,聚合函數的計算不會把 null 值計算在內。比如某個表有3條記錄,但某個記錄的 name 字段的值為 null,則用 count(name) 計算列數時不會把這條記錄計算進去,即得出的結果只有 2 條記錄。
示例:
SELECT count(id) FROM websites; SELECT MAX(count) FROM access_log; SELECT MIN(count) FROM access_log; SELECT SUM(count) FROM access_log; SELECT AVG(count) FROM access_log;
7、分組查詢(GROUP BY)
我們可以用 group by 關鍵字來進行分組查詢。分組查詢可以理解為分類。
示例:
SELECT gender, AVG(score) FROM students GROUP BY gender;
查詢結果:

在進行分組后,select 查詢的字段一般會是分組字段、聚合函數,或者是 where 查詢條件里面的字段,或者是跟這些字段有強關聯的字段,比如用字段 id 進行分組,每個 id 對應著唯一的 name,則此時也可以查詢 name 字段的值。
除了上述一些字段,使用 group by 時查詢其他的字段意義不大。比如上面如果此時查詢 id 字段,雖然 SQL 不會報錯,但只會查詢出第一個有分組字段的記錄,沒有什么實際意義,有時還有可能會查詢出錯誤的數據。
7.1、對多個字段進行分組
GROUP BY x1, x2 意思是只有當 x1 和 x2 都相同才認為是同一個組,否則都會認為是另一個不同的組。對多個字段進行分組時,實際上是對篩選為同一個組多加了限制條件。
示例:
SELECT count(1),class_id,gender FROM `students` GROUP BY class_id,gender;
結果:

7.2、HAVING(對分組之后的數據進行過濾)
在 SQL 中增加 HAVING 子句原因是,WHERE 關鍵字無法與聚合函數一起使用。通過 having 關鍵字就可以將聚合函數放在作為篩選條件來過濾查詢記錄,HAVING 子句可以讓我們篩選分組后的各組數據。
示例:
SELECT name, gender, AVG(score) FROM students WHERE score > 50 GROUP BY gender HAVING count(id) >= 5; -- 先篩選score大于50的數據。篩選完之后,得到分組數據,然后只保留分組之后的所有的記錄數量大于等于5的分組數據
查詢結果:

where 在分組之前對數據進行過濾,如果不滿足條件將不會參與分組。而 having 是對分組之后得到的數據進行過濾,如果不滿足則不會被查詢出來。
8、分頁查詢(limit)
當數據量過大時,一般我們會采用分頁查詢,即每次只查詢固定數量的記錄。
比如,MySQL 的分頁語句是:
-- 標準寫法 SELECT * FROM 表名 LIMIT 每頁數量 OFFSET 偏移量; -- 偏移量 = (當前頁碼 - 1) × 每頁數量,頁碼從1開始 -- 簡寫 select * from students limit 偏移量, 每頁數量;
示例,每次查詢 3 條記錄:
SELECT * FROM students LIMIT 0,3; -- 第一頁,查詢第1~第3條記錄 SELECT * FROM students LIMIT 3,3; -- 第二頁,查詢第4~第6條記錄
查詢結果:

需要注意,Oracle 和 MySQL 的分頁查詢語句并不一樣。
當使用分頁查詢時,數據庫不會只查詢分頁內的數據,而是需要處理大量額外數據來確定分頁位置。深度分頁(大偏移值)會導致顯著的性能下降,因為資源消耗與OFFSET值成正比。
9、null值的比較和運算
9.1、null 值的比較
在MySQL中,NULL是一個特殊的值,代表未知或缺失的值。MySQL中,NULL與任何值的比較(包括NULL本身)都會返回NULL,而不是TRUE或FALSE。例如,NULL = NULL,NULL < 10,NULL > 5等比較都會返回NULL而不是FALSE。
- NULL和任何值都不能比較
- NULL值與任何其它值的比較(即使是NULL)結果都是 NULL,永遠不會為“真”
- NULL只能用is null 或者is not null 來判斷,不能用=或者!=來判斷
所以說在查詢中用 = 或 != 都不會包含 null 值的數據,要想包含應該用 is null。示例如下:
- 查詢結果1:
select * from access_log lg left join websites web on lg.aid = web.id

- 結果2:
select * from access_log lg left join websites web on lg.aid = web.id where web.country = 'CN' select * from access_log lg left join websites web on lg.aid = web.id where web.country != 'CN'
分別是:


都不會包含 null 值,要想包含 null 值,應該用 is null,如下:
select * from access_log lg left join websites web on lg.aid = web.id where web.country = 'CN' or web.country is null


浙公網安備 33010602011771號