天天看點

10@mysql資料庫多表查詢查詢語句(union、内連接配接、外連接配接)

文章目錄

  • ​​mysql資料庫多表查詢​​
  • ​​一、多表查詢分類​​
  • ​​二、多表查詢準備​​
  • ​​三、多表連接配接查詢​​
  • ​​1、 交叉連接配接( 笛卡爾積查詢 )​​
  • ​​1)笛卡爾積查詢介紹​​
  • ​​2)笛卡爾積查詢使用​​
  • ​​2、内連接配接(inner join on)​​
  • ​​1)inner join on介紹​​
  • ​​2)inner join on的使用​​
  • ​​3、外連接配接(左連接配接 left join on )​​
  • ​​1)left join on 介紹​​
  • ​​2)left join on的使用​​
  • ​​4、外連接配接(右連接配接 right join on )​​
  • ​​1)right join on介紹​​
  • ​​2)right join on的使用​​
  • ​​5、全外連接配接( union )​​
  • ​​1)union介紹​​
  • ​​2)union的使用​​
  • ​​四、符合條件連接配接查詢​​
  • ​​五、子查詢​​
  • ​​1、帶in關鍵字的子查詢​​
  • ​​2、帶any關鍵字的子查詢​​
  • ​​3、帶all關鍵字的子查詢​​
  • ​​4、帶比較運算符的子查詢​​
  • ​​5、帶exists關鍵字的子查詢​​
  • ​​1)in與exists​​
  • ​​2) **not in與 not exists**​​
  • ​​3)示例:​​
  • ​​6、案列​​
  • ​​六、綜合練習​​
  • ​​1、實列準備​​
  • ​​2、表結構​​
  • ​​3、sql的使用​​

mysql資料庫多表查詢

一、多表查詢分類

1》多表連接配接查詢
2》複合條件連接配接查詢
3》子查詢      

二、多表查詢準備

#建表
create table department(
id int,
name varchar(20) 
);

create table employee(
id int primary key auto_increment,
name varchar(20),
sex enum('male','female') not null default 'male',
age int,
dep_id int
);

#插入資料
insert into department values
(200,'技術'),
(201,'人力資源'),
(202,'銷售'),
(203,'營運');

insert into employee(name,sex,age,dep_id) values
('egon','male',18,200),
('alex','female',48,201),
('wupeiqi','male',38,201),
('yuanhao','female',28,202),
('liwenzhou','male',18,200),
('jingliyang','female',18,204)
;


#檢視表結構和資料
mysql> desc department;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| name | varchar(20) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+

mysql> desc employee;
+--------+-----------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------+-----------------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(20) | YES | | NULL | |
| sex | enum('male','female') | NO | | male | |
| age | int(11) | YES | | NULL | |
| dep_id | int(11) | YES | | NULL | |
+--------+-----------------------+------+-----+---------+----------------+

mysql> select * from department;
+------+--------------+
| id | name |
+------+--------------+
| 200 | 技術 |
| 201 | 人力資源 |
| 202 | 銷售 |
| 203 | 營運 |
+------+--------------+

mysql> select * from employee;
+----+------------+--------+------+--------+
| id | name | sex | age | dep_id |
+----+------------+--------+------+--------+
| 1 | egon | male | 18 | 200 |
| 2 | alex | female | 48 | 201 |
| 3 | wupeiqi | male | 38 | 201 |
| 4 | yuanhao | female | 28 | 202 |
| 5 | liwenzhou | male | 18 | 200 |
| 6 | jingliyang | female | 18 | 204 |
+----+------------+--------+------+--------+

   #表department與employee      

三、多表連接配接查詢

##!!!!重點:外連結文法

SELECT 字段清單
    FROM 表1 INNER|LEFT|RIGHT JOIN 表2
    ON 表1.字段 = 表2.字段;      

1、 交叉連接配接( 笛卡爾積查詢 )

不适用任何比對條件,生成笛卡爾積
1)笛卡爾積查詢介紹
#select * from 表一,表二      
2)笛卡爾積查詢使用
select * from emp,dep;      #将兩張表拼在一起

select * from emp,dep where dep.id = emp.dep_id;    #找到兩張表中對應的關系記錄

select emp.name from dep,emp where dep.id = emp.dep_id and dep.name='技術';         #拿到篩選後的技術部門資料中emp.name的資料      
mysql> select * from employee,department;
+----+------------+--------+------+--------+------+--------------+
| id | name       | sex    | age  | dep_id | id   | name         |
+----+------------+--------+------+--------+------+--------------+
|  1 | egon       | male   |   18 |    200 |  200 | 技術         |
|  1 | egon       | male   |   18 |    200 |  201 | 人力資源     |
|  1 | egon       | male   |   18 |    200 |  202 | 銷售         |
|  1 | egon       | male   |   18 |    200 |  203 | 營運         |
|  2 | alex       | female |   48 |    201 |  200 | 技術         |
|  2 | alex       | female |   48 |    201 |  201 | 人力資源     |
|  2 | alex       | female |   48 |    201 |  202 | 銷售         |
|  2 | alex       | female |   48 |    201 |  203 | 營運         |
|  3 | wupeiqi    | male   |   38 |    201 |  200 | 技術         |
|  3 | wupeiqi    | male   |   38 |    201 |  201 | 人力資源     |
|  3 | wupeiqi    | male   |   38 |    201 |  202 | 銷售         |
|  3 | wupeiqi    | male   |   38 |    201 |  203 | 營運         |
|  4 | yuanhao    | female |   28 |    202 |  200 | 技術         |
|  4 | yuanhao    | female |   28 |    202 |  201 | 人力資源     |
|  4 | yuanhao    | female |   28 |    202 |  202 | 銷售         |
|  4 | yuanhao    | female |   28 |    202 |  203 | 營運         |
|  5 | liwenzhou  | male   |   18 |    200 |  200 | 技術         |
|  5 | liwenzhou  | male   |   18 |    200 |  201 | 人力資源     |
|  5 | liwenzhou  | male   |   18 |    200 |  202 | 銷售         |
|  5 | liwenzhou  | male   |   18 |    200 |  203 | 營運         |
|  6 | jingliyang | female |   18 |    204 |  200 | 技術         |
|  6 | jingliyang | female |   18 |    204 |  201 | 人力資源     |
|  6 | jingliyang | female |   18 |    204 |  202 | 銷售         |
|  6 | jingliyang | female |   18 |    204 |  203 | 營運         |      

2、内連接配接(inner join on)

隻連接配接比對的行
1)inner join on介紹
在寫sql語句的時候,讓我們對語句有一個清晰的區分,增強代碼的可讀性,聯表的操作和查詢的操作有個明确的區分,就用到了内連接配接,左連結,右連結的方式inner join on就是内連接配接的意思,内連接配接的方式就一個弊端就是,當兩個表的資料中無法通過聯表指定的字段對應上的時候,就無法顯示這些資料,類似集合中交集的意思
2)inner join on的使用
#第一步:連表
  select * from dep inner join emp on dep.id=emp.dep_id;


#第二步: 過濾
  select * from dep inner join emp on dep.id=emp.dep_id where dep.name='技術';



#第三步:找對應字段資料
  select emp.name from dep inner join emp on dep.id=emp.dep_id where dep.name='技術';      
#找兩張表共有的部分,相當于利用條件從笛卡爾積結果中篩選出了正确的結果
  #department沒有204這個部門,因而employee表中關于204這條員工資訊沒有比對出來
  
  
mysql> select employee.id,employee.name,employee.age,employee.sex,department.name from employee inner join department on employee.dep_id=department.id; 
+----+-----------+------+--------+--------------+
| id | name      | age  | sex    | name         |
+----+-----------+------+--------+--------------+
|  1 | egon      |   18 | male   | 技術         |
|  2 | alex      |   48 | female | 人力資源     |
|  3 | wupeiqi   |   38 | male   | 人力資源     |
|  4 | yuanhao   |   28 | female | 銷售         |
|  5 | liwenzhou |   18 | male   | 技術         |
+----+-----------+------+--------+--------------+



#上述sql等同于
mysql> select employee.id,employee.name,employee.age,employee.sex,department.name from employee,department where employee.dep_id=department.id;      

3、外連接配接(左連接配接 left join on )

優先顯示左表全部記錄
1)left join on 介紹
左連接配接的意思就是在内連接配接的基礎上增加左邊有,右邊沒有的資料,将左邊的表作為主表,右邊的表作為輔表,當輔表的資料沒辦法對應上左表的資料時,就通過null來表示(把左表的所有資料都顯示)
2)left join on的使用
#實列:
select * from dep left join emp on dep.id=emp.dep_id;


#以左表為準,即找出所有員工資訊,當然包括沒有部門的員工

 #本質就是:在内連接配接的基礎上增加左邊有右邊沒有的結果


mysql> select employee.id,employee.name,department.name as depart_name from employee left join department on employee.dep_id=department.id;
+----+------------+--------------+
| id | name       | depart_name  |
+----+------------+--------------+
|  1 | egon       | 技術         |
|  5 | liwenzhou  | 技術         |
|  2 | alex       | 人力資源     |
|  3 | wupeiqi    | 人力資源     |
|  4 | yuanhao    | 銷售         |
|  6 | jingliyang | NULL         |      

4、外連接配接(右連接配接 right join on )

優先顯示右表全部記錄
1)right join on介紹
右連接配接于左連接配接的用法使一樣的,不過右連接配接是将右表作為主表,左表作為輔表
2)right join on的使用
#實列:
select * from dep right join emp on dep.id=emp.dep_id;


#以右表為準,即找出所有部門資訊,包括沒有員工的部門

#本質就是:在内連接配接的基礎上增加右邊有左邊沒有的結果

mysql> select employee.id,employee.name,department.name as depart_name from employee right join department on employee.dep_id=department.id;
+------+-----------+--------------+
| id   | name      | depart_name  |
+------+-----------+--------------+
|    1 | egon      | 技術         |
|    2 | alex      | 人力資源     |
|    3 | wupeiqi   | 人力資源     |
|    4 | yuanhao   | 銷售         |
|    5 | liwenzhou | 技術         |
| NULL | NULL      | 營運         |      

5、全外連接配接( union )

顯示左右兩個表全部記錄
1)union介紹
不管是内連接配接還是左連接配接,右連接配接,都會由一些資料使無法顯示出來的,那麼就可以用全連接配接的方式來連結,寫法是寫一個左連接配接,一個右連結,中間用union 來連接配接
2)union的使用
#實列:
 select * from dep left join emp on dep.id=emp.dep_id union select * from dep right join emp on dep.id=emp.dep_id;
 
 
 
 #全外連接配接:在内連接配接的基礎上增加左邊有右邊沒有的和右邊有左邊沒有的結果
  #注意:mysql不支援全外連接配接 full JOIN
  
  #強調:mysql可以使用此種方式間接實作全外連接配接
select * from employee left join department on employee.dep_id = department.id
union
select * from employee right join department on employee.dep_id = department.id
;


#檢視結果
+------+------------+--------+------+--------+------+--------------+
| id   | name       | sex    | age  | dep_id | id   | name         |
+------+------------+--------+------+--------+------+--------------+
|    1 | egon       | male   |   18 |    200 |  200 | 技術         |
|    5 | liwenzhou  | male   |   18 |    200 |  200 | 技術         |
|    2 | alex       | female |   48 |    201 |  201 | 人力資源     |
|    3 | wupeiqi    | male   |   38 |    201 |  201 | 人力資源     |
|    4 | yuanhao    | female |   28 |    202 |  202 | 銷售         |
|    6 | jingliyang | female |   18 |    204 | NULL | NULL         |
| NULL | NULL       | NULL   | NULL |   NULL |  203 | 營運         |
+------+------------+--------+------+--------+------+--------------+


#注意 union與union all的差別:union會去掉相同的紀錄      

四、符合條件連接配接查詢

#示例1:以内連接配接的方式查詢employee和department表,并且employee表中的age字段值必須大于25,即找出年齡大于25歲的員工以及員工所在的部門
select employee.name,department.name from employee inner join department
    on employee.dep_id = department.id
    where age > 25;




#示例2:以内連接配接的方式查詢employee和department表,并且以age字段的升序方式顯示
select employee.id,employee.name,employee.age,department.name from employee,department
    where employee.dep_id = department.id
    and age > 25
    order by age asc;      

五、子查詢

子查詢是将一個查詢的結果作為另一個查詢的條件
1》#子查詢是将一個查詢語句嵌套在另一個查詢語句中

2》#内層查詢語句的查詢結果,可以為外層查詢語句提供查詢條件。

3》#子查詢中可以包含:IN、NOT IN、ANY、ALL、EXISTS 和 NOT EXISTS等關鍵字

4》#還可以包含比較運算符:= 、 !=、> 、<等


#實列:
select name from emp where dep_id = (select id from dep where name = '技術');      

1、帶in關鍵字的子查詢

#查詢平均年齡在25歲以上的部門名
select id,name from department
    where id in 
        (select dep_id from employee group by dep_id having avg(age) > 25);



#檢視技術部員工姓名
select name from employee
    where dep_id in 
        (select id from department where name='技術');



#檢視不足1人的部門名(子查詢得到的是有人的部門id)
select name from department where id not in (select distinct dep_id from employee);      
##!!!!!!注意not in


  not in 無法處理null的值,即子查詢中如果存在null的值,not in将無法處理,如下

mysql> select * from emp;
+----+------------+--------+------+--------+
| id | name | sex | age | dep_id |
+----+------------+--------+------+--------+
| 1 | egon | male | 18 | 200 |
| 2 | alex | female | 48 | 201 |
| 3 | wupeiqi | male | 38 | 201 |
| 4 | yuanhao | female | 28 | 202 |
| 5 | liwenzhou | male | 18 | 200 |
| 6 | jingliyang | female | 18 | 204 |
| 7 | xxx | male | 19 | NULL |
+----+------------+--------+------+--------+
7 rows in set (0.00 sec)

mysql> select * from dep;
+------+--------------+
| id | name |
+------+--------------+
| 200 | 技術 |
| 201 | 人力資源 |
| 202 | 銷售 |
| 203 | 營運 |
+------+--------------+
4 rows in set (0.00 sec)

# 子查詢中存在null
mysql> select * from dep where id not in (select distinct dep_id from emp);
Empty set (0.00 sec)

# 解決方案如下
mysql> select * from dep where id not in (select distinct dep_id from emp where dep_id is not null);
+------+--------+
| id | name |
+------+--------+
| 203 | 營運 |
+------+--------+
1 row in set (0.00 sec)

mysql>      

2、帶any關鍵字的子查詢

#在 SQL 中 ANY 和 SOME 是同義詞,SOME 的用法和功能和 ANY 一模一樣。

   
   
   #ANY 和 IN 運算符不同之處一
ANY 必須和其他的比較運算符共同使用,而且ANY必須将比較運算符放在 ANY 關鍵字之前,所比較的值需要比對子查詢中的任意一個值,這也就是 ANY 在英文中所表示的意義

   例如:#使用 IN 和使用 ANY運算符得到的結果是一緻的
select * from employee where salary = any (
select max(salary) from employee group by depart_id);

select * from employee where salary in (
select max(salary) from employee group by depart_id);

結論:也就是說“=ANY”等價于 IN 運算符,而“<>ANY”則等價于 NOT IN 運算符

  
  
  
  
  
  #ANY和 IN 運算符不同之處二
ANY 運算符不能與固定的集合相比對,比如下面的 SQL 語句是錯誤的

SELECT
*
FROM
T_Book
WHERE
FYearPublished < ANY (2001, 2003, 2005)      

3、帶all關鍵字的子查詢

#all同any類似,隻不過all表示的是所有,any表示任一
   
   
   
1>#查詢出那些薪資比所有部門的平均薪資都高的員工=》薪資在所有部門平均線以上的狗币資本家
select * from employee where salary > all (
select avg(salary) from employee group by depart_id);



2>#查詢出那些薪資比所有部門的平均薪資都低的員工=》薪資在所有部門平均線以下的無産階級勞苦大衆
select * from employee where salary < all (
select avg(salary) from employee group by depart_id);



3>#查詢出那些薪資比任意一個部門的平均薪資低的員工=》薪資在任一部門平均線以下的員工select * from employee where salary < any ( select avg(salary) from employee group by depart_id); 



4>#查詢出那些薪資比任意一個部門的平均薪資高的員工=》薪資在任一部門平均線以上的員工
select * from employee where salary > any (
select avg(salary) from employee group by depart_id);      

4、帶比較運算符的子查詢

#比較運算符:=、!=、>、>=、<、<=、<>


#查詢大于所有人平均年齡的員工名與年齡
mysql> select name,age from emp where age > (select avg(age) from emp);
+---------+------+
| name | age |
+---------+------+
| alex | 48 |
| wupeiqi | 38 |
+---------+------+
2 rows in set (0.00 sec)





#查詢大于部門内平均年齡的員工名、年齡
select t1.name,t1.age from emp t1
inner join 
(select dep_id,avg(age) avg_age from emp group by dep_id) t2
on t1.dep_id = t2.dep_id
where t1.age > t2.avg_age;      

5、帶exists關鍵字的子查詢

EXISTS關字鍵字表示存在

在使用EXISTS關鍵字時,内層查詢語句不傳回查詢的記錄

而是傳回一個真假值 : True或False

當傳回True時,外層查詢語句将進行查詢;當傳回值為False時,外層查詢語句不進行查詢

#department表中存在dept_id=203,Ture
mysql> select * from employee
    ->     where exists
    ->         (select id from department where id=200);
+----+------------+--------+------+--------+
| id | name       | sex    | age  | dep_id |
+----+------------+--------+------+--------+
|  1 | egon       | male   |   18 |    200 |
|  2 | alex       | female |   48 |    201 |
|  3 | wupeiqi    | male   |   38 |    201 |
|  4 | yuanhao    | female |   28 |    202 |
|  5 | liwenzhou  | male   |   18 |    200 |
|  6 | jingliyang | female |   18 |    204 |
+----+------------+--------+------+--------+





#department表中存在dept_id=205,False
mysql> select * from employee
    ->     where exists
    ->         (select id from department where id=204);
Empty set (0.00 sec)      
1)in與exists
!!!!!!當in和exists在查詢效率上比較時,in查詢的效率快于exists的查詢效率!!!!!!


==============================exists==============================
# exists
exists後面一般都是子查詢,後面的子查詢被稱做相關子查詢(即與主語句相關),當子查詢傳回行數時,exists條件傳回true,
否則傳回false,exists是不傳回清單的值的,exists隻在乎括号裡的資料能不能查找出來,是否存在這樣的記錄。

# 例:
查詢出那些班級裡有學生的班級
select * from class where exists (select * from stu where stu.cid=class.id)

# exists的執行原理為:
1》依次執行外部查詢:即select * from class 
2》然後為外部查詢傳回的每一行分别執行一次子查詢:即(select * from stu where stu.cid=class.cid)
3》子查詢如果傳回行,則exists條件成立,條件成立則輸出外部查詢取出的那條記錄







==============================in==============================
# in
in後跟的都是子查詢,in()後面的子查詢 是傳回結果集的

# 例
查詢和所有女生年齡相同的男生
select * from stu where sex='男' and age in(select age from stu where sex='女')

# in的執行原理為:
in()的執行次序和exists()不一樣,in()的子查詢會先産生結果集,
然後主查詢再去結果集裡去找符合要求的字段清單去.符合要求的輸出,反之則不輸出.      
2) not in與 not exists
!!!!!!not exists查詢的效率遠遠高與not in查詢的效率。!!!!!!

==========================not  in============================
not in()子查詢的執行順序是:
為了證明not in成立,即找不到,需要一條一條地查詢表,符合要求才傳回子查詢的結果集,不符合的就繼續查詢下一條記錄,直到把表中的記錄查詢完,隻能查詢全部記錄才能證明,并沒有用到索引。
    
    
    
    
=========================not exists==============================
not exists:
如果主查詢表中記錄少,子查詢表中記錄多,并有索引

#例如:查詢那些班級中沒有學生的班級
select * from class

where not exists

(select * from student where student.cid = class.cid)




#not exists的執行順序是:      
3)示例:
#資料準備:
#建立庫
create database db13;
use db13

#建表
create table student(
    id int primary key auto_increment,
    name varchar(16)
);

create table course(
    id int primary key auto_increment,
    name varchar(16),
    comment varchar(20)
);

create table student2course(
    id int primary key auto_increment,
    sid int,
    cid int,
    foreign key(sid) references student(id),
    foreign key(cid) references course(id)
);




#往表插入資料
insert into student(name) values
("egon"),
("lili"),
("jack"),
("tom");

insert into course(name,comment) values
("資料庫","資料倉庫"),
("數學","根本學不會"),
("英語","鳥語花香");


insert into student2course(sid,cid) values
(1,1),
(1,2),
(1,3),
(2,1),
(2,2),
(3,2);



####################### 實列測試  #########################
1》#查詢選修了所有課程的學生id、name:(即該學生根本就不存在一門他沒有選的課程。)
select * from student s where not exists
    (select * from course c where not exists
        (select * from student2course sc where sc.sid=s.id and sc.cid=c.id));


select s.name from student as s
inner join student2course as sc
on s.id=sc.sid
group by s.name 
having count(sc.id) = (select count(id) from course);




2》#查詢沒有選擇所有課程的學生,即沒有全選的學生。(存在這樣的一個學生,他至少有一門課沒有選)
select * from student s where exists
    (select * from course c where not exists
        (select * from student2course sc where sc.sid=s.id and sc.cid=c.id));





3》#查詢一門課也沒有選的學生。(不存這樣的一個學生,他至少選修一門課程)
select * from student s where not exists
    (select * from course c where exists
        (select * from student2course sc where sc.sid=s.id and sc.cid=c.id));




4》#查詢至少選修了一門課程的學生。
select * from student s where exists
    (select * from course c where exists
        (select * from student2course sc where sc.sid=s.id and sc.cid=c.id));      

6、案列

查詢每個部門最新入職的那位員工
############  準備表和記錄  #########

company.employee
    員工id      id                  int             
    姓名        emp_name            varchar
    性别        sex                 enum
    年齡        age                 int
    入職日期     hire_date           date
    崗位        post                varchar
    職位描述     post_comment        varchar
    薪水        salary              double
    辦公室       office              int
    部門編号     depart_id           int



#建立表
create table employee(
id int not null unique auto_increment,
name varchar(20) not null,
sex enum('male','female') not null default 'male', #大部分是男的
age int(3) unsigned not null default 28,
hire_date date not null,
post varchar(50),
post_comment varchar(100),
salary double(15,2),
office int, #一個部門一個屋子
depart_id int
);


#檢視表結構
mysql> desc employee;
+--------------+-----------------------+------+-----+---------+----------------+
| Field        | Type                  | Null | Key | Default | Extra          |
+--------------+-----------------------+------+-----+---------+----------------+
| id           | int(11)               | NO   | PRI | NULL    | auto_increment |
| name         | varchar(20)           | NO   |     | NULL    |                |
| sex          | enum('male','female') | NO   |     | male    |                |
| age          | int(3) unsigned       | NO   |     | 28      |                |
| hire_date    | date                  | NO   |     | NULL    |                |
| post         | varchar(50)           | YES  |     | NULL    |                |
| post_comment | varchar(100)          | YES  |     | NULL    |                |
| salary       | double(15,2)          | YES  |     | NULL    |                |
| office       | int(11)               | YES  |     | NULL    |                |
| depart_id    | int(11)               | YES  |     | NULL    |                |
+--------------+-----------------------+------+-----+---------+----------------+

#插入記錄
#三個部門:教學,銷售,營運
insert into employee(name,sex,age,hire_date,post,salary,office,depart_id) values
('egon','male',18,'20170301','老男孩駐沙河辦事處外交大使',7300.33,401,1), #以下是教學部
('alex','male',78,'20150302','teacher',1000000.31,401,1),
('wupeiqi','male',81,'20130305','teacher',8300,401,1),
('yuanhao','male',73,'20140701','teacher',3500,401,1),
('liwenzhou','male',28,'20121101','teacher',2100,401,1),
('jingliyang','female',18,'20110211','teacher',9000,401,1),
('jinxin','male',18,'19000301','teacher',30000,401,1),
('成龍','male',48,'20101111','teacher',10000,401,1),

('歪歪','female',48,'20150311','sale',3000.13,402,2),#以下是銷售部門
('丫丫','female',38,'20101101','sale',2000.35,402,2),
('丁丁','female',18,'20110312','sale',1000.37,402,2),
('星星','female',18,'20160513','sale',3000.29,402,2),
('格格','female',28,'20170127','sale',4000.33,402,2),

('張野','male',28,'20160311','operation',10000.13,403,3), #以下是營運部門
('程咬金','male',18,'19970312','operation',20000,403,3),
('程咬銀','female',18,'20130311','operation',19000,403,3),
('程咬銅','male',18,'20150411','operation',18000,403,3),
('程咬鐵','female',18,'20140512','operation',17000,403,3)
;

   #ps:如果在windows系統中,插入中文字元,select的結果為空白,可以将所有字元編碼統一設定成gbk      
#方式一(連結清單)
SELECT
    *
FROM
    emp AS t1
INNER JOIN (
    SELECT
        post,
        max(hire_date) max_date
    FROM
        emp
    GROUP BY
        post
) AS t2 ON t1.post = t2.post
WHERE
    t1.hire_date = t2.max_date;




#方式二(子查詢)
mysql> select (select t2.name from emp as t2 where t2.post=t1.post order by hire_date desc limit 1) from emp as t1 group by post;
+---------------------------------------------------------------------------------------+
| (select t2.name from emp as t2 where t2.post=t1.post order by hire_date desc limit 1) |
+---------------------------------------------------------------------------------------+
| 張野                                                                                  |
| 格格                                                                                  |
| alex                                                                                  |
| egon                                                                                  |
+---------------------------------------------------------------------------------------+
rows in set (0.00 sec)

mysql> select (select t2.id from emp as t2 where t2.post=t1.post order by hire_date desc limit 1) from emp as t1 group by post;
+-------------------------------------------------------------------------------------+
| (select t2.id from emp as t2 where t2.post=t1.post order by hire_date desc limit 1) |
+-------------------------------------------------------------------------------------+
|                                                                                  14 |
|                                                                                  13 |
|                                                                                   2 |
|                                                                                   1 |
+-------------------------------------------------------------------------------------+
rows in set (0.00 sec)





#正确答案
mysql> select t3.name,t3.post,t3.hire_date from emp as t3 where id in (select (select id from emp as t2 where t2.post=t1.post order by hire_date desc limit 1) from emp as t1 group by post);
+--------+-----------------------------------------+------------+
| name   | post                                    | hire_date  |
+--------+-----------------------------------------+------------+
| egon   | 老男孩駐沙河辦事處外交大使              | 2017-03-01 |
| alex   | teacher                                 | 2015-03-02 |
| 格格   | sale                                    | 2017-01-27 |
| 張野   | operation                               | 2016-03-11 |
+--------+-----------------------------------------+------------+
rows in set (0.00 sec)

   #方式一為正确答案,方式二中的limit 1有問題(每個部門可能有>1個為同一時間入職的新員工),我隻是想用該例子來說明可以在select後使用子查詢

   #可以基于上述方法解決:比如某網站在全國各個市都有站點,每個站點一條資料,想取每個省下最新的那一條市的網站品質資訊      

六、綜合練習

#init.sql檔案内容
/*
 資料導入:
 Navicat Premium Data Transfer

 Source Server         : localhost
 Source Server Type    : MySQL
 Source Server Version : 50624
 Source Host           : localhost
 Source Database       : sqlexam

 Target Server Type    : MySQL
 Target Server Version : 50624
 File Encoding         : utf-8

 Date: 10/21/2016 06:46:46 AM
*/

SET NAMES utf8;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
--  Table structure for `class`
-- ----------------------------
DROP TABLE IF EXISTS `class`;
CREATE TABLE `class` (
  `cid` int(11) NOT NULL AUTO_INCREMENT,
  `caption` varchar(32) NOT NULL,
  PRIMARY KEY (`cid`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

-- ----------------------------
--  Records of `class`
-- ----------------------------
BEGIN;
INSERT INTO `class` VALUES ('1', '三年二班'), ('2', '三年三班'), ('3', '一年二班'), ('4', '二年九班');
COMMIT;

-- ----------------------------
--  Table structure for `course`
-- ----------------------------
DROP TABLE IF EXISTS `course`;
CREATE TABLE `course` (
  `cid` int(11) NOT NULL AUTO_INCREMENT,
  `cname` varchar(32) NOT NULL,
  `teacher_id` int(11) NOT NULL,
  PRIMARY KEY (`cid`),
  KEY `fk_course_teacher` (`teacher_id`),
  CONSTRAINT `fk_course_teacher` FOREIGN KEY (`teacher_id`) REFERENCES `teacher` (`tid`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

-- ----------------------------
--  Records of `course`
-- ----------------------------
BEGIN;
INSERT INTO `course` VALUES ('1', '生物', '1'), ('2', '實體', '2'), ('3', '體育', '3'), ('4', '美術', '2');
COMMIT;

-- ----------------------------
--  Table structure for `score`
-- ----------------------------
DROP TABLE IF EXISTS `score`;
CREATE TABLE `score` (
  `sid` int(11) NOT NULL AUTO_INCREMENT,
  `student_id` int(11) NOT NULL,
  `course_id` int(11) NOT NULL,
  `num` int(11) NOT NULL,
  PRIMARY KEY (`sid`),
  KEY `fk_score_student` (`student_id`),
  KEY `fk_score_course` (`course_id`),
  CONSTRAINT `fk_score_course` FOREIGN KEY (`course_id`) REFERENCES `course` (`cid`),
  CONSTRAINT `fk_score_student` FOREIGN KEY (`student_id`) REFERENCES `student` (`sid`)
) ENGINE=InnoDB AUTO_INCREMENT=53 DEFAULT CHARSET=utf8;

-- ----------------------------
--  Records of `score`
-- ----------------------------
BEGIN;
INSERT INTO `score` VALUES ('1', '1', '1', '10'), ('2', '1', '2', '9'), ('5', '1', '4', '66'), ('6', '2', '1', '8'), ('8', '2', '3', '68'), ('9', '2', '4', '99'), ('10', '3', '1', '77'), ('11', '3', '2', '66'), ('12', '3', '3', '87'), ('13', '3', '4', '99'), ('14', '4', '1', '79'), ('15', '4', '2', '11'), ('16', '4', '3', '67'), ('17', '4', '4', '100'), ('18', '5', '1', '79'), ('19', '5', '2', '11'), ('20', '5', '3', '67'), ('21', '5', '4', '100'), ('22', '6', '1', '9'), ('23', '6', '2', '100'), ('24', '6', '3', '67'), ('25', '6', '4', '100'), ('26', '7', '1', '9'), ('27', '7', '2', '100'), ('28', '7', '3', '67'), ('29', '7', '4', '88'), ('30', '8', '1', '9'), ('31', '8', '2', '100'), ('32', '8', '3', '67'), ('33', '8', '4', '88'), ('34', '9', '1', '91'), ('35', '9', '2', '88'), ('36', '9', '3', '67'), ('37', '9', '4', '22'), ('38', '10', '1', '90'), ('39', '10', '2', '77'), ('40', '10', '3', '43'), ('41', '10', '4', '87'), ('42', '11', '1', '90'), ('43', '11', '2', '77'), ('44', '11', '3', '43'), ('45', '11', '4', '87'), ('46', '12', '1', '90'), ('47', '12', '2', '77'), ('48', '12', '3', '43'), ('49', '12', '4', '87'), ('52', '13', '3', '87');
COMMIT;

-- ----------------------------
--  Table structure for `student`
-- ----------------------------
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
  `sid` int(11) NOT NULL AUTO_INCREMENT,
  `gender` char(1) NOT NULL,
  `class_id` int(11) NOT NULL,
  `sname` varchar(32) NOT NULL,
  PRIMARY KEY (`sid`),
  KEY `fk_class` (`class_id`),
  CONSTRAINT `fk_class` FOREIGN KEY (`class_id`) REFERENCES `class` (`cid`)
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8;

-- ----------------------------
--  Records of `student`
-- ----------------------------
BEGIN;
INSERT INTO `student` VALUES ('1', '男', '1', '了解'), ('2', '女', '1', '鋼蛋'), ('3', '男', '1', '張三'), ('4', '男', '1', '張一'), ('5', '女', '1', '張二'), ('6', '男', '1', '張四'), ('7', '女', '2', '鐵錘'), ('8', '男', '2', '李三'), ('9', '男', '2', '李一'), ('10', '女', '2', '李二'), ('11', '男', '2', '李四'), ('12', '女', '3', '如花'), ('13', '男', '3', '劉三'), ('14', '男', '3', '劉一'), ('15', '女', '3', '劉二'), ('16', '男', '3', '劉四');
COMMIT;

-- ----------------------------
--  Table structure for `teacher`
-- ----------------------------
DROP TABLE IF EXISTS `teacher`;
CREATE TABLE `teacher` (
  `tid` int(11) NOT NULL AUTO_INCREMENT,
  `tname` varchar(32) NOT NULL,
  PRIMARY KEY (`tid`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

-- ----------------------------
--  Records of `teacher`
-- ----------------------------
BEGIN;
INSERT INTO `teacher` VALUES ('1', '張磊老師'), ('2', '李平老師'), ('3', '劉海燕老師'), ('4', '朱雲海老師'), ('5', '李傑老師');
COMMIT;

SET FOREIGN_KEY_CHECKS = 1;      

1、實列準備

#####從init.sql檔案中導入資料
#準備表、記錄
mysql> create database db1;
mysql> use db1;
mysql> source      

2、表結構

!!!重中之重:練習之前務必搞清楚sql邏輯查詢語句的執行順序
10@mysql資料庫多表查詢查詢語句(union、内連接配接、外連接配接)

3、sql的使用

#案列:

1、查詢所有的課程的名稱以及對應的任課老師姓名

2、查詢學生表中男女生各有多少人

3、查詢實體成績等于100的學生的姓名

4、查詢平均成績大于八十分的同學的姓名和平均成績

5、查詢所有學生的學号,姓名,選課數,總成績

6、 查詢姓李老師的個數

7、 查詢沒有報李平老師課的學生姓名

8、 查詢實體課程比生物課程高的學生的學号

9、 查詢沒有同時選修實體課程和體育課程的學生姓名

10、查詢挂科超過兩門(包括兩門)的學生姓名和班級

11 、查詢選修了所有課程的學生姓名

12、查詢李平老師教的課程的所有成績記錄
 
13、查詢全部學生都選修了的課程号和課程名

14、查詢每門課程被選修的次數

15、查詢之選修了一門課程的學生姓名和學号

16、查詢所有學生考出的成績并按從高到低排序(成績去重)

17、查詢平均成績大于85的學生姓名和平均成績

18、查詢生物成績不及格的學生姓名和對應生物分數

19、查詢在所有選修了李平老師課程的學生中,這些課程(李平老師的課程,不是所有課程)平均成績最高的學生姓名

20、查詢每門課程成績最好的前兩名學生姓名

21、查詢不同課程但成績相同的學号,課程号,成績

22、查詢沒學過“葉平”老師課程的學生姓名以及選修的課程名稱;

23、查詢所有選修了學号為1的同學選修過的一門或者多門課程的同學學号和姓名;

24、任課最多的老師中學生單科成績最高的學生姓名