MySQL 高級查詢

我們使用SQL查詢不能只使用很簡單、最基礎的SELECT語句查詢。如果想從多個表查詢比較復雜的信息,就會使用高級查詢實現。常見的高級查詢包括多表連接查詢、內連接查詢、外連接查詢與組合查詢等

以一個簡單的學生信息表(學生ID、學生姓名、學生性別)與一個科目表(科目ID、科目)還有學生成績表(學生ID、科目ID、分數)為例子

創建表

create table scores(
    id int auto_increment primary key,
    stuid int,
    subid int,
    score decimal(5,2),
);
create table students(
    id int auto_increment primary key,
    sname varchar(20),
    sex char(1)
);

create table subjects(
    id int auto_increment primary key,
    stitle varchar(20)
);

學生列的數據不是在這里新建的,而應該從學生表引用過來,關系也是一條數據;根據范式要求應該存儲學生的編號,而不是學生的姓名等其它信息
同理,科目表也是關系列,引用科目表中的數據

表關系

外鍵
思考:怎么保證關系列數據的有效性呢?任何整數都可以嗎?
答:必須是學生表中id列存在的數據,可以通過外鍵約束進行數據的有效性驗證為stuid添加外鍵約束

alter table scores 
add constraint stu_sco foreign key(stuid) references students(id);

此時插入或者修改數據時,如果stuid的值在students表中不存在則會報錯
在創建表時可以直接創建約束

外鍵的級聯操作

  • 在刪除students表的數據時,如果這個id值在scores中已經存在,則會拋異常
  • 推薦使用邏輯刪除,還可以解決這個問題
  • 可以創建表時指定級聯操作,也可以在創建表后再修改外鍵的級聯操作
alter table scores 
add constraint stu_sco foreign key(stuid) references students(id) 
on delete cascade;

在創建表時可以直接創建約束,添加級聯操作

create table scores(
    id int auto_increment primary key,
    stuid int,
    subid int,
    score decimal(5,2),
    #這里我在創建表時直接創建約束,添加級聯操作。后面就不用在添加了
    foreign key(stuid) references students(id) on delete cascade,
    foreign key(subid) references subjects(id) on delete cascade
);

級聯操作的類型包括:
restrict(限制):默認值,拋異常
cascade(級聯):如果主表的記錄刪掉,則從表中相關聯的記錄都將被刪除
set null:將外鍵設置為空
no action:什么都不做

連接查詢

-- 建表和數據S
create table students(
    id int auto_increment primary key,
    sname varchar(20)
);

create table subjects(
    id int auto_increment primary key,
    stitle varchar(20)
);
create table scores(
    id int auto_increment primary key,
    stuid int,
    subid int,
    score decimal(5,2),
    foreign key(stuid) references students(id) on delete cascade,
    foreign key(subid) references subjects(id) on delete cascade
);

insert into subjects(stitle) values('語文');
insert into subjects(stitle) values('數學');
insert into subjects(stitle) values('英語');

insert into students(sname,sex) values('小明','男');
insert into students(sname,sex) values('小美','女');
insert into students(sname,sex) values('小壯','男');
insert into students(sname,sex) values('小敏','女');

insert into scores(stuid,subid,score) values(1,1,88);
insert into scores(stuid,subid,score) values(1,2,95);
insert into scores(stuid,subid,score) values(2,1,89);
insert into scores(stuid,subid,score) values(2,3,95);
insert into scores(stuid,subid,score) values(3,1,92);
insert into scores(stuid,subid,score) values(3,2,85);
insert into scores(stuid,subid,score) values(4,2,82);
insert into scores(stuid,subid,score) values(4,3,99);
/*查詢學生的編號,姓名,科目的名稱,成績*/
select t1.id,t1.sname,t2.stitle,t3.score
from students t1,subjects t2,scores t3
where t3.stuid=t1.id and t3.subid=t2.id;

select t1.id,t1.sname,t2.stitle,t3.score
from scores t3
inner join students t1
on t3.stuid = t1.id 
inner join subjects t2
on t3.subid = t2.id;

內連接(INNER JOIN)
   INNER JOIN ...表 ON ...條件

-- 查詢學生的姓名、平均分
select students.sname,avg(scores.score)
from scores
inner join students on scores.stuid=students.id
group by students.sname;

/*查詢學生的編號,姓名,科目的名稱,成績*/
-- 方法一
select t1.id,t1.sname,t2.stitle,t3.score
from students t1,subjects t2,scores t3
where t3.stuid=t1.id and t3.subid=t2.id;
-- 方法二
select t1.id,t1.sname,t2.stitle,t3.score
from scores t3
inner join students t1
on t3.stuid = t1.id 
inner join subjects t2
on t3.subid = t2.id;
-- 方法三
select t1.id,t1.sname,t2.stitle,t3.score
from  students t1
inner join scores t3
on t3.stuid = t1.id 
inner join subjects t2
on t3.subid = t2.id;

-- 查詢學生的姓名、平均分
select students.sname,avg(scores.score)
from scores
inner join students on scores.stuid=students.id
group by students.sname;
-- 查詢男生的姓名、總分
select students.sname,sum(scores.score)
from scores
inner join students on scores.stuid=students.id
where students.sex='男'
group by students.sname;
-- 查詢科目的名稱、平均分
select subjects.stitle,avg(scores.score)
from scores
inner join subjects on scores.subid=subjects.id
group by subjects.stitle;

外聯結
1、左外連接(LEFT OUTER JOIN)
概述:指將左表的所有記錄與右表符合條件的記錄,返回的結果除內連接的結果,還有左表不符合條件的記錄,并在右表相應列中填NULL。
2、右外連接(RIGHT OUTER JOIN)
概述:與左外連接相反,指將右表的所有記錄與左表符合條件的記錄,返回的結果除內連接的結果,還有右表不符合條件的記錄,并在左表相應列中填NULL。

學生姓名來源于students表,科目名稱來源于subjects,分數來源于scores表
當查詢結果來源于多張表時,需要使用連接查詢

當查詢結果來源于多張表時,需要使用連接查詢
關鍵:找到表間的關系,當前的關系是
students表的id---scores表的stuid
subjects表的id---scores表的subid

select students.sname,subjects.stitle,scores.score
from scores
inner join students on scores.stuid=students.id
inner join subjects on scores.subid=subjects.id;
  • 連接查詢分類如下:
  • 表A inner join 表B:表A與表B匹配的行會出現在結果中
  • 表A left join 表B:表A與表B匹配的行會出現在結果中,外加表A中獨有的數據,未對應的數據使用null填充
  • 表A right join 表B:表A與表B匹配的行會出現在結果中,外加表B中獨有的數據,未對應的數據使用null填充
  • 在查詢或條件中推薦使用“表名.列名”的語法
  • 如果多個表中列名不重復可以省略“表名.”部分
  • 如果表的名稱太長,可以在表名后面使用' as 簡寫名'或' 簡寫名',為表起個臨時的簡寫名稱

用一個部門表,員工表演示一下內外連接查詢

-- 部門表,員工表
drop table if exists emp;
drop table if exists dept;
create table dept(
     id int auto_increment primary key,
     dname varchar(20)
);
create table emp(
     id int auto_increment primary key,
     ename varchar(20),
     did int not null,
     mgr int, 
     foreign key(did) references dept(id),
     foreign key(mgr) references emp(id)
);
insert into dept(dname) values('研發部');
insert into dept(dname) values('人事部');
insert into dept(dname) values('財務部');

insert into emp(ename,did,mgr) values('老王',1,null);
insert into emp(ename,did,mgr) values('老張',1,1);
insert into emp(ename,did,mgr) values('老趙',1,1);
insert into emp(ename,did,mgr) values('小紅',2,3);
insert into emp(ename,did,mgr) values('小麗',2,3);

/*查詢員工額編號,姓名,上級的姓名*/
-- 1
select t1.id,t1.ename,t2.ename
from emp t1,emp t2
where t1.mgr = t2.id;
-- 2inner join
select t1.id,t1.ename,t2.ename
from emp t1
inner join emp t2
on t1.mgr = t2.id;
-- 3左外連接
select t1.id,t1.ename,t2.ename
from emp t1
left join emp t2
on t1.mgr = t2.id;
-- 4右外連接
select t1.id,t1.ename,t2.ename
from emp t1
right join emp t2
on t1.mgr = t2.id;
Paste_Image.png

Paste_Image.png

自關聯

概述:指用表的別名實現表自身的連接。

在員工表中mgr列中代表了他們的上級

/*查詢員工額編號,姓名,上級的姓名*/
select 員工表.id,員工表.ename 員工,上級表.ename 上級 from emp 員工表,emp 上級表
where 員工表.mgr = 上級表.id;
Paste_Image.png

子查詢

查詢支持嵌套使用
查詢各學生的語文、數學、英語的成績

-- 查詢各學生的語文、數學、英語的成績
select sname,
    (select sco.score from scores sco inner join subjects sub on sco.subid=sub.id 
            where sub.stitle='語文' and stuid=stu.id) as 語文,
    (select sco.score from  scores sco inner join subjects sub on sco.subid=sub.id 
            where sub.stitle='數學' and stuid=stu.id) as 數學,
    (select sco.score from  scores sco inner join subjects sub on sco.subid=sub.id 
            where sub.stitle='英語' and stuid=stu.id) as 英語
from students stu;
查詢結果

內置函數

字符串函數

-- 查看字符的ascii碼值ascii(str),str是空串時返回0
select ascii('a');
-- 查看ascii碼值對應的字符char(數字)
select char(97);
-- 拼接字符串concat(str1,str2...)
select concat(12,34,'ab');
-- 包含字符個數length(str)
select length('abc');
-- 截取字符串
-- left(str,len)返回字符串str的左端len個字符
-- right(str,len)返回字符串str的右端len個字符
-- substring(str,pos,len)返回字符串str的位置pos起len個字符
select substring('abc123',2,3);
-- 去除空格
-- ltrim(str)返回刪除了左空格的字符串str
-- rtrim(str)返回刪除了右空格的字符串str
-- trim([方向 remstr from str)返回從某側刪除remstr后的字符串str,
--   方向詞包括both、leading、trailing,表示兩側、左、右
select trim('  bar   ');
select trim(leading 'x' FROM 'xxxbarxxx');
select trim(both 'x' FROM 'xxxbarxxx');
select trim(trailing 'x' FROM 'xxxbarxxx');
-- 返回由n個空格字符組成的一個字符串space(n)
select space(10);
-- 替換字符串replace(str,from_str,to_str)
select replace('abc123','123','def');
-- 大小寫轉換,函數如下
-- lower(str)
-- upper(str)
select lower('aBcD');

數學函數


-- 求絕對值abs(n)
select abs(-32);
-- 求m除以n的余數mod(m,n),同運算符%
select mod(10,3);
select 10%3;
-- 地板floor(n),表示不大于n的最大整數
select floor(2.3);
-- 天花板ceiling(n),表示不小于n的最大整數
select ceiling(2.3);
-- 求四舍五入值round(n,d),n表示原數,d表示小數位置,默認為0
select round(1.6);
-- 求x的y次冪pow(x,y)
select pow(2,3);
-- 獲取圓周率PI()
select PI();
-- 隨機數rand(),值為0-1.0的浮點數
select rand();
-- 還有其它很多三角函數,使用時可以查詢文檔

日期時間函數

獲取子值,語法如下
year(date)返回date的年份(范圍在1000到9999)
month(date)返回date中的月份數值
day(date)返回date中的日期數值
hour(time)返回time的小時數(范圍是0到23)
minute(time)返回time的分鐘數(范圍是0到59)
second(time)返回time的秒數(范圍是0到59)

select year('2016-12-21');
日期計算,使用+-運算符,數字后面的關鍵字為year、month、day、hour、minute、second
select '2016-12-21'+interval 1 day;

獲取年%Y,返回4位的整數
獲取年%y,返回2位的整數
獲取月%m,值為1-12的整數
獲取日%d,返回整數
獲取時%H,值為0-23的整數
獲取時%h,值為1-12的整數
獲取分%i,值為0-59的整數
獲取秒%s,值為0-59的整數

/*日期-->字符串*/
select date_format('2017-10-20','%Y年%m月%d日')
/*字符串-->日期*/
select str_to_date('2017年10月20日','%Y年%m月%d日')

當前日期current_date()
select current_date();
當前時間current_time()
select current_time();
當前日期時間now()
select now();
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,606評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,582評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,540評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,028評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,801評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,223評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,294評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,442評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,976評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,800評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,996評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,543評論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,233評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,926評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,702評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,991評論 2 374

推薦閱讀更多精彩內容

  • 前言 我們使用SQL查詢不能只使用很簡單、最基礎的SELECT語句查詢。如果想從多個表查詢比較復雜的信息,就會使用...
    暖熊熊閱讀 629評論 0 0
  • 認真算一算 社保的繳費周期、費率、以及最后能領取多少?社保可不可以你想什么時候領養老金都可以? 能不能保證領多少?...
    美格發型工作室閱讀 144評論 0 0
  • 在火車上大半夜醒來然后就睡不著了,想著你現在應該已經熟睡了,不知道你昨晚什么時候回去的,都沒發條消息過來,有點難過...
    風花微涼閱讀 209評論 0 0
  • 財富=價值*杠桿 最近老大跑到上海、深圳,去找導師,去建人脈,老大說他學到了很多東西,大腦都被更新成光滑的了,他說...
    堅果姐姐閱讀 361評論 3 1