數據庫練習-多表聯查

在這裏插入圖片描述

數據庫練習-多表聯查

1多表聯查

查詢所有學生的 name,以及該學生在 score 表中對應的 cnodegree

SELECT no, name FROM student;
+-----+-----------+
| no  | name      |
+-----+-----------+
| 101 | 曾華      |
| 102 | 匡明      |
| 103 | 王麗      |
| 104 | 李軍      |
| 105 | 王芳      |
| 106 | 陸軍      |
| 107 | 王尼瑪    |
| 108 | 張全蛋    |
| 109 | 趙鐵柱    |
+-----+-----------+

SELECT sno, cno, degree FROM score;
+------+-------+--------+
| s_no | c_no  | degree |
+------+-------+--------+
| 103  | 3-105 |     92 |
| 103  | 3-245 |     86 |
| 103  | 6-166 |     85 |
| 105  | 3-105 |     88 |
| 105  | 3-245 |     75 |
| 105  | 6-166 |     79 |
| 109  | 3-105 |     76 |
| 109  | 3-245 |     68 |
| 109  | 6-166 |     81 |
+------+-------+--------+

通過分析可以發現,只要把 score 表中的 sno 字段值替換成 student 表中對應的 name 字段值就可以了,如何做呢?

#	 select 要查詢的字段1,要查詢的字段2,要查詢的字段3 from 這些字段從那個表查,這些字段從那個表查 where 根據那個表的字段進行篩選=根據那個表的字段進行篩選;
mysql> select sname,cno,degree from student,score where student.sno=score.sno;
+--------+-------+--------+
| sname  | cno   | degree |
+--------+-------+--------+
| 王麗   | 3-105 | 92     |
| 王麗   | 3-245 | 86     |
| 王麗   | 6-166 | 85     |
| 王芳   | 3-105 | 88     |
| 王芳   | 3-245 | 75     |
| 王芳   | 6-166 | 79     |
| 趙鐵柱 | 3-105 | 76     |
| 趙鐵柱 | 3-245 | 68     |
| 趙鐵柱 | 6-166 | 81     |
+--------+-------+--------+
9 rows in set (0.08 sec)

查詢所有學生的 sno 、課程名稱 ( course 表中的 name ) 和成績 ( score 表中的 degree ) 列。

mysql> select sname,cname,degree from student,score,course where student.sno=score.sno and score.cno=course.cno;
+--------+------------+--------+
| sname  | cname      | degree |
+--------+------------+--------+
| 王麗   | 計算機導論 | 92     |
| 王麗   | 操作系統   | 86     |
| 王麗   | 數字電路   | 85     |
| 王芳   | 計算機導論 | 88     |
| 王芳   | 操作系統   | 75     |
| 王芳   | 數字電路   | 79     |
| 趙鐵柱 | 計算機導論 | 76     |
| 趙鐵柱 | 操作系統   | 68     |
| 趙鐵柱 | 數字電路   | 81     |
+--------+------------+--------+
9 rows in set (0.10 sec)
2子查詢加分組求平均分

查詢 95031 班學生每門課程的平均成績。

score 表中根據 student 表的學生編號篩選出學生的課堂號和成績:

-- IN (..): 將篩選出的學生號當做 sno 的條件查詢
SELECT sno, c_no, degree FROM score
WHERE sno IN (SELECT no FROM student WHERE class = '95031');
+------+-------+--------+
| sno | cno  | degree |
+------+-------+--------+
| 105  | 3-105 |     88 |
| 105  | 3-245 |     75 |
| 105  | 6-166 |     79 |
| 109  | 3-105 |     76 |
| 109  | 3-245 |     68 |
| 109  | 6-166 |     81 |
+------+-------+--------+

這時只要將 cno 分組一下就能得出 95031 班學生每門課的平均成績:

SELECT c_no, AVG(degree) FROM score
WHERE s_no IN (SELECT no FROM student WHERE class = '95031')
GROUP BY c_no;
+-------+-------------+
| c_no  | AVG(degree) |
+-------+-------------+
| 3-105 |     82.0000 |
| 3-245 |     71.5000 |
| 6-166 |     80.0000 |
+-------+-------------+

3查詢在 3-105 課程中,所有成績高於 109 號同學的記錄。

思路:先查詢出3-105中109號同學的成績,然後在根據查出來的結果去查詢大於當前同學成績的學生

#先查詢出3-105中109號同學的成績
mysql> select degree from score where sno='109' and cno='3-105';
+--------+
| degree |
+--------+
| 76     |
+--------+
1 row in set (0.06 sec)
#根據查出來的結果去查詢大於當前同學成績的學生
#注意:在嵌套查詢時,整個sql語句只能有一個結束符-->分號
mysql>  select * from score where  degree>(select degree from score where sno='109' and cno='3-105') and cno='3-105';
+-----+-------+--------+
| sno | cno   | degree |
+-----+-------+--------+
| 103 | 3-105 | 92     |
| 105 | 3-105 | 88     |
+-----+-------+--------+
2 rows in set (0.06 sec)

4YEAR 函數與帶 IN 關鍵字查詢

查詢所有和 101108 號學生同年出生的 nonamebirthday 列。

# 先查詢出這兩位同學的生日所在年份
#  使用year()函數可以直接選取年份
mysql> select year(sbirthday) from student where sno in('108','109');
+-----------------+
| year(sbirthday) |
+-----------------+
|            1975 |
|            1974 |
+-----------------+
2 rows in set (0.06 sec)
#根據查出來的年份作爲條件去篩選 ,因爲查出來的年份有兩個,所以使用in關鍵字
mysql> select * from student where year(sbirthday) in ( select year(sbirthday) from student where sno in('108','109'));
+-----+--------+------+---------------------+--------+
| sno | sname  | ssex | sbirthday           | sclass |
+-----+--------+------+---------------------+--------+
| 102 | 匡明   | 男   | 1975-10-02 00:00:00 | 95031  |
| 105 | 王芳   | 女   | 1975-02-10 00:00:00 | 95031  |
| 106 | 陸軍   | 男   | 1974-06-03 00:00:00 | 95031  |
| 108 | 張全蛋 | 男   | 1975-02-10 00:00:00 | 95031  |
| 109 | 趙鐵柱 | 男   | 1974-06-03 00:00:00 | 95031  |
+-----+--------+------+---------------------+--------+
5 rows in set (0.10 sec)

5UNION 和 NOTIN 的使用

查詢 計算機系電子工程系 中的不同職稱的教師。

-- NOT: 代表邏輯非
SELECT * FROM teacher WHERE department = '計算機系' AND profession NOT IN (
    SELECT profession FROM teacher WHERE department = '電子工程系'
)
-- 合併兩個集UNION
UNION
SELECT * FROM teacher WHERE department = '電子工程系' AND profession NOT IN (
    SELECT profession FROM teacher WHERE department = '計算機系'
);

6表示所有的 ALL

查詢課程 3-105 且成績高於 3-245score 表。

-- ALL: 符合SQL語句中的所有條件。
-- 也就是說,在 3-105 每一行成績中,都要大於從 3-245 篩選出來全部行纔算符合條件。
SELECT * FROM score WHERE cno = '3-105' AND degree > ALL(
    SELECT degree FROM score WHERE cno = '3-245'
);
+-----+-------+--------+
| sno | cno   | degree |
+-----+-------+--------+
| 103 | 3-105 | 92     |
| 105 | 3-105 | 88     |
+-----+-------+--------+
2 rows in set (0.09 sec)

7ANY 表示至少一個 - DESC ( 降序 )

查詢課程 3-105 且成績 至少 高於 3-245score 表。

SELECT * FROM score WHERE c_no = '3-105';
+------+-------+--------+    
| sno | cno  | degree |
+------+-------+--------+
| 101  | 3-105 |     90 |
| 102  | 3-105 |     91 |
| 103  | 3-105 |     92 |
| 104  | 3-105 |     89 |
| 105  | 3-105 |     88 |
| 109  | 3-105 |     76 |
+------+-------+--------+

SELECT * FROM score WHERE cno = '3-245';
+------+-------+--------+
| s_no | c_no  | degree |
+------+-------+--------+
| 103  | 3-245 |     86 |
| 105  | 3-245 |     75 |
| 109  | 3-245 |     68 |
+------+-------+--------+

-- ANY: 符合SQL語句中的任意條件。
-- 也就是說,在 3-105 成績中,只要有一個大於從 3-245 篩選出來的任意行就符合條件,
-- 最後根據降序查詢結果。
SELECT * FROM score WHERE cno = '3-105' AND degree > ANY(
    SELECT degree FROM score WHERE cno = '3-245'
) ORDER BY degree DESC;
+------+-------+--------+
| sno | cno  | degree |
+------+-------+--------+
| 103  | 3-105 |     92 |
| 102  | 3-105 |     91 |
| 101  | 3-105 |     90 |
| 104  | 3-105 |     89 |
| 105  | 3-105 |     88 |
| 109  | 3-105 |     76 |
+------+-------+--------+

8按等級查詢

建立一個 grade 表代表學生的成績等級,並插入數據:

CREATE TABLE grade (
    low INT(3),
    upp INT(3),
    grade char(1)
);

INSERT INTO grade VALUES (90, 100, 'A');
INSERT INTO grade VALUES (80, 89, 'B');
INSERT INTO grade VALUES (70, 79, 'C');
INSERT INTO grade VALUES (60, 69, 'D');
INSERT INTO grade VALUES (0, 59, 'E');

查詢所有學生的 snocnograde 列。

思路是,使用區間 ( BETWEEN ) 查詢,判斷學生的成績 ( degree ) 在 grade 表的 lowupp 之間。

#語句解釋:兩表聯查,以成績進行區間查詢,當成績在對應的區間的時候顯示;
# select 查詢的字段1,查詢的字段2,查詢的字段3 from 字段來自表1,字段來自表2 where 以成績劃分 between 區間條件1 and 區間條件2;
mysql> select sno,cno,grade from score,grade where degree between low and upp;
+-----+-------+-------+
| sno | cno   | grade |
+-----+-------+-------+
| 103 | 3-105 | A     |
| 103 | 3-245 | B     |
| 103 | 6-166 | B     |
| 105 | 3-105 | B     |
| 105 | 3-245 | C     |
| 105 | 6-166 | C     |
| 109 | 3-105 | C     |
| 109 | 3-245 | D     |
| 109 | 6-166 | B     |
+-----+-------+-------+
9 rows in set (0.06 sec)

9連接查詢

sql的四種連接查詢;

內連接 inner join 或者join 內聯查詢就是兩張表中的的數據,通過某個字段有對應關係,查出相關記錄數據

外連接

​ —>左連接 left join 或者 left outer join 完整顯示左邊的表,右邊的表如果符合條件就顯示,不符合則補 NULL

​ —>右連接 right join 或者 right outer join 完整顯示右邊的表 ,左邊的表如果符合條件就顯示,不符合則補 NULL

​ —>全外連接 full join 或者 full outer join 完全顯示兩張表的數據(mysql不支持)

連接查詢數據準備

CREATE DATABASE testJoin;

CREATE TABLE person (
    id INT,
    name VARCHAR(20),
    cardId INT
);

CREATE TABLE card (
    id INT,
    name VARCHAR(20)
);

INSERT INTO card VALUES (1, '飯卡'), (2, '建行卡'), (3, '農行卡'), (4, '工商卡'), (5, '郵政卡');
SELECT * FROM card;
+------+-----------+
| id   | name      |
+------+-----------+
|    1 | 飯卡      |
|    2 | 建行卡    |
|    3 | 農行卡    |
|    4 | 工商卡    |
|    5 | 郵政卡    |
+------+-----------+

INSERT INTO person VALUES (1, '張三', 1), (2, '李四', 3), (3, '王五', 6);
SELECT * FROM person;
+------+--------+--------+
| id   | name   | cardId |
+------+--------+--------+
|    1 | 張三   |      1 |
|    2 | 李四   |      3 |
|    3 | 王五   |      6 |
+------+--------+--------+

分析兩張表發現,person 表並沒有爲 cardId 字段設置一個在 card 表中對應的 id 外鍵。如果設置了的話,personcardId 字段值爲 6 的行就插不進去,因爲該 cardId 值在 card 表中並沒有。

內連接

要查詢這兩張表中有關係的數據,可以使用 INNER JOIN ( 內連接 ) 將它們連接在一起。

-- INNER JOIN: 表示爲內連接,將兩張表拼接在一起。
-- on: 表示要執行某個條件。
-- 語句解釋:SELECT * FROM 查詢的表名1 INNER JOIN 查詢的表名2 on 篩選條件;
SELECT * FROM person INNER JOIN card on person.cardId = card.id;
+------+--------+--------+------+-----------+
| id   | name   | cardId | id   | name      |
+------+--------+--------+------+-----------+
|    1 | 張三   |      1 |    1 | 飯卡      |
|    2 | 李四   |      3 |    3 | 農行卡    |
+------+--------+--------+------+-----------+

-- 將 INNER 關鍵字省略掉,結果也是一樣的。
-- SELECT * FROM person JOIN card on person.cardId = card.id;

-- ------注意:card 的整張表被連接到了右邊。

左外連接

完整顯示左邊的表 ( person ) ,右邊的表如果符合條件就顯示,不符合則補 NULL

-- LEFT JOIN 也叫做 LEFT OUTER JOIN,用這兩種方式的查詢結果是一樣的。
mysql> select * from person left join card on person.cardid=card.id;
+----+------+--------+------+--------+
| id | name | cardId | id   | name   |
+----+------+--------+------+--------+
|  1 | 張三 |      1 |    1 | 飯卡   |
|  2 | 李四 |      3 |    3 | 農行卡 |
|  3 | 王五 |      6 | NULL | NULL   |
+----+------+--------+------+--------+
3 rows in set (0.07 sec)

右外鏈接

完整顯示右邊的表 ( card ) ,左邊的表如果符合條件就顯示,不符合則補 NULL

#-- right join 也叫做right outer join,用這兩種方式的查詢結果是一樣的。

SELECT * FROM person RIGHT JOIN card on person.cardId = card.id;
+------+--------+--------+------+-----------+
| id   | name   | cardId | id   | name      |
+------+--------+--------+------+-----------+
|    1 | 張三   |      1 |    1 | 飯卡      |
|    2 | 李四   |      3 |    3 | 農行卡    |
| NULL | NULL   |   NULL |    2 | 建行卡    |
| NULL | NULL   |   NULL |    4 | 工商卡    |
| NULL | NULL   |   NULL |    5 | 郵政卡    |
+------+--------+--------+------+-----------+

全外連接

完全顯示兩張表的數據

-- MySQL 不支持這種語法的全外連接
-- SELECT * FROM person FULL JOIN card on person.cardId = card.id;
-- 出現錯誤:
-- ERROR 1054 (42S22): Unknown column 'person.cardId' in 'on clause'

-- MySQL全連接語法,使用 UNION 將兩張表合併在一起。
SELECT * FROM person LEFT JOIN card on person.cardId = card.id
UNION
SELECT * FROM person RIGHT JOIN card on person.cardId = card.id;
+------+--------+--------+------+-----------+
| id   | name   | cardId | id   | name      |
+------+--------+--------+------+-----------+
|    1 | 張三   |      1 |    1 | 飯卡      |
|    2 | 李四   |      3 |    3 | 農行卡    |
|    3 | 王五   |      6 | NULL | NULL      |
| NULL | NULL   |   NULL |    2 | 建行卡    |
| NULL | NULL   |   NULL |    4 | 工商卡    |
| NULL | NULL   |   NULL |    5 | 郵政卡    |
+------+--------+--------+------+-----------+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章