目錄
1. 聯(lián)合查詢
1.1 內(nèi)查詢
1.2 外查詢
1.3 自連接
1.4 子查詢
1.5 合并查詢
1. 聯(lián)合查詢
聯(lián)合查詢,簡單的來講就是多個表聯(lián)合起來進行查詢。這樣的查詢在我們實際的開發(fā)中會用到很多,因此會用笛卡爾積的概念。
啥是笛卡爾積?兩張表經(jīng)過笛卡爾積后得到的新表的列數(shù)是兩表列數(shù)之和,行數(shù)是兩表行數(shù)之積。
我們可以看到下圖中兩表形成一個笛卡爾積后,把這兩張表組成情況的所有的可能性都羅列出來了。因此會造成出現(xiàn)很多無用數(shù)據(jù),這就是笛卡爾積的一個簡單理解。因此,我們在查詢兩個表時得使用一些方法來避免類似于笛卡爾積這種情況的出現(xiàn),這些方法的總稱就是聯(lián)合查詢。
當(dāng)然,上圖兩表中的數(shù)據(jù)沒有任何關(guān)聯(lián),在此解釋一下。?
在我們進入聯(lián)合查詢的各個知識點講解之前,我們先來創(chuàng)建幾張表。下方的所有聯(lián)合查詢都是通過這幾張表來進行演示的。
首先創(chuàng)建一個名為student的表作為學(xué)生表:
//創(chuàng)建student表
mysql> create table student(
-> id int primary key auto_increment,
-> sn varchar(20),
-> name varchar(20),
-> e_mail varchar(20),
-> classes_id int
-> );
Query OK, 0 rows affected (0.02 sec)
//往student表中插入數(shù)據(jù)
mysql> insert into student(id,sn,name,e_mail,classes_id) values
-> (1,23001,'阿三','asan@qq.com',1),
-> (2,23005,'李四','lisi@qq.com',2),
-> (3,23011,'王五',null,2),
-> (4,23002,'趙六','zhaoliu@qq.com',2),
-> (5,23015,'老八',null,1);
Query OK, 5 rows affected (0.00 sec)
Records: 5 Duplicates: 0 Warnings: 0
student表的內(nèi)容為:?
創(chuàng)建一個名為classes的表作為成績表:
//創(chuàng)建表classes
mysql> create table classes(
-> id int primary key auto_increment,
-> name varchar(20),
-> descr varchar(100)
-> );
Query OK, 0 rows affected (0.02 sec)
//往classes中插入數(shù)據(jù)
mysql> insert into classes(id,name,descr) values
-> (1,'計算機專業(yè)','學(xué)習(xí)了C、Java、數(shù)據(jù)結(jié)構(gòu)與算法'),
-> (2,'醫(yī)護專業(yè)','學(xué)習(xí)了康復(fù)相關(guān)知識');
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
classe表的內(nèi)容為:?
創(chuàng)建一個名為course的表作為課程表:
//創(chuàng)建course表
mysql> create table course(
-> id int primary key auto_increment,
-> name varchar(20)
-> );
Query OK, 0 rows affected (0.02 sec)
//往course表中插入數(shù)據(jù)
mysql> insert into course(id,name) values
-> (1,'Java'),
-> (2,'英語'),
-> (3,'數(shù)學(xué)'),
-> (4,'中華傳統(tǒng)文化'),
-> (5,'擺爛');
Query OK, 5 rows affected (0.00 sec)
Records: 5 Duplicates: 0 Warnings: 0
course表的內(nèi)容為:?
創(chuàng)建一個名為score的表作為成績表:
//創(chuàng)建一個score表
mysql> create table score(
-> score int,
-> student_id int,
-> course_id int
-> );
Query OK, 0 rows affected (0.02 sec)
//插入相應(yīng)的數(shù)據(jù)
mysql> insert into score(score,student_id,course_id) values
-> (80,1,1),
-> (60,1,2),
-> (70,1,5),
-> (66,2,4),
-> (88,2,1),
-> (99,3,5),
-> (20,3,1),
-> (78,4,4),
-> (66,4,2),
-> (89,4,1),
-> (99,5,2),
-> (77,5,3),
-> (76,5,4);
Query OK, 13 rows affected (0.01 sec)
Records: 13 Duplicates: 0 Warnings: 0
score表中的內(nèi)容為:?
通過上面創(chuàng)建的四張表,我們可以知道這幾張表之間的聯(lián)系。
當(dāng)然不止上圖三表中之間有聯(lián)系,student表中的classes_id與classes表中的id也是有關(guān)聯(lián)。因此,這四張表之間都是相互關(guān)聯(lián)的,那么我們就可以通過聯(lián)合查詢來操作相應(yīng)的數(shù)據(jù)。
1.1 內(nèi)查詢
內(nèi)查詢是表與表之間通過一些內(nèi)部相同數(shù)據(jù)的關(guān)聯(lián)進行查詢,因此當(dāng)我們把需要查詢的表進行笛卡爾積后,可以根據(jù)表之間內(nèi)部相同的字段來作為連接條件從而篩選到要想的數(shù)據(jù)。內(nèi)連接語法為:
- select 字段 from 表1 別名1 join 表2 別名2 on 連接條件 and 其他連接條件;
- select 字段 from 表1 別名1,表2 別名2 where 連接條件 and 其他連接條件;
如果查我們要找名為阿三同學(xué)的成績,這時就會使用到兩張表:student、score。這兩張表進行笛卡爾積后數(shù)據(jù)非常的冗雜:
mysql> select * from student,score;
足足有65行數(shù)據(jù),我們要查找阿三的同學(xué)的成績會使用到兩個條件:第一個條件為name='阿三',第二個條件就是student.id = score.student_id。這樣就能避免出現(xiàn)其他無效的數(shù)據(jù)。
那么在對兩張表進行笛卡爾積過后,我們有兩種方式來進行查詢阿三同學(xué)的成績,第一種使用join on的方式進行查詢:?
mysql> select name,score from student join score on name='阿三' and student.id=score.student_id;
+------+-------+
| name | score |
+------+-------+
| 阿三 | 80 |
| 阿三 | 60 |
| 阿三 | 70 |
+------+-------+
3 rows in set (0.00 sec)
第二種方式,使用where的方式進行查詢:?
mysql> select name,score from student,score where name='阿三' and student.id = score.student_id;
+------+-------+
| name | score |
+------+-------+
| 阿三 | 80 |
| 阿三 | 60 |
| 阿三 | 70 |
+------+-------+
3 rows in set (0.00 sec)
通過上方代碼之間的比較我們不難發(fā)現(xiàn),join on和where這兩種方式都能達到我們的目的,因此只要能掌握其中一種方式就能達到內(nèi)查詢的效果。注意,上述代碼中我們可以通過.號來引用相關(guān)字段。當(dāng)兩張表中有相同字段name時我們可以通過表1.name來訪問到表1中的name,通過表2.name來訪問到表2中的name。?
經(jīng)過上方簡單的程序相信大家已經(jīng)對內(nèi)查詢有了初步的了解,下面我們來升級難度:查詢所有同學(xué)的總成績,及同學(xué)的個人信息。
首先我們要知道這些數(shù)據(jù)的來源于student和score這兩張表,并且我們要得到student中的所有學(xué)生信息、score中的成績總和,以及條件為student中的id等于score中的student_id。這樣我們就可以寫出以下代碼:
mysql> select stu.id,stu.name,stu.e_mail,stu.classes_id,sum(sco.score)
-> from student stu join score sco on stu.id=sco.student_id
-> group by sco.student_id;
+----+------+----------------+------------+----------------+
| id | name | e_mail | classes_id | sum(sco.score) |
+----+------+----------------+------------+----------------+
| 1 | 阿三 | asan@qq.com | 1 | 210 |
| 2 | 李四 | lisi@qq.com | 2 | 154 |
| 3 | 王五 | NULL | 2 | 119 |
| 4 | 趙六 | zhaoliu@qq.com | 2 | 233 |
| 5 | 老八 | NULL | 1 | 252 |
+----+------+----------------+------------+----------------+
5 rows in set (0.00 sec)
在上述代碼中stu是student的別名,sco是score的別名。因此我們from前就可以使用這兩個別名進行.操作來獲取字段,但這種代碼的可讀性并不太高,建議使用原表名來獲取字段而不是使用別名來獲取字段。如將上方代碼修改為使用表名來.引用字段:
select student.id,student.name,student.e_mail,student.classes_id,sum(score.score)
from student join score on student.id = score.student_id
group by score.student_id;
1.2 外查詢
那么在上述內(nèi)查詢的使用時,其實都是表之間的“內(nèi)連接”,在MySQL中還有一種聯(lián)合查詢叫作“外連接”,也就是現(xiàn)在我們要學(xué)的外查詢。
何為外查詢,如在兩張表中有一部分數(shù)據(jù)是有關(guān)聯(lián)的另一部分數(shù)據(jù)是沒有關(guān)聯(lián)的,我們可以通過外查詢把表1中不存在的數(shù)據(jù)或表2中不存的的數(shù)據(jù)通過外查詢顯示出來。有些抽象,下面我就用實例來講解。外查詢分為左外連接與右外連接,語法為:
- select 字段 from 表1 left join 表2 on 連接條件; --左外連接,表1完全顯示
- select 字段 from 表1 right join 表2 on 連接條件; --右外連接,表2完全顯示
在mytest數(shù)據(jù)庫中創(chuàng)建兩張表,student學(xué)生表和score課程表:
//創(chuàng)建名為mytest的數(shù)據(jù)庫
mysql> create database mytest charset utf8;
Query OK, 1 row affected (0.00 sec)
//使用該數(shù)據(jù)庫
mysql> use mytest;
Database changed
//創(chuàng)建學(xué)生表
mysql> create table student(
-> id int,
-> name varchar(10),
-> sex varchar(10)
-> );
Query OK, 0 rows affected (0.02 sec)
//插入對應(yīng)數(shù)據(jù)
mysql> insert into student values
-> (101,'張三','男'),
-> (102,'李四','女'),
-> (103,'王五','男');
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0
//創(chuàng)建成績表
mysql> create table score(
-> student_id int,
-> score int
-> );
Query OK, 0 rows affected (0.02 sec)
//插入相應(yīng)數(shù)據(jù)
mysql> insert into score values (101,99),(102,89);
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
這兩張表的內(nèi)容為:
有一需求:查找這兩張表的id,name,score這三條信息,要求為有效信息。當(dāng)我們通過內(nèi)連接,左外連接以及右外連接進行查詢就會發(fā)現(xiàn)不同之處。
內(nèi)連接查詢:
mysql> select student.id,student.name,score.score from student join score on student.id = score.student_id;
+------+------+-------+
| id | name | score |
+------+------+-------+
| 101 | 張三 | 99 |
| 102 | 李四 | 89 |
+------+------+-------+
2 rows in set (0.00 sec)
我們發(fā)現(xiàn)使用內(nèi)連接進行查詢得到的結(jié)果是正確的,關(guān)聯(lián)性比較強。我們再來看左連接查詢:
mysql> select student.id,student.name,score.score from student left join score on student.id = score.student_id;
+------+------+-------+
| id | name | score |
+------+------+-------+
| 101 | 張三 | 99 |
| 102 | 李四 | 89 |
| 103 | 王五 | NULL |
+------+------+-------+
3 rows in set (0.00 sec)
通過上述代碼我們發(fā)現(xiàn),查詢的結(jié)果并不有效。把score表中不存在的字段給查詢出來了,我們可以把student和score這兩張表看作兩個數(shù)學(xué)里面的集合,這樣就不難理解:
當(dāng)我們的連接條件為student.id=score.student_id時,我們通過左外連接時強制要得到左表也就是student表中的信息,那么student表中id為103的行中沒有score值,此時就會顯示null。右連接則不會出現(xiàn)這種情況:
mysql> select id,name,score from student right join score on student.id = score.student_id;
+------+------+-------+
| id | name | score |
+------+------+-------+
| 101 | 張三 | 99 |
| 102 | 李四 | 89 |
+------+------+-------+
2 rows in set (0.00 sec)
因為右連接根據(jù)右表也就是score表進行查詢,score表中關(guān)于id的信息有101和102因此通過條件為student.id=score.student_id進行查詢后得到的結(jié)果也是存在的。
1.3?自連接
自連接是一種特殊情況下才使用的查詢方式,它是一種取巧的查詢方式,何為取巧?我們通過上方的內(nèi)連接與外連接的學(xué)習(xí)知道了這兩種都是表與表之間進行連接的,而自連接它是表自己和自己進行連接的,因此我認為它是取巧的一種方式。
如使用自連接查找Java成績要大于擺爛成績:
因為是自連接所以只能用到score這一張表。此外,我們需要知道Java成績的課程id和擺爛成績的課程id這樣才能去比較它們的成績。
?因此,我們可以寫出以下代碼:
mysql> select
-> s1.*
-> from
-> score s1,
-> score s2
-> where
-> s1.student_id = s2.student_id
-> and s1.score<s2.score
-> and s1.course_id = 1
-> and s2.course_id = 5;
+-------+------------+-----------+
| score | student_id | course_id |
+-------+------------+-----------+
| 20 | 3 | 1 |
+-------+------------+-----------+
1 row in set (0.00 sec)
當(dāng)然,我們也可以使用join on方式來實現(xiàn):
mysql> select
-> s1.*
-> from
-> score s1
-> join
-> score s2
-> on
-> s1.student_id = s2.student_id
-> and s1.score<s2.score
-> and s1.course_id = 1
-> and s2.course_id = 5;
+-------+------------+-----------+
| score | student_id | course_id |
+-------+------------+-----------+
| 20 | 3 | 1 |
+-------+------------+-----------+
1 row in set (0.00 sec)
我們可以看到,Java小于擺爛的成績只有一條。
1.4 子查詢
子查詢是指嵌入在其他sql語句中的select語句,也叫嵌套查詢。什么意思呢,就是在查詢一些數(shù)據(jù)的時候使用另一條select語句作為查詢條件,從而達到特定的查詢效果。
如查找老八及與同班級的學(xué)生,首先我們要查找student表中的所有信息,在where條件后面再加上條件。這個條件為classes_id=老八的classes_id,注意老八的classes_id可以使用另一條select語句來查詢。因此可以寫出以下代碼:
mysql> select * from student where classes_id=(select classes_id from student where name = '老八');
+----+-------+------+-------------+------------+
| id | sn | name | e_mail | classes_id |
+----+-------+------+-------------+------------+
| 1 | 23001 | 阿三 | asan@qq.com | 1 |
| 5 | 23015 | 老八 | NULL | 1 |
+----+-------+------+-------------+------------+
2 rows in set (0.01 sec)
使用in關(guān)鍵字也能做到嵌套查詢這種效果,如查詢與李四同班的同學(xué)信息:
mysql> select * from student where classes_id in (select classes_id from student where name = '李四');
+----+-------+------+----------------+------------+
| id | sn | name | e_mail | classes_id |
+----+-------+------+----------------+------------+
| 2 | 23005 | 李四 | lisi@qq.com | 2 |
| 3 | 23011 | 王五 | NULL | 2 |
| 4 | 23002 | 趙六 | zhaoliu@qq.com | 2 |
+----+-------+------+----------------+------------+
3 rows in set (0.00 sec)
注意,in關(guān)鍵可以表示一個范圍,只要是滿足in()里面的內(nèi)容就可以被查詢出來,查詢一個字段滿足5,6,7這三個條件。則字段 in(5,6,7)即可。
1.5 合并查詢
在實際應(yīng)用中,為了合并多個select的執(zhí)行結(jié)果,可以使用集合操作符 union,union all。使用union和union all時,前后查詢的結(jié)果集中,字段需要一致。
union操作符:
查找id<3并且name=擺爛的課程,我們會用到course表,使用兩個select語句進行查詢我們會使用union這個操作符進行連接,因此有以下代碼:
mysql> select * from course where id < 3 union select * from course where name = '擺爛';
+----+------+
| id | name |
+----+------+
| 1 | Java |
| 2 | 英語 |
| 5 | 擺爛 |
+----+------+
3 rows in set (0.00 sec)
或者我們使用or來實現(xiàn):
mysql> select * from course where id < 3 or name = '擺爛';
注意,使用union操作符用于取得兩個結(jié)果集的并集。當(dāng)使用該操作符時,會自動去掉結(jié)果集中的重復(fù)行。
union all操作符:
該操作符用于取得兩個結(jié)果集的并集。當(dāng)使用該操作符時,不會去掉結(jié)果集中的重復(fù)行。如查詢id<3或者name='Java'的課程:
mysql> select * from course where id < 3 union all select * from course where name = 'Java';
+----+------+
| id | name |
+----+------+
| 1 | Java |
| 2 | 英語 |
| 1 | Java |
+----+------+
3 rows in set (0.00 sec)
我們可以看到,重復(fù)被查詢的Java字段出現(xiàn)了兩次。
今天這篇博文內(nèi)容比較豐富,大家下來了可以自行測試每個查詢所實現(xiàn)的效果,只有自己嘗試了并且實現(xiàn)了一些效果,這樣才會更好的掌握這些知識點。
文章來源:http://www.zghlxwxcb.cn/news/detail-422636.html
本期博文到這里就結(jié)束,感謝各位的閱讀。文章來源地址http://www.zghlxwxcb.cn/news/detail-422636.html
到了這里,關(guān)于MySQL數(shù)據(jù)庫,聯(lián)合查詢的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!