天天看點

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

寫在前面:本篇為作者自學總結,學習内容為課堂所學和網絡學習筆記彙總,對于内容引用部分在文中和文末注明。

文章僅供參考,如需深入了解,請查閱MySQL參考手冊。附上下載下傳連結:

連結:https://pan.baidu.com/s/1FpONA6oyI6O73m_ebN7J_Q 

提取碼:7pr8 

複制這段内容後打開百度網盤手機App,操作更友善哦

目錄

查(SELECT)的操作  (重點)

1. 補充知識:MySQL表的複制

2. SELECT語句的一般格式和講解

2.1 SQL語句基本格式

2.2 SQL最基本的查詢語句

3. 帶條件的查詢(WHERE)

3.1 比較搜尋條件

3.2 複合比較搜尋條件

3.3 範圍搜尋條件

3.4 設定搜尋成員

3.5 模式比對

3.6 NULL查詢條件

4 查詢結果的排序(ORDER BY)和傳回指定數量的記錄(LIMIT)

4.1 查詢結果的排序(ORDER BY)

4.2 傳回指定數出數目的記錄(LIMIT) 

5 連接配接字元串(CONCAT)和随機數(RAND)

5.1 連接配接字元串(CONCAT)

5.2 随機數(LIMIT)

6 聚合(Aggregates) --(COUNT, SUM, AVG, MIN, MAX)

6.1 COUNT

6.2 SUM

6.3 AVG

6.4 MIN

6.5 MAX

7 分組(Grouping) -- (GROUP BY ) 

7.1  GROUP BY與聚合函數配合使用

7.2 GROUP BY與HAVING配合使用

7.3 當GROUP BY與聚合函數,同時非聚合字段同時使用

7.4 分組聚合思想總結

8 MySQL多表查詢

8.1 普通多表查詢

8.2 嵌套查詢或子查詢 

8.3 連結查詢

9 自己的一些心得總結 (随着經驗增加更新)

參考資料:

在之前的MySQL學習筆記(一)中已經總結了MySQL的基礎概念, 在MySQL學習筆記(二)已經記錄了增删改的指令,在本篇MySQL學習筆記(三)中将更新MySQL查詢語句。

查詢語句是MySQL的重難點,建議動手操作,跟着例子走一遍,加深了解。我在學習MySQL的時候使用的工具: MySQL Workbench, navicat。

查(SELECT)的操作  (重點)

增删改都會改變表,但是查詢不會。接下來我們将講解查詢(SELECT)操作。

關于查詢操作的講解全部将基于user和class兩個表。

/*student表*/
-- 建立student表
CREATE TABLE student(
    student_id SMALLINT(5) UNSIGNED NOT NULL AUTO_INCREMENT, 
		student_name VARCHAR(20) NOT NULL, 
		gender TINYINT(1) NOT NULL COMMENT '0為女生,1為男生',
		age TINYINT NOT NULL,
        class_id TINYINT(1) NOT NULL,
        PRIMARY KEY (student_id));

-- 向student表插入資料
INSERT INTO student(student_name, gender, age, class_id) VALUES('紅紅', 0, 16, 1);
INSERT INTO student(student_name, gender, age, class_id) VALUES('李華', 1, 18, 5);
INSERT INTO student(student_name, gender, age, class_id) VALUES('花花', 0, 14, 3);
INSERT INTO student(student_name, gender, age, class_id) VALUES('明明', 1, 16, 5);
INSERT INTO student(student_name, gender, age, class_id) VALUES('大明', 1, 20, 2);
INSERT INTO student(student_name, gender, age, class_id) VALUES('貝貝', 1, 15, 1);
INSERT INTO student(student_name, gender, age, class_id) VALUES('晶晶', 0, 16, 4);
INSERT INTO student(student_name, gender, age, class_id) VALUES('歡歡', 0, 17, 3);
INSERT INTO student(student_name, gender, age, class_id) VALUES('瑩瑩', 0, 18, 4);
INSERT INTO student(student_name, gender, age, class_id) VALUES('妮妮', 0, 19, 4);

SELECT * FROM student;
           

student表視圖如下所示:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:
/*class表*/
-- 建立class表
CREATE TABLE class (
  class_id TINYINT(1) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
  class_name VARCHAR(10) NOT NULL
);

-- 向class表插入資料
INSERT INTO class(class_name) VALUES('金融數學');
INSERT INTO class(class_name) VALUES('離散數學');
INSERT INTO class(class_name) VALUES('圍棋');
INSERT INTO class(class_name) VALUES('古筝');
INSERT INTO class(class_name) VALUES('舞蹈');

SELECT * FROM class;
           

class表視圖如下所示: 

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

建議提前熟悉兩個表中的資料,友善之後了解基于它們的操作。

1. 補充知識:MySQL表的複制

 MySQL也可以複制表,語句如下,我們建立了一個名為student1的表,它的字段屬性和student一緻,關鍵字是LIKE:

CREATE TABLE student1 LIkE student;
           

我們可以看到資料困中建立了一個student1的表:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

檢視兩個表的字段資訊,可以對比發現兩個表的字段屬性一緻: 

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:
MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

但是student1的内容為空,我們可以檢視student1的試圖來确定: 

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

現在我們隻是建立了一個和student屬性一緻的表,但是沒有内容,接下開應該把student的内容指派給student1:

INSERT INTO student1 SELECT * FROM student;
           

上面的語句将student表中的全部資料插入student1表中,我們用SELECT * FROM student1; 來檢視一下student1的全部資料:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

可以看到通過先指派表,在插入資料,我們可以實作表的複制。 

2. SELECT語句的一般格式和講解

2.1 SQL語句基本格式

條款的順序不能改變。隻有SELECT和FROM是必需的。一般格式如下:

SELECT [DISTINCT | ALL]

 {* | [columnExpression [AS newName]] [,...] }

FROM  TableName [alias] [, ...]

[WHERE  condition]

[GROUP BY  columnList]  [HAVING  condition]

[ORDER BY  columnList]

其中:

FROM       指定要使用的表

WHERE      篩選行

GROUP BY    形成具有相同列值的行組

HAVING        根據某些條件篩選組

SELECT        指定要在輸出中顯示的列

ORDER BY   指定輸出的順序

2.2 SQL最基本的查詢語句

最基本的查詢:

SELECT *
FROM student;
           

*指的是全部列。該SQL語句選擇student表中的全部資料,視圖如下:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

MySQL同樣支援選擇特定的字段。如果隻想查詢學生姓名和年齡,則将*換成學生姓名和年齡對應的字段名,用,連接配接,查找顯示的字段順序以我們寫查找語句的時候的字段順序為準:

SELECT student_name,age
FROM student;
           

查詢結果:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

列資料中可能會有重複的資料,可以使用DISTINCT關鍵子來消除重複:

SELECT DISTINCT gender
FROM student;
           

查詢結果: 

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

 可以對查詢的資料進行運算,如下:

SELECT age+2 AS agePlus2
FROM student;
           

在查詢過程中對所有年齡進行了+2的數學運算,并通過AS将加2後的年齡重命名為了agePlus2,如果不選擇重命名,則加2後的年齡的字段名還是age。修改名字主要是為了友善了解和避免誤會。AS可以省略,上面的語句等同于SELECT age+2 agePlus2 FROM student; 。給給字段名起别名的時候,别名僅在查詢結果顯現,原表中的字段名和資料并未發生改變。查詢結果如下:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

3. 帶條件的查詢(WHERE)

WHERE後面一般帶有查詢條件,用來篩選滿足條件的行。

3.1 比較搜尋條件

比較搜尋條件的時候,和我們數學常用的>,>=,=,<=,<,<>用法相同,注意不等于寫為<>:

SELECT student_id,student_name, age
FROM student
WHERE age >= 18;
           

 查詢結果:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

3.2 複合比較搜尋條件

 可以使用AND和OR來連接配接這些查詢條件:

SELECT student_id,student_name, age
FROM student
WHERE age = 18 AND gender = 0;
           

查詢結果:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

3.3 範圍搜尋條件

 可以使用BETWEEN a AND b,包括區間頂點a和b。下面的語句與SELECT student_id,student_name, age FROM student WHERE age>=16 AND age<=19;等效:

SELECT student_id,student_name, age
FROM student
WHERE age BETWEEN 16 AND 19;
           

 查詢結果:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

3.4 設定搜尋成員

可以使用IN加()來設定所需要選的成員。括号内是滿足的條件,邏輯關系相當于OR。下面的查詢等同于SELECT student_id,student_name, age FROM student WHERE age = 16 OR age = 19;:

SELECT student_id,student_name, age
FROM student
WHERE age IN(16, 19);
           

查詢結果:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

IN還有否定形式NOT IN,下面的查詢語句等同于SELECT student_id,student_name, age FROM student WHERE age <>16 AND age <>19;,因為OR被否定,是以連接配接用AND:

SELECT student_id,student_name, age
FROM student
WHERE age NOT IN(16, 19);
           

 查詢結果:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

雖然IN和OR可以互相替換,但當集合包含多個值時,IN更有效。 

3.5 模式比對

在class表中找到課程名中包含‘數學’的課程的是以資訊:

SELECT * 
FROM class 
WHERE class_name LIKE '%數學%';
           

 查詢結果如下:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

 SQL有兩個特殊的模式比對符号:

                  %:零個或多個字元的序列;

                  _(下劃線):任何單個字元。

SELECT * FROM class WHERE class_name LIKE '__數學'; 與

SELECT * FROM class WHERE class_name LIKE '%數學'; 的查詢結果與上面的代碼查詢結果相同,但表達的含義不一樣:'%數學%'表示包含“數學”的任意長度的字元序列,'__數學'表示長度為四的後兩位為'數學'的字元序列,'%數學'表示末尾兩個字為'數學'的任意長度的字元序列。

3.6 NULL查詢條件

可以用IS NULL和 IS NOT NULL來進行查詢。詳情看MySQL學習筆記(一)的第五節的NULL的内容。注意區分NULL和'''。

4 查詢結果的排序(ORDER BY)和傳回指定數量的記錄(LIMIT)

4.1 查詢結果的排序(ORDER BY)

使用ORDER BY對查詢結果排序。排序分為升序ASC(從小到大),降序DESC(從大到小)和随機排列(RAND),本節隻講解升序和降序排列,随機排列将在下一節詳述。

1)單列排序

 選擇學生的所有資訊并以class_id從大到小的順序排列:

SELECT * 
FROM student 
ORDER BY class_id DESC;
           

查詢結果:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

2)多列排序

從上面的結果可以知道,如果沒有指定其他的排列順序,在滿足單列排序後,系統會自己選擇行的排列順序。如果我們可以自己設定行的排列順序,需要我們指定次要順序。

選擇學生的是以資訊并以學生class_id降序,gender升序的順序排列: 

SELECT * 
FROM student 
ORDER BY class_id DESC, gender;
           

如果是升序,可以加ASC關鍵字,如果沒有加,則預設為升序;降序必須寫DESC,不可省略。上面語句的查詢結果:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

注意ORDER BY的順序對查詢結果有影響,上面的查詢是先以class_id降序排列,再在相同的class_id的行中按gender升序排列。如果将兩者位置互換,例如下面的查詢:

SELECT * 
FROM student 
ORDER BY gender, class_id DESC;
           

 按照排序順序,先以gender升序排列,再在gender相同的情況下以class_id降序的方式排列。查詢結果:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

4.2 傳回指定數出數目的記錄(LIMIT) 

使用LIMIT關鍵字。接受一個或兩個數字參數,該參數必須是整數常量。文法為SELECT * FROM table LIMIT [offset,] rows | rows OFFSET   offset;。

1)選擇前n行(從第一行開始)

以下兩種寫法相同,都表示選取前3行。初始偏移量為0:

SELECT student_id, student_name, age 
FROM student 
LIMIT 3;
           
SELECT student_id, student_name, age 
FROM student 
LIMIT 0,3;
           

查詢結果相同,如下所示:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

2)選擇從第n行開始選擇m條記錄(從第一行開始)

表示方法: LIMIT n-1, m。以下記錄從第3行開始選取2行,即選取第3、4行:

SELECT student_id, student_name, age 
FROM student 
LIMIT 2,2;
           

查詢結果如下:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

5 連接配接字元串(CONCAT)和随機數(RAND)

5.1 連接配接字元串(CONCAT)

将CONCAT函數括号裡的資料連接配接起來,傳回結果為連接配接參數産生的字元串。如下查詢:

SELECT student_name,age, CONCAT(student_name,age)
FROM student;
           

查詢結果:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

可以給我們連接配接的資料加别名以防止誤會,同時便于了解,AS可以省略:

SELECT student_name,age, CONCAT(student_name,age) name_age
FROM student;
           

查詢結果: 

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

可以自己添加任意字元: 

SELECT student_name,age, CONCAT('合并:',student_name,'-',age,'歲') name_age
FROM student;
           

 查詢結果:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

 如有任何一個參數為NULL ,則傳回值為 NULL: 

SELECT student_name,age, CONCAT('合并:',student_name,NULL,age,'歲') name_age
FROM student;
           

 查詢結果:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

5.2 随機數(LIMIT)

RAND函數每次生成一個0到1的随機數,可以搭配ORDER BY來随機打亂資料表,每次輸出結果各不相同。配合LIMIT函數可以用來随機生成一行記錄,可以用來抽獎随機抽取一位幸運者等日常活動,很實用。

SELECT *
FROM student
ORDER BY RAND() LIMIT 1;
           

查詢結果如下(注意每次生成結果不同): 

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

6 聚合(Aggregates) --(COUNT, SUM, AVG, MIN, MAX)

MySQL有五種聚合函數:

COUNT  傳回指定列中的值的個數。

SUM       傳回指定列中的值之和。

AVG        傳回指定列中值的平均值。

MIN         傳回指定列中的最小值。

MAX        傳回指定列中的最大值。

每個操作都對表的一列進行操作并傳回一個值。COUNT、MIN和MAX适用于數字和非數字字段,但SUM和AVG隻能用于數字字段。除了COUNT(*)之外,每個函數都首先消除空值,并且隻對剩餘的非空值進行操作。

COUNT(*)統計表中的所有行,而不管是否出現空值或重複值。可以在列名前使用DISTINCT來消除重複項。DISTINCT對MIN/MAX沒有影響,但對SUM/AVG可能有影響。

6.1 COUNT

統計student表的學生總數:

SELECT COUNT(*) 學生總數
FROM student;
           

統計結果:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

 統計學生中總共有幾種年齡:

SELECT COUNT(DISTINCT age) 
FROM student;
           

查詢結果:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

6.2 SUM

計算所選列資料的總和。統計學生中年齡共有幾種,并且算出全部學生的年齡之和:

SELECT COUNT(DISTINCT age), SUM(age)
FROM student;
           

 查詢結果:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

 統計學生中年齡共有幾種,并且算出這幾種不同的年齡的總和是多少:

SELECT COUNT(DISTINCT age), SUM(DISTINCT age)
FROM student;
           
MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

6.3 AVG

計算所選列資料的平均數。統計學生中年齡共有幾種,并且算出全部學生的平均年齡:

SELECT COUNT(DISTINCT age), AVG(age)
FROM student;
           

查詢結果:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

統計學生中年齡共有幾種,并且算出這幾種不同的年齡的平均數是多少:

SELECT COUNT(DISTINCT age), AVG(DISTINCT age)
FROM student;
           

查詢結果:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

6.4 MIN

計算所選列資料的最小數。統計學生中年齡共有幾種,并且算出全部學生的最小年齡:

SELECT COUNT(DISTINCT age), MIN(age)
FROM student;
           

查詢結果:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

統計學生中年齡共有幾種,并且算出這幾種不同的年齡的最小年齡是多少:

SELECT COUNT(DISTINCT age), MIN(DISTINCT age)
FROM student;
           

查詢結果:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

從查詢結果可以看出重複資料對MIN沒有影響。

6.5 MAX

計算所選列資料的最大數。統計學生中年齡共有幾種,并且算出全部學生的最大年齡:

SELECT COUNT(DISTINCT age), MAX(age)
FROM student;
           

查詢結果:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

統計學生中年齡共有幾種,并且算出這幾種不同的年齡的最大年齡是多少: 

SELECT COUNT(DISTINCT age), MAX(DISTINCT age)
FROM student;
           

查詢結果:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

從查詢結果可以看出重複資料對MAX沒有影響。 

7 分組(Grouping) -- (GROUP BY ) 

當GROUP BY與聚合函數配合使用時,功能為分組後計算。

當GROUP BY與HAVING配合使用時,功能為分組後過濾。

當GROUP BY與聚合函數,同時非聚合字段同時使用時,非聚合字段的取值是第一個比對到的字段内容,即id小的條目對應的字段内容。

7.1  GROUP BY與聚合函數配合使用

GROUP BY的正常用法是配合聚合函數,利用分組資訊進行統計。

計算student中男女生各多少人:

SELECT COUNT(student_id),gender
FROM student
GROUP BY gender;
           

查詢結果:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

7.2 GROUP BY與HAVING配合使用

配合HAVING進行篩選後過濾。在上述查詢條件下繼續篩選gender>0的資料:

SELECT COUNT(student_id),gender
FROM student
GROUP BY gender
HAVING gender > 0;
           

查詢結果:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

SELECT COUNT(student_id), gender FROM student WHERE gender > 0;的查詢結果與上面的查詢結果相同。對同一需求的查詢關系了解不同,查詢語句也會不同,隻要能正确得到所需資料且關系了解正确,選哪一種語句都可以。對于其他的查詢語句同理。

7.3 當GROUP BY與聚合函數,同時非聚合字段同時使用

 非聚合條件字段的取值與資料寫入的時間無關,非聚合字段的取值是第一個比對到的字段内容,即student_id小的條目對應的字段内容:

SELECT student_id,COUNT(student_id),gender
FROM student
GROUP BY gender;
           

查詢結果:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

7.4 分組聚合思想總結

分組與聚合原理:

組是使用特定的條件将中繼資料進行劃分為多個組。聚合是對每個分組中的資料執行某些操作,最後将計算結果進行整合。

分組與聚合的過程大概分三步:

拆分:将資料集按照一些标準拆分為若幹組。

應用:将某個函數或者方法應用到每個分組。

合并:将産生的新值整合到結果對象中

8 MySQL多表查詢

1.普通多表查詢

2.嵌套查詢或子查詢

3.連結查詢

1)左連結

2)右連結

3)内連結

8.1 普通多表查詢

1)兩表無條件查詢: 

SELECT *
FROM student, class;
           

查詢結果如下: 

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

查詢記錄顯示總共查詢了(10乘以5)行。 

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

由此可知兩表無條件查詢是對兩表所有資料進行組合,資料量是兩表條數乘積。

2)兩表有條件查詢

當student表中的student_id等于class表裡的class_id的時候,選取student表裡的student_id, student_name和age。其實為student表重命名為s,class表重命名為c,以便書寫友善,簡單易讀:

SELECT s.student_id, s.student_name, s.age
FROM student s, class c
WHERE s.student_id = c.class_id;
           

查詢結果:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

8.2 嵌套查詢或子查詢 

SQL語句中可以嵌入SELECT查詢,合起來被稱為嵌套查詢。嵌套查詢是外層主查詢和内層子查詢的結合,是一種更複雜的查詢。子查詢還可以包括子查詢,可以是多層子查詢,主查詢也可以包括多個子查詢。子選擇也可能出現在INSERT、UPDATE和DELETE語句中。

子查詢就是括号中的查詢。嵌套查詢和子查詢雖不是一個概念,但是相關的概念。 

嵌套查詢的格式:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

 其中括号外是主查詢,括号内是子查詢,合起來叫做嵌套查詢。

1)子查詢規則

ORDERBY子句不能用在子查詢中(盡管它可以用在最外層的SELECT中)。子查詢選擇清單必須由單個列名(a single column name)或表達式(expression)組成,使用EXISTS的子查詢除外。

預設情況下,列名引用子查詢的FROM子句中的表名。可以通過使用别名引用中的表。(By default, column names refer to table name in FROM clause of subquery. Can refer to a table in FROM using an alias.)

當子查詢是比較中的操作數時,子查詢必須出現在右側。子查詢不能用作表達式中的操作數。

2)等号子查詢 

主查詢和子查詢是等号關系。舉例,找到學金融數學的學生姓名。

我們需要從student表得到學生姓名,從class表得到學金融數學的資訊,兩個表靠class_id連接配接,嵌套查詢的代碼如下:

SELECT student_name 
FROM student 
WHERE class_id = 
      (SELECT class_id 
      FROM class 
      WHERE class_name = '金融數學');
           

查詢結果如下:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

 通過子查詢選擇和主查詢相等的條件。 

3) 帶聚合的子查詢 

舉例,找到學生比所有學生的平均年齡大的學生并求得他們比平均年齡大多少,代碼如下:

SELECT student_name, age - (SELECT AVG(age) 
      FROM student) AS AgeDiff
FROM student 
WHERE age > 
      (SELECT AVG(age) 
      FROM student);
           

查詢結果如下:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

注意,不能使用“WHERE age > AVG(age)”。查詢語句SELECT student_name, age - (SELECT AVG(age) FROM student AS AgeDiff FROM student WHERE age > AVG(age);會報錯,錯誤如下:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

 相反,我們應該先使用子查詢查找平均年齡(16.9000),然後使用外部選擇(outer SELECT)查找工資高于此值的員工,邏輯等同于:

SELECT student_name, age - 16.9000 AS AgeDiff
FROM student 
WHERE age > 16.9000;
           

4) 帶in的子查詢

IN關鍵字主要用于判斷表達式是否在多值清單中。主選擇進行多汁判斷然後傳回在多值清單中的記錄。

舉例,2)中舉例找到學金融數學的學生姓名,我們用帶IN的子查詢可以改寫為如下:

SELECT student_name 
FROM student 
WHERE class_id IN 
      (SELECT class_id 
      FROM class 
      WHERE class_name = '金融數學');
           

 查詢結果如下:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

與2)中結果一樣。 

5) 帶any(some)或all的子查詢

ANY和ALL可用于生成一列數字的子查詢。對于ALL,條件隻有在子查詢生成的所有值都滿足時才為true。對于ANY,如果子查詢生成的任何值滿足條件,則該條件将為true。如果子查詢為空,則ALL傳回true,ANY傳回false。

SOME可以用來代替任ANY。

ANY(SOME):

舉例,在student表中查找年齡大于至少一名其他學生的學生姓名,可以寫成如下SQL語句:

SELECT student_name 
FROM student 
WHERE age > SOME
      (SELECT age 
      FROM student);
           

查詢結果如下:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

可以看出來除了年齡最小的十四歲的花花外都被選擇到了。将SOME換成ANY效果一樣。

ALL:

舉例,在student表中查找年齡大于class_id為1的學生的學生姓名,可以寫成如下SQL語句:

SELECT student_name 
FROM student 
WHERE age > ALL
      (SELECT age 
      FROM student
      WHERE class_id = 1);
           

查詢結果如下: 

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

 其中class_id為1的學生的年齡分别為15和16歲,是以選擇出來的學生是年齡大于16且class_id部位1的。

5) 帶EXISTS的子查詢

EXISTS和NOT EXISTS僅用于子查詢。它們生成簡單的真/假(true/false )結果。如果子查詢傳回的結果表中至少存在一行,則為True。如果子查詢傳回空結果表,則為False。NOT EXISTS是EXISTS的相反情況。

由于(NOT)EXISTS隻檢查子查詢結果表中是否存在行,是以子查詢可以包含任意數量的列。

舉例:找到所有學金融數學或圍棋的同學的姓名,SQL的包含EXISITS子查詢的語句如下:

SELECT s.student_name 
FROM student s
WHERE EXISTS
      (SELECT *
      FROM class c
      WHERE s.class_id = c.class_id AND c.class_name IN ("金融數學", "圍棋"));
           

 如果EXISTS後面的查詢有滿足的,則EXISTS後面的話可以了解為TRUE。

查詢結果如下: 

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

8.3 連結查詢

如果結果列來自同一個表,則可以使用子查詢。如果結果列來自多個表,則必須使用聯接(join)。要執行聯接,請在FROM子句中包含多個表。使用逗号作為分隔符,通常包括WHERE子句來指定聯接列。 

可以對在FROM子句中命名的表使用别名。别名和表名之間用空格隔開。别名可用于在出現歧義時限定列名。

連結查詢多用于複雜的連表查詢,可以通過ON關鍵字後面的資訊将幾個表連在一起,友善我們進一步加條件進行篩選。

MySQL有多種連接配接方式,連結方式可以參考下圖,我目前在工作實踐中用的最多的是左連結(和右連結,二者隻是連結方向不同,效果一樣)。其他的連結方式這裡不做總結,建議重點學會左連結,右連結則同理。

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

 圖檔引用:sql左外連接配接和右外連接配接的差別

用了連結(join)後必用ON關鍵字,ON後面跟兩個表的連結依據,在實際工作中多用索引進行連結。左連結和右連結用的較多,從邏輯上看隻是把表放在左邊或者右邊的差別,在實際工作中我總結出了一個規律:對于左連接配接來說,如果我們需要的查詢條件(WHERE後面的條件)主要是A表的,則把A表放在左邊,A LEFT JOIN B ON A的條件。對于右連結同理,如果如果我們需要的查詢條件(WHERE後面的條)主要是A表的,則把A表放在右邊,B RIGHT JOIN A ON A的條件。

SQL的LEFT JOIN 、RIGHT JOIN 、INNER JOIN之間的差別:

  •   LEFT JOIN(左聯接) 傳回包括左表中的所有記錄和右表中聯結字段相等的記錄 
  •   RIGHT JOIN(右聯接) 傳回包括右表中的所有記錄和左表中聯結字段相等的記錄
  •   INNER JOIN(等值連接配接) 隻傳回兩個表中聯結字段相等的行

我用的student表和class表不太适合舉例表連結,建議自己往每個表中加入無法和其他表連結的獨有的值和空值等,自己多練習幾遍,便于了解。

1)左連結(LEFT JOIN)

我們先左連接配接一下,感受一下左連接配接是什麼。讓student表與class表左連接配接:

SELECT * 
FROM student s LEFT JOIN class c
ON s.class_id = c.class_id;
           

連結後的試圖如下:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

我們的連結條件是兩邊的class_id相同。可以觀察到上圖兩個表連結到了一起,且class_id相同。

在左連接配接後我們可以對連結後的表加篩選條件,舉例我們想選擇學金融資料學的同學的姓名,隻需要加限制條件使得class_name為金融數學即可,SQL語句如下:

SELECT s.student_name
FROM student s LEFT JOIN class c
ON s.class_id = c.class_id
WHERE c.class_name = "金融數學";
           

這裡我們在WHERE後面的條件用别名c來專門指定了class_name屬性是class中的,因為class_name隻有class一個表有,是以哪怕不指明是哪個表的,直接用class_name = "金融數學"也是對的。這裡我隻是養成了标明屬性來源的習慣。建議養成。

但是ON後面用了别名s和c來指明class_id分别是哪個表的很有必要,不然容易産生困惑。是以總的建議還是順手指定表名比較好。

上面的SQL語句運作如下:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

2)右連結(RIGHT JOIN)

左連接配接和右連結如果要效果一緻,應該表的順序相反,如果表的順序沒有換,則結果會變。如果把LEFT JOIN換成RIGHT JOIN,兩個表的順序也變了,語句如下:

SELECT *
FROM class c RIGHT JOIN student s
ON s.class_id = c.class_id;
           

表的邏輯空間順序(左右)雖然變了,但是内容并不會變,視圖如下:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

這也就是為什麼我說學會左連接配接即可,右連結隻是變了順序而已。 

3)内連結(INNER JOIN)

INNER JOIN 與 JOIN 是相同的。INNER JOIN 關鍵字在表中存在至少一個比對時傳回行。我這裡的例子不足以了解INNER JOIN:

SELECT *
FROM student s INNER JOIN class c
ON s.class_id = c.class_id;
           

視圖如下:

MySQL學習筆記(三)查詢查(SELECT)的操作  (重點)參考資料:

9 自己的一些心得總結 (随着經驗增加更新)

  1. 多練,看視訊看再多也沒用自己做一遍了解的深。當可以不看視訊就能自己建幾個表,往裡面加入資料,對資料庫進行各種增删改查的時候,就已經了解了資料庫的基礎了。
  2. 資料庫的操作很簡單,會發現一個查詢結果可以用多種SQL查詢得到,但是其中的效率可能會有很大差别,特别是當資料足夠大的時候。建議深入學習資料庫優化等課程,資料庫光用很簡單,但是用好需要下功夫。
  3. 個人感覺資料庫的核心是了解資料庫。SQL語句很簡單,但是學會了也不一定能寫出我們需要的查詢語句,原因就是不了解資料庫,不知道每個資料庫記錄什麼,不知道每個表的字段代表什麼,不清楚表和表之間的關系是什麼……在學習的時候接觸的資料庫都很簡單,但實工作中資料庫可能極大,有上百個資料庫,每個資料庫裡都有幾十個相關的表,每個表裡面都有幾千幾萬幾十萬的資料,是以想要熟練的寫出SQL,不妨先花時間好好讀讀DDL語言,看看comment,問問同僚業務邏輯和他們之間的關系等,磨刀不誤砍柴工。
  4. 工作中遇到不會的要積極搜尋,可能絆倒我們的就是一個小問題,别人也遇到過,要善于借鑒,不要鑽牛角尖。
  5. 寫SQL前先想好我們是要幹什麼,目的是什麼,根據目的來規劃思路(舉例,确定了目的可以确定選擇條件,然後确定連結順序)
  6. 事出反常必有妖,如果發現篩選出的結果很離譜,要多想多看,找問題。自己的主動思考或許很慢,問别人可能一下子就出來了,但是追求效率的同時也不要放棄了獨立思考,加深了解,而且說不定能想要更優化的解決方案。

參考資料:

課堂資料:

X. Zhu(2019). Introduction to Database [PowerPoint slides]. Available: https://ice.xjtlu.edu.cn/course/view.php?id=293

Mysql資料庫設計與操作 (access time: 2021/6/23)

網絡資料:

mySql limit 函數後的參數是什麼意思 (access time: 2021/6/30)

MySQL之CONCAT()的用法 (access time: 2021/6/30)

mysql中group by 的用法解析 (access time: 2021/6/30)

https://blog.csdn.net/weixin_43336305/article/details/94445810 (access time: 2021/6/30)

嵌套查詢和子查詢是一樣的概念嗎? (access time: 2021/7/20)

【SQL】嵌套查詢與子查詢  (access time: 2021/7/20)

SQL INNER JOIN 關鍵字 (access time: 2021/7/20)