日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

【一周入门MySQL—3】多表查询、子查询、常用函数

發(fā)布時間:2025/3/20 数据库 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【一周入门MySQL—3】多表查询、子查询、常用函数 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

多表查詢、子查詢、常用函數(shù)

一、多表查詢

多表查詢:通過不同表中具有相同意義的關(guān)鍵字段,將多個表進(jìn)行連接,查詢不同表中的字段信息。

對應(yīng)關(guān)系

一對一:比如下圖的人員信息表和人員身份證對應(yīng)表,一個員工只會有一個身份證號碼;

一對多:比如下圖的部門信息表和部門人員表,一個部門可能會有多個員工存在;

多對多:多對多的情況就比較復(fù)雜了,建議拆分表,這樣可以節(jié)省存儲空間,避免數(shù)據(jù)冗余;

連接方式

內(nèi)連接外連接(左外連接和右外連接)。

多表連接的結(jié)果通過三個屬性決定

  • 方向性:在外連接中寫在前面的表為左表,寫在后面的表為右表;
  • 主附關(guān)系:主表要出所有的數(shù)據(jù)范圍,附表與主表無匹配項時標(biāo)記為null,內(nèi)連接時無主附表之分;
  • 對應(yīng)關(guān)系:關(guān)鍵字段中有重復(fù)值的表為多表,沒有重復(fù)值的表為一表;
  • 比如上圖中的t1表和t2表:

    若左外連接:t1是主表,t2是附表;

    若右外連接:t2是主表,t1是附表;

    左連接:

    結(jié)果中除了包括滿足連接條件的行外,還包括左表的所有行。

    select 字段1[,...] from表1 left join 表2 on 表1.key = 表2.key;

    右連接:

    結(jié)果中除了包括滿足的連接條件的行外,還包括右邊的所有行。

    select 字段1[,...] from表1 right join 表2 on 表1.key = 表2.key;

    內(nèi)連接:

    按照連接條件合并兩個表,返回滿足條件的行。

    沒有主附關(guān)系,也沒有方向性。

    select 字段1[,...] from表1 [inner] join 表2 on 表1.key = 表2.key;

    另外在其他工具中還有全連接、左反和右反連接(Power BI)。

    -- 內(nèi)連接select * from t1 inner join t2 on t1.key1 = t2.key2;-- 左連接select * from t1 left join t2 on t1.key1 = t2.key2;-- 右連接select * from t1 right join t2 on t1.key1 = t2.key2;

    縱向合并(聯(lián)合查詢):

    把多條select語句查詢的結(jié)果合并為一個結(jié)果集,即追加 / 增加記錄。

    指數(shù)據(jù)集的縱向合并,從數(shù)據(jù)集被合并到主數(shù)據(jù)集中。

    注意 :

    兩張表必須擁有相同數(shù)量的字段;

    兩張表字段的順序必須相同;

    兩張表獨贏的字段的數(shù)據(jù)類型必須一致;

    字段名可以不相同,選取主數(shù)據(jù)集中的字段名(第一個表)。

    union 去重:select 字段1[,字段2,...] from 表名 union select 字段1[,字段2,...] from 表名;

    union all不去重:select 字段1[,字段2,...] from 表名 union all select 字段1[,字段2,...] from 表名;

    -- 合并查詢select * from t1union allselect * from t2;-- union去重select * from t1unionselect * from t2;

    【測試題】

    表a userid

    表b userid

    查詢出現(xiàn)在a表,不在b表的userid。

    思路:左反連接和右反連接

    select *from table_aleft join table_bon table_a.userid = table_b.useridwhere table_b.userid is null;

    order表:userid,endtime

    求每個userid的最新結(jié)束時間

    select userid,max(endtime)from ordergroup by uderid;

    order表:userid,endtime

    user表:userid,tel

    找出用戶結(jié)束時間在3月份的userid的tel

    select order.userid, user.telfrom user right join order on user.userid = order.useridwhere month(endtime) = 3;select order.userid, user.telfrom user right join order on user.userid = order.useridwhere endtime between ‘2021-03-01’ and ‘2021-03-31’;

    ?在一張表中查詢出員工姓名和對應(yīng)的領(lǐng)導(dǎo)姓名

    -- 自連接:通過設(shè)置別名實現(xiàn),將同一張表視為兩張表select t1.ename 員工姓名,t2.ename 領(lǐng)導(dǎo)姓名from emp t1left join emp t2 on t1.mgr = t2.empno;

    查詢?nèi)肼毴掌谠缬谄渲睂兕I(lǐng)導(dǎo)的員工信息:empno、ename、dname(部門表)

    select t1.empno 員工編號,t1.ename 員工姓名,t3.dname 部門名稱from emp t1left join emp t2 on t1.mgr = t2.empnoinner join dept t3 on t1.deptno = t3.deptnowhere t1.hiredate < t2.hiredate;

    二、子查詢

    子查詢:在一個select語句中包含另一個或者多個完整的select語句。

    子查詢出現(xiàn)的位置

    出現(xiàn)在where子句中:將子查詢返回的結(jié)果作為主查詢的條件

    出現(xiàn)在from子句中:將子查詢返回的結(jié)果作為主查詢的一個表

    子查詢的分類

    • 標(biāo)量子查詢:返回的結(jié)果是一個數(shù)據(jù)(單行單列);
    • 行子查詢:返回的結(jié)果是一行(單行多列);
    • 列子查詢:返回的結(jié)果是一列(多行單列);
    • 表子查詢:返回的結(jié)果是一張臨時表(多行多列);

    子查詢的操作符:

    • [NOT] IN:在【不在】其中
    • ANY:其中任何一個
    • ALL:全部(每個)

    -- 子查詢:標(biāo)量子查詢

    -- 查詢基本工資高于公司平均工資的員工信息(where子句中不能直接使用聚合函數(shù))select * from empwhere sal > (select avg(sal) from emp);-- 查詢與“張曉明”同一個領(lǐng)導(dǎo)的員工信息:empno、ename、job、mgrselect empno,ename,job,mgrfrom empwhere mgr = (select mgr from emp where ename = '張曉明')and ename <> '張曉明';

    -- 子查詢:行子查詢

    -- 查詢和“許飛龍”同部門同職位的員工信息:empno,ename,job,deptnoselect empno,ename,job,deptnofrom empwhere (deptno,job) = (select deptno,job from emp where ename = '許飛龍')and ename <> '許飛龍';

    -- 子查詢:列子查詢

    -- 查詢普通員工的工資等級:empno,ename,sal,gradeselect empno 員工號,ename 員工姓名,sal 基本工資,grade 工資等級from empleft join salgrade on sal between losal and hisalwhere empno not in (select distinct mgr from emp where mgr is not null);-- 查詢員工數(shù)不少于3個人的部門所有員工信息:empno,ename,deptno-- 思路:先查找出大于等于3人的部門編號select empno,ename,deptnofrom empwhere deptno in (select deptno from emp group by deptno having count(*) >= 3);-- 查詢基本工資高于51部門任意員工的員工信息select *from empwhere sal > any (select sal from emp where deptno = 51)and deptno <> 51;select *from empwhere sal > (select min(sal) from emp where deptno = 51)and deptno <> 51;-- 查詢基本工資高于51部門所有員工的員工信息select *from empwhere sal > all (select sal from emp where deptno = 51)and deptno <> 51;

    -- 子查詢:from子查詢

    -- 查詢各個部門最高工資的員工:empno,ename,sal,deptno-- 表子查詢必須設(shè)置別名select empno,ename,sal,emp.deptnofrom empleft join (select deptno,max(sal) as 最高工資 from emp group by deptno) as ton emp.deptno = t.deptnowhere sal = 最高工資;

    三、函數(shù)

    -- 字符串函數(shù)

    select concat('My','Name','Is','Jack'); #MyNameIsJackselect concat('My','Name','Is',null); #nullselect instr('ABCDE','C'); #3select left('ABCDE',4); #ABCDselect right('ABCDE',4); #BCDEselect mid('ABCDEFG', 3, 4); #CDEFselect mid('ABCDEFG', 3); #CDEFGselect substring('ABCDEFG', 3, 4); #CDEFselect substring('ABCDEFG', 3); #CDEFGselect ltrim('?? ABC'); #ABCselect rtrim('ABC?? '); #ABCselect trim('?? ABC?? '); #ABCselect replace('ABCdeF','de','DE'); #ABCDEFselect repeat('Shit',3); #ShitShitShitselect reverse('ABCDE'); #EDCBAselect upper('abcde'); #ABCDEselect lower('ABCDE');? #abcde-- 將員工表中姓名首字母大寫,其他字母小寫顯示select concat(upper(left(ename,1)),lower(mid(ename,2))) from emp;

    數(shù)學(xué)函數(shù)

    例如:

    abs() 絕對值

    floor() 向下取整 – 地板

    ceiling() 向上取整 – 天花板

    round() 四舍五入,第二個參數(shù)為保留小數(shù)位數(shù)

    rand() 返回一個0-1之間的隨機(jī)小數(shù)

    select rand(1); 輸入的隨機(jī)種子一樣,得到的結(jié)果一樣。

    日期時間函數(shù)

    date() 返回指定日期時間表達(dá)式的日期或者將文本字符串格式日期轉(zhuǎn)換成標(biāo)準(zhǔn)的日期格式

    select date('20200101'); #2020-01-01select date('2020-01-01 11:11:11'); #2020-01-01select week('2022-01-01'); #0select month('2020-01-01 11:11:11'); #1select quarter('2020-12-01 11:11:11'); #4select year('2020-12-01 11:11:11'); #2020select year('20-12-01'); #2020select date_add('2022-01-01',interval 1 day); #2022-01-02select date_add('2022-01-01',interval 1 year); #2023-01-01select adddate('2022-01-01',interval 1 month); #2022-02-01select date_sub('2022-01-01',interval 1 day); #2021-12-31select date_sub('2022-01-01',interval 1 year); #2021-01-01select subdate('2022-01-01',interval 1 month); #2021-12-01select date_format('2022-01-06 15:05:20','%Y-%m-%d'); #2022-01-06select date_format('2022-01-06 15:05:20','%Y-%m'); #2022-01select date_format('2022-01-06 15:05:20','%m'); #01select curdate(); #無參函數(shù),當(dāng)前電腦系統(tǒng)日期select curtime(); #無參函數(shù),當(dāng)前電腦系統(tǒng)時間select now();???? #無參函數(shù),當(dāng)前電腦系統(tǒng)日期時間select datediff('20220106','20211228'); #9 日期間隔天數(shù)-- 計算員工表中每個員工的工齡use test;select ename 姓名,hiredate 入職日期,round(datediff(curdate(),hiredate)/365) 工齡from emp;select unix_timestamp(); #當(dāng)前日期從1970-01-01 00:00:00開始到現(xiàn)在過了多少秒select unix_timestamp('2022-01-06'); #1641398400select from_unixtime(1641473220); #2022-01-06 20:47:00-- 查詢每個員工的試用截止日期(試用期三個月):ename,hiredate,試用截止日期select ename,hiredate,adddate(hiredate,interval 3 month)? 試用截止日期from emp;

    分組合并函數(shù) group_concat()

    對文本字符串進(jìn)行合并,跟group by結(jié)合使用,返回一個字符串結(jié)果。

    平時我們group by之后只能對數(shù)值型進(jìn)行聚合,不能對字符串?dāng)?shù)據(jù)聚合。

    忽略空置null

    -- 查詢每個部門有哪些員工select deptno,group_concat(ename)from empgroup by deptno;-- 查詢每個部門有哪些員工(去重)select deptno,group_concat(distinct ename)from empgroup by deptno;-- 查詢每個部門有哪些員工(排序)select deptno,group_concat(distinct ename order by sal desc)from empgroup by deptno;-- 查詢每個部門有哪些員工(指定分隔符/)select deptno,group_concat(distinct ename order by sal desc separator '/')from empgroup by deptno;

    邏輯函數(shù)

    ifnull()

    -- 計算每位員工的實發(fā)工資:基本工資 + 提成-- 思路:沒有提成的null 需要用0代替select ename,sal,ifnull(comm,0)+sal 實發(fā)工資from emp;

    if()

    -- 判斷每位員工的工資級別select ename,sal,if(sal>=15000,'高',if(sal<=9000,'低','中')) 工資級別from emp;

    case when end

    -- 判斷每位員工的工資級別select ename,sal,case when sal>=15000 then'高'when sal<=9000 then'低'else '中'end 工資級別from emp;

    開窗函數(shù)

    MySQL 8.0才支持。

    開窗函數(shù)是在滿足某種條件的記錄集合上執(zhí)行的特殊函數(shù)。

    靜態(tài)窗口 滑動窗口

    本質(zhì)還是聚合運算,但是使用靈活,在每一個記錄行上來執(zhí)行并返回計算結(jié)果。

    語法:

    開窗函數(shù)名稱([<字段名>]) over([partition by <分組字段>] [order by<排序字段>[desc]] [<細(xì)分窗口>])

    對于滑動窗口的范圍指定,通常使用between frame_start and frame_end語法來表示行范圍,rame_start 和frame_end可以支持如下關(guān)鍵字,來確定不同的動態(tài)行記錄:

    • current row 邊界是當(dāng)前行,一般和其他范圍關(guān)鍵字一起使用;
    • unbounded preceding 邊界是分區(qū)中的第一行;
    • unbounded following 邊界是分區(qū)中的最后一行;
    • expr preceding 邊界是當(dāng)前行減去expr的值;
    • expr following 邊界是當(dāng)前行加上expr的值;

    比如,下面都是合法的范圍:

    rows between 1 preceding and 1 following 窗口范圍是當(dāng)前行、前一行、后一行一共三行記錄;

    rows unbounded preceding 窗口范圍是當(dāng)前行到分區(qū)的最后一行;

    rows between unbounded preceding and unbounded following 窗口范圍是當(dāng)前分區(qū)中的所有行,等同于不寫;

    序號函數(shù)

    • row_number():顯示分區(qū)中不重復(fù)不間斷的序號;
    • dense_rank():顯示分區(qū)中重復(fù)不間斷的序號;
    • rank():顯示分區(qū)中重復(fù)間斷的序號;

    -- 開窗函數(shù):聚合函數(shù)-- 所有員工的平均工資select avg(sal) avg_sal from emp; #得到一個值select *,avg(sal) over() avg_sal from emp; #得到一列值(每個記錄行)-- 查詢各個部門的平均工資select deptno,avg(sal) avg_sal from emp group by deptno;select *,avg(sal) over(partition by deptno) avg_sal from emp; #同一個部門的數(shù)據(jù)會分到一個區(qū)域-- 各個部門按照入職日期計算累計工資select *,sum(sal) over(partition by deptno order by hiredate asc) sum_sal from emp;-- 按照入職日期計算各個部門當(dāng)前行的前一行和后一行的平均工資-- 例如:按照部門分組,按照入職日期升序排列,掃描第一條記錄,計算其前一行+當(dāng)前行+后一行的平均工資select *,avg(sal) over(partition by deptno order by hiredate rows between 1 preceding and 1 following) avg_sal from emp;-- 開窗函數(shù):序號函數(shù)-- 所有員工按照入職日期顯示排名select *,row_number() over(order by hiredate) as '排名' from emp; #在一個區(qū)內(nèi)按照入職日期進(jìn)行排序-- 各個部門員工按照基本工資顯示排名select *,row_number() over(partition by deptno order by sal desc) as 'row_number排名' from emp;select *,dense_rank() over(partition by deptno order by sal desc) as 'dense_rank排名' from emp;select *,rank() over(partition by deptno order by sal desc) as 'rank排名' from emp;

    【練習(xí)題】

    計算2017年每筆投資均大于50萬元的用戶

    select user_idfrom cmn_investment_requestwhere year(created_at)=2017group by user_idhaving min(invest_amount)>500000;

    計算2017年僅投資過CFH和AX產(chǎn)品的用戶

    select user_id,group_concat(distinct invest_item order by invest_item desc)from cmn_investment_requestwhere year(created_at)=2017group by user_idhaving group_concat(distinct invest_item order by invest_item desc)=’CFH,AX’;

    計算歸屬于10002業(yè)務(wù)員的投資金額

    select sum(invest_amount)from dim_agentleft join cmn_investment_requeston cmn_investment_request.user_id=dim_agent.user_idand created_at between start_date and end_datewhere agent_id=’10002’;

    與50位技術(shù)專家面對面20年技術(shù)見證,附贈技術(shù)全景圖

    總結(jié)

    以上是生活随笔為你收集整理的【一周入门MySQL—3】多表查询、子查询、常用函数的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。