原文在我的 Github 中,歡迎訂閱。
前言
前幾篇文章
之所以把數據查詢單拉一個文章,是因爲查詢牽扯的知識點比較多,可以說在增刪改查裏,查的複雜度也是最高的。
之前已經瞭解一點像WHERE id=2
這種非常簡單的條件語句。
單表查詢非常簡單,但開發中更多的是多表查詢,那我們以多表查詢來說道說道。
熱熱身
我們在處理數據時通過某個字段來查另一個跟它有關的信息,除了在數據庫中經常這樣操作,在前端也有類似情況。
先看一段前端經常遇到的數據:
{
province:'江蘇省',
citys:[
'南京市',
'蘇州市',
'無錫市'
]
}
上面是把省市都揉到一起了,只嵌套了兩層,但如果嵌套個四五層,就像這樣:
{
province:'江蘇省',
children:[
{
name:'城市1',
children:[
name:'江寧區',
children:[
name:'XX小區'
]
]
},
{
name:'城市2',
children:[
name:'AA區',
children:[
name:'BB小區'
]
]
}
]
}
這種數據解析起來會瘋。
我們一直說數據扁平化,來 我們扁平一把:
// 省
const provice = [
{
province:'江蘇省',
province_id: 1001
},
{
province:'浙江省',
province_id: 1002
},
...
]
// 市
const citys = [
{
name:'南京市',
province_id: 1001
},
{
name:'蘇州市',
province_id: 1001
},
{
name:'杭州市',
province_id: 1002
},
{
name:'嘉興市',
province_id: 1002
},
...
]
//找到江蘇省下所有的城市
const result = citys.filter(i => i.province_id === 1001);
數據扁平化的好處就是,當不需要找城市
的時候,citys
數據跟我無關,只需關心 province
就可以了,而且在查找性能上更快(有時候能免了遞歸)。
上面的例子引出下面這句話:在數據庫中,通過某些字段將表與表關聯起來,這就是關係型數據庫的核心。
準備幾張表
在圖中可以看到 student
表裏有 class_id
,這樣 學生
和 班級
通過 class_id
就有了關聯,在開發中,我們可以通過它來查找class
信息。
查詢
我們通過上面幾個表來查詢幾個需求:
- 查詢成績大於 60 分的學生,顯示學生的姓名和成績
- 查詢姓
馬
的老師的個數 - 查詢沒有學過
馬上來
老師課的學生姓名 - 查詢所有學生的姓名、選課數量、成績總和
我們一個一個來並分析。
查詢成績大於 60 分的學生,顯示學生的姓名和成績
SELECT t1.student_name, t2.number FROM
student t1 LEFT JOIN score t2 ON t1.id=t2.student_id
WHERE t2.number>60;
先看結果:
得到了正確數據。
分析語句:t1
和t2
分別是 student 和 score 的別名。
細心的同學能看出,我把上面的 sql 語句用三行來顯示,這是有寓意的喲:
- 第一行:要查詢的字段,這個非常好理解
- 第二行:其實它的結果是個臨時表!即對應查詢語句裏的 table_name !
- 第三行:通俗易通的
WHERE
條件語句
也就是說,它依然是符合通用語法:
SELECT column_name,column_name
FROM table_name
[WHERE Clause]
[LIMIT N][ OFFSET M]
只不過第二行生成了一個臨時表。
這裏牽扯到了 JOIN ON
語法,我會在後面的章節中專門細說,這裏推薦幾篇相關文章:
- 圖解 SQL 裏的各種 JOIN
- 圖解SQL的inner join、left /right join、 outer join區別
- [SQL多表查詢:SQL JOIN連接查詢各種用法總結
天空未藍](https://zhuanlan.zhihu.com/p/...
查詢姓馬的老師的個數
SELECT COUNT(id) AS teacher_num FROM teacher WHERE teacher_name LIKE '馬%';
解析:
- COUNT(fieldName): COUNT 函數用於統計某字段數量
- AS: 取別名
- LIKE:一般與
%
使用,模糊搜索,如果不用%
相當於精確搜索。 - %:表示任意字符,類似於正則表達式裏的
*
查詢所有學生的姓名、選課數量、成績總和
這個查詢比較複雜,我們先上 sql :
SELECT
t1.student_name,
IFNULL(t2.course_num,0) AS course_num,
IFNULL(t2.sum_number,0) AS sum_number FROM
student t1
LEFT JOIN
(SELECT student_id,count(id) course_num, SUM(number) AS sum_number FROM score GROUP BY student_id) t2
ON t1.id=t2.student_id;
再看下結果:
先!不!要!慌! 我們一點一點來解析。
現在你腦海裏應該先浮現出通用查詢語句:
SELECT column_name,column_name
FROM table_name
[WHERE Clause]
[LIMIT N][ OFFSET M]
而圖中的查詢語句翻譯過來就是:
SELECT 學生名, 選課數量, 成績總和 FROM 表;
然後我們來拆分上圖中的查詢:
先看 SELECT student_id,count(id) course_num, SUM(number) AS sum_number FROM score GROUP BY student_id
,我們單獨來執行這句看看結果:
這條語句爲我們生成了一個表,它顯示了 學生id、選課數、總成績,所以這張表示核心,但需求是讓我們展示所有的學生,所以我們必須依賴student
查。
如果把上圖中查出來的結果 命名爲t2
,就會變成:
SELECT
t1.student_name, IFNULL(t2.course_num,0) AS course_num, IFNULL(t2.sum_number,0) AS sum_number
FROM student t1 LEFT JOIN t2
ON t1.id=t2.student_id;
再去掉些“多餘”的部分:
SELECT
t1.student_name, t2.course_num, t2.sum_number
FROM student t1 LEFT JOIN t2
ON t1.id=t2.student_id;
哈哈,是不是一下就看懂了呢?
這裏再介紹下語句裏沒見過的東東:
- IFNULL(a,b):類似常見的 if 語句,判斷 a 是否爲 null,如果是則顯示 b。
- COUNT():對讀取的數據中的某字段計算出個數,一般用於查詢出數據的條數。
- SUM():求和,對讀取數據中的某個字段求和。
- GROUP BY:通過 GROUP BY 可以設定通過哪些字段對讀取的數據進行分組排序(默認升序),需要注意的是,GROUP BY 有分組聚合功能。
關於GROUP BY
有幾篇文章可以看看:
附建表語句
下面是幾個表的建表語句:
-- 班級表
CREATE TABLE class(
id INT UNSIGNED PRIMARY KEY auto_increment,
caption VARCHAR(30) COMMENT '班級名'
);
-- 學生表
CREATE TABLE student(
id INT UNSIGNED PRIMARY KEY auto_increment,
student_name CHAR(30) COMMENT '學生名',
gender CHAR(30) DEFAULT NULL COMMENT '學生性別',
class_id INT DEFAULT NULL COMMENT '班級id'
);
-- 老師表
CREATE TABLE teacher(
id INT UNSIGNED PRIMARY KEY auto_increment,
teacher_name CHAR(30) COMMENT '教師名'
);
-- 課程表
CREATE TABLE course(
id INT UNSIGNED PRIMARY KEY auto_increment,
course_name CHAR(30) COMMENT '課程名',
teacher_id INT DEFAULT NULL COMMENT'教師id'
);
-- 成績表
CREATE TABLE score(
id INT UNSIGNED PRIMARY KEY auto_increment,
number INT DEFAULT NULL COMMENT '分數',
student_id INT DEFAULT NULL COMMENT '學生id',
course_id INT DEFAULT NULL COMMENT '課程id'
);
總結
這篇文章主要了解查詢,然而這也只是一個練習而已,實際開發中比這難的查詢有很多,需要自己平常沒事多練習。
今天工作比價忙,文章寫的可能有點糙,如果有哪裏不正確的地方歡迎指正。