1.SELECT --group by 子句

group by 子句按照指定的列column_name對表數據進行分組
group by 后面跟的列也叫分組特性列
使用group by后,能 選擇的列 通常只能包括分組特性列 和 聚合函數
聚合函數 ???
1.按照班號分組,列出學生表中的班號 (注意:按照班號進行分組,班號就不會有重復值)
select cno from stu group by cno;cno分組特性列

2.按照班號分組,列出學生表中的班號,還要列出學生姓名
select sname,cno from stu group by cno;
查詢報錯
注意:學生有20人,姓名一共20行記錄,班號分組去重后有4行記錄,20行無法與4行拼接在一起
使用group by后,能選擇的列通常只能包括分組特性列和聚合函數
除非用group_concat字符串聚合函數把每個班的學生姓名變成字符串,每個班一行:
select cno,group_concat(sname) from stu group by cno;

3.按照班號分組,列出學生表中的班號,統計每個班的平均身高,平均體重,人數,最高分,不包括未分班的那些同學
select cno 班號,avg(height) 平均身高,avg(weight) 平均體重,count(*) 人數,max(score) 最高分 from stu where cno is not null group by cno;

4.先按照班號分組,再按照性別分組,列出學生表中的班號和性別,統計出每個班男女生的平均身高,平均體重,人數,最高分,不包括未分班的那些同學,結果先按班號,再按照男女s的順序排序
select cno 班號,sex 性別,avg(height) 平均身高,avg(weight) 平均體重,count(*) 人數,max(score) 最高分 from stu where cno is not null group by cno,sex order by cno,sex desc;

5.按照學生出生年份分組,統計出所有學生每個年份的人數,最高分,最低分,按照年份排序
select year(birth) 出生年份,count(sno) 人數,max(score) 最高分, min(score) 最低分 from stu group by year(birth) order by 1; +分組特性列和函數

2.SELECT - HAVING子句

HAVING子句是對group by產生的結果集的過濾
HAVING子句可以對分組特性列column_name進行過濾,也可以對聚合函數(aggregate_function(列))的值進行過濾
1.按照學生出生年份分組,統計出所有學生每個出生年份的人數,最高分,最低分,按照年份排序,並從結果中找出人數超過2個,並且最高分有超過700分的年份分組
select year(birth) 出生年份,count(sno) 人數,max(score) 最高分, min(score) 最低分 from stu group by year(birth) having count(*)>2 and max(score)>700 order by 1;
分組特性列+分組函數 having有 where沒有

2.已分班的學生中,哪些班學生的平均身高超過175,列出其班號和人數
select cno 班號,count(*) 人數 from stu where cno is not null group by cno having avg(height)>175 order by 1;

已分班的學生中,哪些班的學生每個人的體重 都超過50公斤,列出其班號和人數
select cno 班號,count(*) 人數 from stu where cno is not null group by cno having min(weight)>50 order by 1;

統計1班的學生人數,列出班號和人數
select cno 班號,count(*) 人數 from stu group by cno having cno=1;

或者
select 1 班號,count(*) 人數 from stu where cno=1;
第一種方法先使用group by統計,再用having過濾統計結果,統計了和1班不相干的其他班級的人數,浪費了系統CPU資源,效率低;
第二種方法,先用where子句過濾掉了不相干班級的人員,然后直接統計1班的人數,效率高

統計人數超過5個的班號和人數,結果按照班號排序,只顯示一行記錄
select cno 班號,count(*) 人數 from stu where cno is not null group by cno having 人數>5 order by 1 limit 1;

也可以寫為:
select cno 班號,count(*) 人數 from stu where cno is not null group by 班號 having 人數>5 order by 班號 limit 1;

也可以寫為:
select cno 班號,count(*) 人數 from stu where cno is not null group by 班號 having 人數>5 order by 班號 limit 1;

MySQL查詢語句 參考 執行步驟:

了解查詢語句發到MySQLD后,服務器端的處理步驟有助於降低語句書寫錯誤的可能性(注:不同數據庫處理步驟略有不同)。
初學查詢常見的錯誤如下:
select cno,count(*) from stu where count(*)>5;

where子句第二步執行,要調用count(*)第五步產生的結果,結果還沒有產生,報錯!
select cno 班號 from stu where 班號=1;

where子句第二步執行,調用至少第三步才能產生的別名,報錯!
where和having的區別(以例5舉例說明)
相同點:
都是對表行按照條件進行的篩選
不同點:
where對原始的stu表按照條件篩選行
having對分組后的新表按照條件篩選行

3.視圖 VIEW 創建視圖語法 視圖主要作用 視圖做DML操作
屬於關系型數據庫中的一種常用數據對象,保存一段select語句,可以把視圖名稱當作普通表來使用
創建視圖語法:
CREATE VIEW vtbl_name as select_statement;

查看視圖

視圖主要作用:
1.提高數據安全性(隱藏部分行和列)
2.簡化查詢
可以將常用的查詢語句寫成視圖的形式被其他查詢調用,這樣可以降低查詢語句的復雜度,提高可讀性
1.對視圖做DML操作 查看有哪些視圖 查看視圖的定義:
視圖僅僅保存SELECT語句,其select語句中的表稱為基表(或母表),視圖對應的數據是放在基表中的,基表中數據產生變化,視圖的結果集也會產生變化。即:視圖里面的數據發生變化,其實是基表中數據的變化所致
如果視圖和其相關基表存在記錄一一對應的關系,排除基表上存在約束的條件,通常可以對視圖做DML操作,但是不要輕易對視圖做DML操作,以防止對基表數據產生意想不到的影響
查看有哪些視圖:
show table status\G
其中“comment”值為“view”的表是視圖

查看視圖的定義:
show create table view_name;

4.多表連接查詢

將分散在多個表中的信息(列)橫向合並在一起
通常需要指明連接條件
一般會根據表列的實際業務含義進行連接,這樣才有實際意義
多表連接查詢和單表查詢相比會耗費更多的系統資源
語法
不使用表別名
select table1.column, table2.column from
table1 [inner|left|right] join table2
on table1.col1 = table2.col1;
使用表別名
select a.column,b.column from
table1 a [inner|left|right] join table2 b
on a.col1=b.col1;
分類
交叉連接
等值連接
內聯接
左連接 (左外連接)
右連接 (右外連接)
非等值連接
創建2個測試表 a和b
create table a (id int, name char(10));
create table b (id int, loc char(10));
insert into a values (1,'a');
insert into a values (2,'b');
insert into a values (4,'d');
insert into b values (1,'x');
insert into b values (2,'y');
insert into b values (3,'z');



1.交叉連接 笛卡兒爾積
無連接條件,結果記錄數= 3 * 3 =9
select * from a cross join b;


2.等值連接--內連接
有連接條件,結果記錄數= 3 * 3 =9
select * from a inner join b on a.id=b.id;



結果集顯示符合連接條件的
a表中的行,b表中的行,a表的id有1,2,b表的id也有1,2;
如果不符合連接條件,結果集將無記錄
3.等值連接-左連接
有連接條件,左表的記錄會全部顯示
select * from a left join b on a.id=b.id;

左指的是,上面語句中a寫在了b的左邊,結果集顯示左表a的所有行,右表b中符合連接條件的行,a表的id有1,2,4,b表的id沒有4,b表中不符合連接條件的行會用NULL值來填充

4.等值連接-右連接
有連接條件,右表的記錄會全部顯示
select * from a right join b on a.id=b.id;

右指的是,上面語句中b寫在了a的右邊,結果集顯示右表b的所有行,左表a中符合連接條件的行,b表的id有1,2,3,a表的id沒有3,a表中不符合連接條件的行會用NULL值來填充

5.非等值連接
多表連接條件可以分為等值和非等值兩種
等值連接條件
select * from a join b on a.id=b.id; 2條記錄

非等值連接條件
select * from a join b on a.id>b.id; 4條記錄

select * from a join b on a.id<b.id; 3條記錄

以上 a.id=b.id;a.id>b.id;a.id<b.id三種查詢記錄數加起來是9條
等於2個表交叉連接的數量
還有其他的寫法,根據業務需求定,有實際意義最重要
select * from a join b on a.id between 1 and 3 and b.id<4;;
......


6.多表連接查詢-示例

顯示學生的學號,姓名,性別,班號,班級名稱以及他們的班主任姓名,按照班號和學號排序 (等值連接-內連接)
mysql> select s.sno 學號,s.sname 姓名,s.sex 性別,s.cno 班號,c.cname 班名,c.teacher 班主任 from stu s inner join class c on s.cno=c.cno order by s.cno,s.sno;


顯示全部學生的學號,姓名,性別,班號,班級名稱以及他們的班主任姓名,無班主任的顯示‘暫無’,按照班號和學號排序 (等值連接-左連接)
mysql> select s.sno 學號,s.sname 姓名,s.sex 性別,s.cno 班號,c.cname 班名,ifnull(c.teacher,'暫無') 班主任 from stu s left join class c on s.cno=c.cno order by s.cno,s.sno;



顯示所有學生的學號,姓名,性別,身高,體重,班號,BMI指數(體重/身高^2),BMI表中對應的體態,低值,高值和性別 (非等值連接)
mysql> select s.sno 學號,s.sname 姓名,s.sex 性別,s.height 身高,s.weight 體重,s.cno 班號,round(weight/(height/100*height/100),2) BMI指數,b.lval 低值,b.hval 高值,bname 體態,b.sex 性別 from stu s join bmi b on s.sex=b.sex and round(weight/(height/100*height/100),2) between b.lval and b.hval;




基於例3的結果,把肥胖的同學和他們的班主任找出來 (三個表連接)

mysql> select s.sno 學號,s.sname 姓名,s.sex 性別,s.height 身高,s.weight 體重,s.cno 班號,round(weight/(height/100*height/100),2) BMI指數,b.lval 低值,b.hval 高值,bname 體態,b.sex 性別,c.cname 班名,c.teacher 班主任 from stu s left join bmi b on s.sex=b.sex and round(weight/(height/100*height/100),2) between b.lval and b.hval left join class c on s.cno=c.cno where b.bname='肥胖';



5.復合查詢
mysql> select sno,sname,cno from stu union select cno,cname,teacher from class;

復合查詢指用集合運算符對多個查詢結果集進行運算,產生新的查詢結果集。
MySQL常用集合運算符包括以下2種:
union對兩個結果集進行並集操作,重復行只取一次,同時進行默認規則的排序
union all對兩個結果集進行並集操作,包括所有重復行,不進行排序
MySQL不支持交集和差集運算,可以通過多表連接的方式實現

創建示例表
create table class1 as select * from class where cno=1;

insert into class1 values(5,'5班','董卓');

select * from class;

select * from class1;


1.並集union
求表class和class1的並集,重復記錄只顯示一次
mysql> select * from class union select * from class1;


默認排序為增序,順序列1、列2、列3......
可以自定義排序,order by寫在語句的最后

去掉重復
2.union all 重復顯示倆表記錄
求表class和class1的並集,重復記錄重復顯示
mysql> select * from class union all select * from class1;

結果默認不排序

3.求表class和class1的交集
mysql無intersect集合運算符,交集運算可以通過多表連接實現

mysql> select c.* from class c join class1 c1 on c.cno=c1.cno;

4.求表class和class1的差集,即顯示class表中在class1表中沒有的行記錄

mysql> select * from class c left join class1 c1 on c.cno=c1.cno;
mysql> select * from class c left join class1 c1 on c.cno=c1.cno where c1.cno is null;
mysql> select c.cno,c.cname,c.teacher from class c left join class1 c1 on c.cno=c1.cno where c1.cno is null;

5.學生表按照班號分組統計各班人數,也要顯示出合計總人數

select ifnull(cno,'-') 班號,count(*) 人數 from stu group by cno union select '合計:',count(*) from stu;

學生表按照班號分組統計各班人數,


