【題目】
“滿意度表”記錄了教師和學生對課程的滿意程度。“是否滿意”列裡是老師和學生對課程的評價,其中“是”表示教師和學生都滿意。

“ 使用者表”記錄了學校教師和學生的資訊。每個使用者有唯一鍵 “編号”,“是否在系統”表示這個使用者是否還在這所學校裡,“角色”表示這個人是學生還是教師。
兩個表的關系:滿意度表的“學生編号” 、 “教師編号” 和使用者表的 “編号” 聯結。
現在需要分析出學校裡人員對課程的滿意度。滿意度的計算方式如下:
(教師和學生對課程都滿意且已存在目前教務系統中的使用者) / (在學校裡的人數)
【解題思路】
1.多表聯結
統計滿意度的前提是需要使用者在學校裡,需要用到“使用者表”裡的“是否在系統”來判斷。滿意度需要用到“滿意度表”。是以涉及到兩個表裡的資料,就要用到《猴子 從零學會sql》裡講過的多表聯結。
那麼,使用哪種聯結呢?
統計值為滿意度,是以使用“滿意度表”為主表,進行左聯結。
from 滿意度表
left join 使用者表;
如何聯結呢?
兩個表的關系:滿意度表的“學生編号” 、 “教師編号” 和使用者表的 “編号” 聯結。是以聯結條件是:
滿意度表.教師編号 = 使用者表.編号 or 滿意度表.學生編号 = 使用者表.編号
基于上面的分析,多表聯結查詢sql語句如下:
from 滿意度表
left join 使用者表
on (滿意度表.教師編号 = 使用者表.編号 or
滿意度表.學生編号 = 使用者表.編号);
2.查詢條件
滿意度等于:
由這個公式可以知道,分子和分母計算的前提都是存在學校裡的使用者。是以,查詢條件是:使用者表中存在學校裡的使用者。
把條件子句加入前面的多表查詢sql裡,就是下面的sql:
from 滿意度表
left join 使用者表
on (滿意度表.教師編号 = 使用者表.編号 or 滿意度表.學生編号 = 使用者表.編号)
where 使用者表.是否在系統 = '是';
上面sql運作結果如下,我們發現,教師編号“02”不在學校裡(對應的列“是否在系統”裡的值是“否”),這是怎麼回事呢?
我們重新梳理一遍邏輯。
目前的邏輯是:(教師編号 = 編号 或 學生編号 = 編号) 且 編号在學校中。這等價于:
(教師編号 = 編号 且 編号在學校中) 或(學生編号 = 編号,且 編号在學校中)
這裡的“或”邏輯會将範圍擴大,是以且不在學校的“02”号教師也會出現在查詢結果中。
正确的做法是先從表中分别選出“在學校”裡的學生和教師,然後再多表聯結。也就是:
(教師編号 = 編号 且 該編号在系統中 )并且
(學生編号 = 編号 且 該編号在系統中)
對應的sql如下:
from 滿意度表
left join(select 編号 from 使用者表 where 是否在系統='是') as 學生
on (滿意度表.學生編号 = 學生.編号)
left join(select 編号 from 使用者表 where 是否在系統='是') as 教師
on (滿意度表.教師編号 = 教師.編号);
3.統計
我把這個公示簡化為:滿意度=a/b
其實a=教師和學生對課程都滿意且已存在目前教務系統中的使用者
b=在學校裡的人數
我們隻需要把a和b的值計算出來就可以啦。
1)計算a
統計好“是否滿意”列裡有多少個值為“是”。
我們可以把“是”轉化成1,然後累計求和,對應的sql就是:
else 0
end)
2)計算b
b=在學校裡的人數,直接用計數函數(count)就可以:count(是否滿意)
3)計算出滿意度
滿意度=a/b,也就是
as 滿意度
把這個計算公示加入前面sql語句的查詢結果裡就是(下面的select子句):
from 滿意度表
left join(select 編号 from 使用者表 where 是否在系統='是') as 學生
on (滿意度表.學生編号 = 學生.編号)
left join(select 編号 from 使用者表 where 是否在系統='是') as 教師
on (滿意度表.教師編号 = 教師.編号);
最後的查詢結果是滿意度=0.75。
【本題考點】
● 考察多表查詢的應用
● 如何将業務需求轉換為sql語句的能力
● 聚合函數的運用
【舉一反三】
下表是一家出行公司(比如滴滴、Uber)的資料庫表。乘客通過該公司的app叫車,司機通過app接收訂單。
Users 表裡存放的是使用者資訊。每個使用者有唯一值(Users_Id) 。Banned 表示使用者是否因為違規被禁止使用app。Role 記錄了使用者的角色,裡面的值driver是司機,client是乘客,partner是合夥人。
Trips 表記錄了各個計程車的行程資訊。每段行程有唯一鍵(Id) 。Status 行程類型 ‘completed’表行程正常結束, ‘cancelled_by_driver’ 表示行程因為司機原因取消,‘cancelled_by_client’表示行程因為乘客原因取消。
兩個表的聯結關系:Trips 表(Client_Id 、 Driver_Id) 和 Users 表中 Users_Id 的聯結。
寫一段 SQL 語句查出非禁止使用者的取消率。
取消率的計算方式如下:(被司機或乘客取消的非禁止使用者生成的訂單數量) / (非禁止使用者生成的訂單總數)
參考答案:
1.多表聯結,找出非禁止的使用者
from trips
left join (select users_id from users where banned = 'no') as client
on (trips.Client_Id = client.users_id)
left join (select users_id from users where banned = 'no') as driver
on (trips.Driver_Id = driver.users_id);
2.按日期分組
因為要計算的是“每天”的取消率,是以要按日期分組,統計每一天的。
group by trips.request_at
3.計算取消率
被司機或乘客取消的非禁止使用者生成的訂單數量=
sum(case when status = 'completed' then 1 else 0 end)
非禁止使用者生成的訂單總數=count(status)
最終sql如下:
from trips
left join (select users_id from users where banned = 'no') as client
on (trips.Client_Id = client.users_id)
left join (select users_id from users where banned = 'no') as driver
on (trips.Driver_Id = driver.users_id);
group by trips.request_at;