資料庫(三)分組查詢,having條件,語句執行順序,內連線,外連線,子查詢
分組查詢:
select 列名 from 表名 group by 列
在分組查詢中使用聚合查詢,會對每一個組別單獨執行一次聚合操作
在執行聚合查詢或者是分組查詢中,只能查詢被分組的列或聚合列
同時對多個列進行分組:
select 列名 from 表名 group by 列,列
having條件篩選:
select 列名 from 表名 group by 列having條件
having和where一樣表示條件的篩選過濾,但是having只能和group結合使用
having和where條件的相同點和區別點:
1.都表示條件的過濾
2.having只能寫在group後,where可以出現任何情況
4.having中可以使用聚合函式,where不能使用
語句的執行順序:
select 列 from 表 where條件 group by 列 having 條件 order by 列
1.from
2.where
3.group by
4.having條件
5.select
6.order by
例子資料
-- 建立學生表 create table student ( stuId int primary key auto_increment, stuName varchar(20) not null, email varchar(50) ); -- 建立課程表 create table course ( courseId int primary key auto_increment, courseName varchar(20) not null ); -- 建立成績表 create table score ( stuId int not null, courseId int not null, score float ); -- 插入學生資料 insert into student values(null,"tom","tom@geekhome.com"); insert into student values(null,"jack","jack@geekhome.com"); insert into student values(null,"tony","tony@geekhome.com"); insert into student values(null,"rose","rose@geekhome.com"); -- 新增課程資料 insert into course values(null,"Java"); insert into course values(null,"MySQL"); insert into course values(null,"JDBC"); -- 新增成績資訊 insert into score values(1,1,45); insert into score values(1,1,58); insert into score values(1,1,60); insert into score values(1,2,78); insert into score values(1,3,82); insert into score values(2,1,90); insert into score values(2,2,92); insert into score values(2,3,78); insert into score values(3,1,53); insert into score values(3,2,45); insert into score values(3,3,75);
-- 檢視班級的平均分
select avg(score) as avg_score from score;
-- 對課程進行分組查詢
-- 在分組查詢,只能對被分組的列進行檢視
select courseId from score group by courseId;
-- 在分組查詢中使用聚合查詢,會對每一個組別單獨執行一次聚合操作
-- 在執行聚合查詢或者是分組查詢中,只能查詢被分組的列或聚合列
-- 檢視每一門課程的平均分
select courseId,avg(score) from score group by courseId;
-- 查詢每個部門總薪資和平均薪資
select department_id,sum(salary) as sum_salary,avg(salary) as avg_salary from emp group by department_id;
-- 查詢每個崗位的人數
select job_id,count(*) as empCount from emp group by job_id;
-- 查詢每個部門中最高的薪資和最低的薪資
select department_id,max(salary) as maxSalary,min(salary) as minSalary from emp group by department_id;
-- 每個部門中入職時間是晚於2010年的員工總數
select department_id,count(*) as empCount from emp where hire_date>='2010-1-1' group by department_id;
-- 查詢參加單科累計考試次數達到5次以上的所有科目的平均成績
-- where條件中不允許進行聚合操作
-- having表示在group by分組後執行的條件篩選,可以使用聚合函式
select courseId,avg(score) from score group by courseId having count(*)>5
-- 查詢參加過補考的同學編號
-- 思路:每個學生考的每門課程超過1次以上的,就是參加過補考的
-- 同時對多個列進行分組
-- 要查的是每個學生參加過的每一門考試超過一次 select stuId from score group by stuid,courseId having count(*)>1;
-- 以下兩個都不是要查詢的結果 --查詢的是每個學生考試超過一次,即這個學生參加過的所有課程 select stuId from score group by stuid having count(*)>1; -- 查詢的是所有學生參加的課程考試超過一次的,即所有參加過這門考試的資料 select stuId from score group by courseId having count(*)>1;
資料高階查詢:
如果希望查詢得到學生的姓名課程科目和成績該怎麼辦?
姓名來自於學生表,課程來自於課程表,而成績又來自於成績表,所以必須從三張表中獲取各個資料
表連線查詢:多表查詢時,如果兩張表中存在同名的欄位,則必須要使用表名.欄位名 加以區分(不同名不用加)
(多表查詢時只查詢單個表中的資料用子查詢,需要查詢多表中的資料需要用內連線和外連線)
1.inner join:
內連線查詢 獲取兩表中共同部分的資料
語句:select 列 from 表A inner join 表B on 表A.列=表B.列 [where 條件]
2.left join:
左外連線 獲取左表中的所有資料和右表中匹配的資料
左連線以左表為基表去連線右邊的資料表,查詢出左表的所有資料以及右邊和左表關聯的資料
3.right join:
右外連線 獲取右表中的所有資料和左表中匹配的資料
(左連線和右連線只是基表不一樣,表的排放順序不一樣,其餘沒有任何區別,會一種就行)
inner join ··· on 的執行機制:查詢學生的姓名和成績,通過stuid進行連線
left join 左連線的執行機制:找到沒有參加考試的學生(最後只要查詢右表不為null的列值為null的情況)
-- inner join 內聯接查詢多表的資料
-- 查詢所有學生的姓名和課程編號和對應的成績
方法一:inner join ··· on
-- 多表查詢時,如果兩張表中存在同名的欄位,則必須要使用表名.欄位名 加以區分
select stu.stuName,s.courseId,s.score from student as stu//表一 inner join score as s//表二 on stu.stuId=s.stuId//兩張表的連線條件;
方法二:from a表,b表 where 關聯的條件
-- 使用from A表,B表也可以實現多表的關聯查詢(不寫where的時候可以檢視交叉的具體情況)
select stuName,courseId,score from student as stu,score as s where stu.stuId=s.stuId;
-- 查詢所有及格的學生的編號、課程名稱以及成績
-- 課程表和成績表通過courseID進行連線
select stuId,courseName,score from course as c inner join score as s on c.courseId=s.courseId where score>=60;
-- 查詢所有學生的姓名,課程名稱、成績
-- inner join 每次只能連線兩個表,連線以後生成一個新的表,然後再去連線另外的表
--多表連線是有順序的,要兩個表鍵有直接聯絡的才能直接連線(學生表——成績表——課程表)
select stuName,courseName,score from student as stu inner join score as s on stu.stuId=s.stuId -- 學生表和成績表連線 inner join course as c on s.courseId=c.courseId;-- 成績表和成績表連線
課堂練習
-- 查詢員工的姓名、薪資和所在部門的名稱 select first_name,last_name,salary,department_name from emp inner join dep on emp.department_id=dep.department_id; -- 查詢部門編號是50的部門名稱和該部門每個員工的姓名、入職時間 select first_name,last_name,hire_date from emp inner join dep on emp.department_id=dep.department_id where emp.department_id=50; -- 查詢發帖人的姓名、主貼的名稱、回帖人姓名、回帖的內容
--inner join ··· on的方法 select u.uname,t.ttopic,r.rcontents,u2.uname from
bbsusers as u inner join bbstopic as t on u.userid=t.tuid-- 使用者表和主貼表的關聯inner join bbsreply as r on t.tid=r.rtid-- 回帖表和主貼表的關聯inner join bbsusers as u2 on u2.userid=r.ruid; -- 使用者表和回帖表的關聯
-- from A表,B表 查詢的方法 select u1.uname,t.ttopic,r.rcontents,u2.uname from
bbsusers as u1,bbsusers as u2,bbstopic as t,bbsreply as r -- from 的四張表where u1.userid=t.tuid and u2.userid=r.ruid and t.tid=r.rtid; -- 四張表的三個關聯關係
左連線:
使用join left ··· on查詢沒有參加考試的學員姓名
-- 使用left join左連線實現 select * from student as stu left join score as s on stu.stuId=s.stuId where s.stuId is null;
右連線:
使用right join ··· on 查詢沒有參加考試的學生
-- 使用right join右聯接 select * from score as s right join student as stu on stu.stuId=s.stuId where s.stuId is null;
子查詢:(多表查詢時只查詢單個表中的資料用子查詢,需要查詢多表中的資料需要用內連線和外連線)
如果想查詢年齡比TOM的年齡大的學生資訊怎麼辦?(要先查詢tom的年齡,在進行查詢比他年齡大的,要兩次查詢)
使用子查詢解決!
子查詢:即查詢語句中使用巢狀的查詢,在SQL語句中可以將查詢的結果作為呈現資料或者將結果作為條件再次進行條件篩選
使用子查詢的注意事項:
select 列名from 表名 where 列名=(select 列名 from 表名)
1.當使用關係運算符對子查詢結果進行處理時,子查詢的結果必須為單行單列的值,只有單行單列的值才能用 > < =進行比較
2.如果是多行資料,則可以使用 in 進行比較
-- 查詢年齡比tom大的學生資訊
-- 使用子查詢,可以將查到的結果集繼續進行查詢處理
select * from student where age>(select age from student where stuname='tom');
-- 可以通過子查詢作為結果集的虛擬表,繼續完成查詢,起別名為n
select stuName,age from (select * from student) as n;
-- 查詢所有及格的學生姓名:groupby stuid是為了不重複
select stuid,stuname from student where stuid in (select stuid from score where score<60 group by stuid);
-- 查詢沒有參加考試的學生姓名(對成績表中的學生編號進行分組,然後查詢學生表中學生學號不在之前的分組中的學生)
select stuname from student where stuid not in(select stuid from score group by stuid);
-- 查詢java課程的平均分(查詢課程表中的Java對應的courseid ,然後對成績表中的courseid和Java對應的courseID相同的所有成績,進行平均分計算)
select avg(score) from score where courseId=(select courseId from course where courseName='Java');
-- 查詢在所在地(location)在美國的所有部門的員工姓名(emp)和部門名稱(dep)
方法一:用inner join 但是交叉的資料量較大
select first_name,last_name,department_name from emp inner join dep on emp.department_id=dep.department_id inner join location as l on l.location_id=dep.location_id where country_id='US';
方法二:
-- 先查詢出所在是美國的部門編號,
-- 然後根據部門編號查詢這些部門的員工姓名和部門編號
-- 最後將查詢的結果集inner join部門表
-- 先查詢出所在是美國的部門編號, select location_id from location where country_id='US' -- 然後根據部門編號查詢這些部門的部門編號 select department_id from dep where location_id in (select location_id from location where country_id='US') -- 然後根據部門編號查詢這些部門的員工姓名 select first_name,last_name,department_id from emp where department_id in (select department_id from dep where location_id in (select location_id from location where country_id='US')) -- 最後將查詢的結果集inner join部門表 select first_name,last_name,department_name from (select first_name,last_name,department_id from emp where department_id in (select department_id from dep where location_id in (select location_id from location where country_id='US'))) n (-- 別名) inner join dep on n.department_id=dep.department_id
或者:
--先查詢出所在是美國的部門編號
-- 然後根據部門編號查詢這些部門的部門名稱
--在通過部門編號和emp進行交叉查詢
select first_name,last_name,department_name from (select department_id,department_name from dep where location_id in (select location_id from location where country_id='US')) n inner join emp on n.department_id=emp.department_id