SQL進階day9————聚合與分組

?

目錄

1聚合函數

1.1SQL類別高難度試卷得分的截斷平均值

1.2統計作答次數

1.3?得分不小于平均分的最低分

2?分組查詢

2.1平均活躍天數和月活人數

2.2?月總刷題數和日均刷題數

2.3未完成試卷數大于1的有效用戶

1聚合函數

1.1SQL類別高難度試卷得分的截斷平均值

我的錯誤代碼:截斷平均值是有專門的函數嗎?

select tag,difficulty,avg(score) clip_avg_score
from examination_info ei join exam_record
using(id)
group by tag
where tag = 'SQL' and difficulty='hard'
and score not in (max(score),min(score))

我的思路改正:用 (全部值 - 最大值 - 最小值) / (總數-2) ,但是缺點就是,如果最大值和最小值有多個,這個方法就很難篩選出來

SELECT ei.tag,ei.difficulty,ROUND((SUM(er.score)-MIN(er.score)-MAX(er.score)) / (COUNT(er.score)-2),1) AS clip_avg_score
FROM examination_info ei join exam_record er
on ei.exam_id = er.exam_id
where ei.tag = "SQL"
AND ei.difficulty = "hard";

標準正確代碼:

使用in子句將最大值和最小值排除掉,再求平均值

  • 懶人寫法,可以用with...as句式將要多次使用的表只寫1次即可(WITH AS 語法是MySQL中的一種臨時結果集,它可以在SELECT、INSERT、UPDATE或DELETE語句中使用。通過使用WITH AS語句,可以將一個查詢的結果存儲在一個臨時表中,然后在后續的查詢中引用這個臨時表。這樣可以簡化復雜的查詢,提高代碼的可讀性和可維護性。但是不知道哪個MySQL版本開始支持with...as句式的,我的本地電腦里面是Navicat 15 for MySQL,不支持
  • union把max和min的結果集中在一行當中,這樣形成一列多行的效果,不用多寫一次代碼
# t1篩選出SQL高難度的數據
WITH t1 as(SELECT er.*,ei.tag,ei.difficultyFROM exam_record er INNER JOINexamination_info eiON er.exam_id = ei.exam_idWHERE tag = "SQL" and difficulty = "hard"
)# 在t1的基礎上計算均值
SELECT tag,difficulty,round(avg(score),1)
FROM t1# 用in子句將最大值和最小值排除掉,再求平均值 not in
WHERE score not in (SELECT max(score)FROM t1UNIONSELECT min(score)FROM t1
)

Q:為什么這里where換成and也不報錯,因為前面有on?那么where和on有啥區別呢,可以只有一個嗎?

A:

(1)where和having是在臨時表生產之后,對臨時表中的數據進行過濾用的。

如SQL語句:select * form tab1 left join tab2 on (tab1.size = tab2.size) where tab2.name=’AAA’

(2)?on是在生成中臨時表之前就去作用的,它會在數據源那里就把不符合要求的數據給過濾掉,即是先把不符合條件的記錄過濾后才進行統計,它就可以減少中間運算要處理的數據所以on運行的速度最快。

如SQL語句:select * form tab1 left join tab2 on (tab1.size = tab2.size and tab2.name=’AAA’)

(3)在兩個表聯接時才用on的,所以在一個表的時候,就剩下where跟having比較了。在這單表查詢統計的情況下,如果要過濾的條件沒有涉及到要計算字段,那它們的結果是一樣的,但是where可以使用rushmore技術,而having就不能,在速度上后者要慢。

(4)? 如果要涉及到計算的字段,where的作用時間是在計算之前就完成的,而having就是在計算后才起作用的,所以在這種情況下,兩者的結果會不同。???

(5) 在多表聯接查詢時,on比where更早起作用。系統首先由on根據各個表之間的聯接條件,把多個表合成一個臨時表后,再由where進行過濾,然后再計算,計算完后再由having進行過濾。

1.2統計作答次數

我的報錯代碼:求已完成的試卷數時應該要分組一下,exam_id

select count(er.id) total_pv,
count(er.submit_time) complete_pv,
count(t2.exam_id) complete_exam_cnt
from exam_record er,(select count(exam_id) from exam_record 
group by exam_id) t2

正確代碼1:

主要在于已完成的試卷數的統計,因為這個帶有條件,且需要統計聚合結果,可以使用 聚合函數與case when 結合count中是可以加條件的

select 
count(*)  total_pv,
count(score)  complete_pv,
count(distinct case when score is null then null else exam_id end)  complete_exam_cnt
from exam_record

復習case when

(1)case expr when v1 then r1 [when v2 then r2] ...[else rn] end

?????? 例如:case 2 when 1 then 'one' when 2 then 'two' else 'more' end 返回two

?????? case后面的值為2,與第二條分支語句when后面的值相等相等,因此返回two

(2)case when v1 then r1 [when v2 then r2]...[else rn] end

?????? 例如:case when 1<0 then 'T' else 'F' end返回F

?????? 1<0的結果為false,因此函數返回值為else后面的F

正確代碼2:

select count(*) as total_pv,
count(score) as complete_pv,
count(distinct exam_id,score IS NOT NULL or null) as complete_exam_cnt
# 是逗號,連接不是and連接
from exam_record

在select和count后面都可以加條件的,但是要明白內核:

count(distinct exam_id,score IS NOT NULL or null) as complete_exam_cnt (正確)

不能是

count(distinct exam_id and score IS NOT NULL or null) as complete_exam_cnt (錯誤,結果永遠為2, 這個題只是碰巧結果為2,改一個數據就不對了)

1 用and:

(1)一般在where后篩選過濾,還是得到的滿足條件的score

(2)如果在select后直接加條件判斷:這里的score is not null 是判斷

  • 符合條件的返回 true ,即為1
  • 不符合的返回 false ,即為0?

(3) 加上exam_id,進行and邏輯運算

  • exam_id 本身為值,可以理解為真 在 and 邏輯下,所以上一步的1,0并不會變化,后面加上or NULL,否則會把0也計算上。

(4) 在上一步的基礎上去重,則只會剩下1和0

  • 經過and運算之后,只剩下一列數據,多行1和0
  • distinct 去重后,就只剩下兩行數據 1 和 0

(5)所以這時候再進行count計算,結果恒為2 (兩行數據)

?2 正確答案的執行邏輯:

(1)用,連接(從之前的邏輯判斷,變為多列組合)

(2)這時候distinct 去重后,就不是只剩下兩行數據 1 和 0,而是會把score為null也會考慮進去。

(3)結果應該是3,如果沒有or NULL,就是5行了(null為0會被計數)

1.3?得分不小于平均分的最低分

?

我的代碼:where后面的條件錯了,但是思路大概這樣。

select score min_score_over_avg 
from exam_record er join examination_info ei
on er.id = ei.id
group by exam_id
where score>=avg(score) and ei.tag = 'SQL'
order by score asc
limit 1

修改我的代碼:

select er.score min_score_over_avg 
from exam_record er 
left join examination_info ei
on er.exam_id = ei.exam_id # 不是按照id連接
where  ei.tag = 'SQL' 
and score>= (SELECT avg(er.score) from exam_record er
left join examination_info ei
on er.exam_id=ei.exam_id
where ei.tag='SQL')
order by score asc
limit 1

(1)表連接是按照exam_id ,不是按照id連接?

(2)score>=某個值,這里不能直接score>=avg(score),而是應該通過表查詢返回得到avg(score),然后在進行比較。

改進我的代碼:

這里有表查詢的部分重復了兩次,可以用with...as句式將要多次使用的表命名,這樣可以只寫一次,多次調用。

此外,order by score asc? limit 1? 可以換為min函數。

with t as
(SELECT score from exam_record er
left join examination_info ei
on er.exam_id=ei.exam_id
where ei.tag='SQL')select min(score) min_score_over_avg 
from t 
where score>= 
(SELECT avg(t.score) from t)

2?分組查詢

2.1平均活躍天數和月活人數

我的代碼:此處活躍指有交卷行為,用戶平均月活躍天數avg_active_days啥意思?

with t as
(select * 
from exam_record
where year(start_time)=2021)select month(start_time) 'month',
count(submit_time) mau
from t
group by month(submit_time)

正確代碼:

select DATE_FORMAT(start_time,"%Y%m") as month,
round(count(distinct uid,date_format(start_time,"%Y%m%d"))/count(distinct uid),2) as avg_active_days,
count(distinct uid) as mau
from exam_record
where submit_time is not NULL
and YEAR(submit_time) =2021
group by month;

(1)202107是用date_format函數:DATE_FORMAT(start_time,"%Y%m") as month

(2)主要難的一點是天數的計算。

到底是count(distinct uid,date_format(start_time,"%Y%m%d"))

還是count(start_time)作為分子呢

關鍵是理解題目的意思是:天數。

假設一個uid 比如1001在2021-07-06這一天有二個記錄,如果是count(start_time)那么就是天數是2,但是如果是count(distinct uid,date_format(start_time,"%Y%m%d"))天數就是1了

復盤探索:

(1)先找出2021年,活躍的用戶ID和時間(具體到哪天)

(2)如果不考慮uid,直接按照活躍時間去重,那么不同用戶在同一天活躍記錄會被去重到只剩下1條,

(3)同理,如果只安裝用戶ID去重,那么同一用戶在不同天的記錄也會被去重到只有1條。這里查詢的實際是月活躍的用戶有哪些。

(4) 所以要去重的目的是,同一個用戶,在同一天,重復提交活躍多次的記錄。(因為這里是按天算,同一天同一個用戶只算一次。)

(5)用戶平均月活躍天數=月活躍天數?/月活躍用戶

:count(distinct uid,date_format(start_time,"%Y%m%d"))/count(distinct uid)

月活躍天數:

月活躍用戶:?

2.2?月總刷題數和日均刷題數

我的代碼:分組好像報錯,后面那個求總數我也不知道咋整

分組報錯問題:MySQL提供了any_value()函數來抑制ONLY_FULL_GROUP_BY值被拒絕

select 
date_format(submit_time,'%y%m') submit_month,
count(score) month_q_cnt,
count(score)/day(month(submit_time)) avg_day_q_cnt
from practice_record
group by date_format(submit_time,'%y%m%d') 
having year(submit_time)=2021

(1)當月天數求錯了,我是想先求出當前月,再求出當月天:這樣操作結果是不對的。

? ??

應該用last_day函數求出最后一天,然后用day函數求出這個日期的天數。

復習【日期時間函數】

●?? year(date)——獲取年的函數

●?? month(date)——獲取月的函數

●?? day(date)——獲取日的函數

●?? date_add(date,interval expr type)——對指定起始時間進行加操作

●?? date_sub(date,interval expr type)——對指定起始時間進行減操作

●?? datediff(date1,date2)——計算兩個日期之間間隔的天數

●?? date_format(date,format)——將日期和時間格式化

代碼改正:

select 
date_format(submit_time,'%y%m') submit_month,
any_value(count(score)) month_q_cnt,
any_value(round(count(score)/day(last_day(submit_time)),3)) avg_day_q_cnt
from practice_record
where year(submit_time)='2021'
# where date_format(submit_time,'%y')='2021'
group by submit_month

該年的總體情況,可以用union all來連接,完整代碼:

select date_format(submit_time,'%Y%m') submit_month,
any_value(count(question_id)) month_q_cnt,
any_value(round(count(question_id)/day(LAST_DAY(submit_time)),3)) avg_day_q_cnt 
from practice_record
where date_format(submit_time,'%Y')='2021'
group by submit_month
union all
select '2021匯總' as submit_month,
count(question_id) month_q_cnt,
round(count(id)/31,3) avg_day_q_cnt
from practice_record
where date_format(submit_time,'%Y')='2021'
order by submit_month;

復習:

1、區別1:取結果的交集

1)union: 對兩個結果集進行并集操作, 不包括重復行,相當于distinct, 同時進行默認規則的排序;

2)union all: 對兩個結果集進行并集操作, 包括重復行, 即所有的結果全部顯示, 不管是不是重復;

2、區別2:獲取結果后的操作

1)union: 會對獲取的結果進行排序操作

2)union all: 不會對獲取的結果進行排序操作

3、總結

union all只是合并查詢結果,并不會進行去重和排序操作,在沒有去重的前提下,使用union all的執行效率要比union高。

2.3未完成試卷數大于1的有效用戶

我的代碼:羅里吧嗦答案還不對。。

with t as
(select uid,er.exam_id,start_time,submit_time,tag
from exam_record er , examination_info ei
where er.exam_id=ei.exam_id
and date_format(start_time,'%Y')='2021')select uid,
(select count(submit_time) from t
where submit_time is NULL) incomplete_cnt,
(select count(submit_time) from t
where submit_time is not NULL) complete_cnt
from t
where (select count(submit_time) from t
where submit_time is NULL)<5 and (select count(submit_time) from t
where submit_time is not NULL)>1
order by incomplete_cnt

我的代碼改正:

select uid,
sum(case when submit_time is NULL then 1 else 0 end ) incomplete_cnt,
sum(case when submit_time is NULL then 0 else 1 end ) complete_cnt
from exam_record er join examination_info ei
on er.exam_id=ei.exam_id
where date_format(start_time,'%Y')='2021'
group by uid
having incomplete_cnt >1 and incomplete_cnt<5 and complete_cnt>1
order by incomplete_cnt

接下來是detail,作答過的試卷tag集合,是提交日期:類型;一直重復顯示

我的完整代碼:

select uid,
sum(case when submit_time is NULL then 1 else 0 end ) incomplete_cnt,
sum(case when submit_time is NULL then 0 else 1 end ) complete_cnt,
group_concat(DISTINCT concat_ws(':',date_format(start_time,"%Y-%m-%d"),tag) order by start_time Separator ';') detailfrom exam_record er join examination_info ei
on er.exam_id=ei.exam_id
where date_format(start_time,'%Y')='2021'
group by uid
having incomplete_cnt >1 and incomplete_cnt<5 and complete_cnt>1
order by incomplete_cnt desc

注意:select后面的屬性,不管計算了多長,每個之間都要有逗號!!!?

大佬代碼:

SELECT uid,
SUM(CASE WHEN submit_time IS NULL THEN 1 ELSE 0 END) "incomplete_cnt",
SUM(CASE WHEN submit_time IS NULL THEN 0 ELSE 1 END) "complete_cnt",
group_concat(distinct concat_ws(':',date(start_time),tag) 
order by start_time separator ';') as detail
FROM exam_record er INNER JOIN
examination_info ei 
ON er.exam_id = ei.exam_id
WHERE year(start_time) = 2021
GROUP BY uid
HAVING complete_cnt >= 1 AND incomplete_cnt > 1 AND
incomplete_cnt < 5
ORDER BY incomplete_cnt desc

其中

(1)用sum和case when函數來求完成和未完成的試卷數

(2)detail的實現是用concat_ws或者concat函數將submit_time和tag連接并且同時distinct:

函數group_concat([DISTINCT] 要連接的字段 [Order BY ASC/DESC?排序字段] [Separator'分隔符'])

concat()函數

  • 功能:將多個字符串連接成一個字符串。

  • 語法:concat(str1, str2,…)

  • 返回結果為連接參數產生的字符串,如果有任何一個參數為null,則返回值為null。

concat_ws()函數

  • 功能:和concat()一樣,將多個字符串連接成一個字符串,但是可以一次性指定分隔符(concat_ws就是concat with separator)
  • 語法:concat_ws(separator, str1, str2, …)
  • 說明:第一個參數指定分隔符。需要注意的是分隔符不能為null,如果為null,則返回結果為null。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/23733.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/23733.shtml
英文地址,請注明出處:http://en.pswp.cn/web/23733.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

開放式耳機十大品牌推薦!怎么選耳機看這六招!

隨著耳機廠家的瘋狂內卷&#xff0c;以前讓學生黨望其項背的千元耳機技術&#xff0c;紛紛被廠家下沉至百元耳機&#xff0c;是以2024年始&#xff0c;百元開放式耳機以新物種、價低格而爆火。看到身邊朋友爭相購買開放式耳機&#xff0c;既當耳飾&#xff0c;又當耳機&#xf…

分享:2024年(第12屆)“泰迪杯”數據挖掘挑戰賽成績公示

2024年&#xff08;第12屆&#xff09;“泰迪杯”數據挖掘挑戰賽歷時兩個月順利結束。競賽采用盲審&#xff08;屏蔽參賽者信息&#xff1b;評審專家只能評閱非本區域作品&#xff1b;三位評閱專家同時評閱同一作品&#xff0c;超限調整后再取平均分&#xff09;&#xff0c;答…

redis做為緩存,mysql的數據如何與redis進行同步呢?

讓我們一步步來實現如何讓MySQL數據庫的數據和Redis緩存保持同步。想象一下&#xff0c;MySQL是一個大倉庫&#xff0c;存放著所有重要的貨物&#xff08;數據&#xff09;&#xff0c;而Redis則像是一個快速取貨窗口&#xff0c;讓你能更快拿到常用的東西。為了讓兩者保持一致…

FC-135是一款受歡迎的32.768kHz晶振

KHZ中愛普生是以32.768KHZ最為出名的。32.768K晶振是一款數字電路板都要使用到的重要部件&#xff0c;有人比喻為電路板的冰發生器&#xff0c;也就是說心如果停止了跳動&#xff0c;那么電路板也將無法進行穩定的工作了&#xff0c;愛普生晶振FC-135是一款受歡迎的32.768KHz晶…

ALOS PALSAR 產品介紹

簡介 L1.0 產品 該產品由原始觀測數據&#xff08;0 級&#xff09;通過數據編輯&#xff08;如位重新調整和添加軌道信息&#xff09;生成。它是重建的、未經處理的信號數據&#xff0c;帶有輻射和幾何校正系數&#xff08;附加但未應用&#xff09;。 L1.1 產品 該產品由…

Java Web學習筆記13——JSON

JavaScript自定義對象 定義格式&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Js-對…

前端面試題日常練-day57 【面試題】

題目 希望這些選擇題能夠幫助您進行前端面試的準備&#xff0c;答案在文末 1. 在PHP中&#xff0c;以下哪個符號用于連接兩個字符串&#xff1f; a) b) . c) , d) : 2. PHP中的預定義變量$_SESSION用于存儲什么類型的數據&#xff1f; a) 用戶的輸入數據 b) 瀏覽器發送的…

前后端不分離與前后端分離的Java Web開發對比介紹

在現代Web開發中&#xff0c;前后端架構設計有兩種主要模式&#xff1a;前后端不分離和前后端分離。本文將詳細介紹這兩種模式&#xff0c;展示如何使用Spring Boot開發應用&#xff0c;并提供可運行的示例代碼。 前后端不分離的Java Web開發 在前后端不分離的架構中&#xf…

Linux 命令 `uniq`:去重利器

Linux 命令 uniq&#xff1a;去重利器 在 Linux 系統中&#xff0c;處理文本數據是日常任務中不可或缺的一部分。當我們面對大量重復的數據行時&#xff0c;如何高效地去除這些重復項成為了一個值得探討的話題。這時&#xff0c;uniq 命令就派上了用場。本文將介紹 uniq 命令的…

走進AI大模型的瘦身房,看看如何把大模型塞進我們的手機里

人工智能的廣泛應用已經改變了我們的生活方式。從智能助手到自動駕駛汽車&#xff0c;AI技術正變得越來越普及。然而&#xff0c;這些AI大模型往往參數眾多&#xff0c;體積龐大&#xff0c;需要依賴龐大的網絡計算資源&#xff0c;如何讓大模型能在個人電腦&#xff0c;甚至手…

【docker】 /bin/sh: ./mvnw: No such file or directory解決方案.dockerignore被忽略

報錯如下&#xff1a;解決方案很簡單&#xff0c;但是容易讓大家忽視的問題。 > CACHED [stage-1 2/4] WORKDIR /work/ …

【Android面試八股文】使用equals和==進行比較的區別?

使用equals和==進行比較的區別 這道題想考察什么 ? 在開發中當需要對引用類型和基本數據類型比較時應該怎么做,為什么有區別。 考察的知識點 equals 的實現以及棧和堆的內存管理 考生應該如何回答 在 Java 中,equals() 方法和 == 運算符用于比較對象之間的相等性,但它…

數據賦能(111)——體系:監控數據采集——概述、關注焦點

概述 監控數據采集是指對數據采集過程進行實時的監視和控制&#xff0c;以確保數據的準確性、完整性和可用性。監控數據采集旨在及時發現并解決數據采集過程中出現的問題&#xff0c;保證數據的穩定性和可靠性。 監控數據采集的主要目的是確保數據的準確性、完整性和可用性。…

要改進單例模式的實現以確保線程安全并優化性能,有幾種常見的方法

要改進單例模式的實現以確保線程安全并優化性能&#xff0c;有幾種常見的方法。以下是幾種改進 ThreadUtil 單例實現的方法&#xff1a; ### 1. 懶漢式&#xff08;線程安全版&#xff09; 使用同步機制來確保線程安全&#xff0c;但只在第一次創建實例時同步&#xff0c;這樣…

正則匹配規則

正則表達式&#xff1a;查找某字符串開始和某字符串結束的字符串 a.*?b 查找以a開始&#xff0c;并且以b結束的字符串 例如&#xff1a; 字符串為&#xff1a;上海12345abcd.opi,.<>北京 patten &#xff1a;上海.*?北京 結果&#xff1a;上海12345abcd.opi,.<>…

用互斥鎖解決緩存擊穿

我先說一下正常的業務流程&#xff1a;需要查詢店鋪數據&#xff0c;我們會先從redis中查詢&#xff0c;判斷是否能命中&#xff0c;若命中說明redis中有需要的數據就直接返回&#xff1b;沒有命中就需要去mysql數據庫查詢&#xff0c;在數據庫中查到了就返回數據并把該數據存入…

Unity DOTS技術(三)JobSystem+Burst+批處理

文章目錄 一.傳統方式二.使用JobSystemBurst方式三.批處理 在之前的例子中我們都中用的單線程與傳統的編譯器,下面我們試著使用JobSystem與打找Burst編譯器來對比一下性能的差異. 一.傳統方式 1.首先用傳統方式創建10000個方塊并讓基每幀旋轉 2.我們可以看到他的幀率是40 …

RBAC 模型梳理

1. RBAC 模型是什么 RBAC&#xff08;Role-Based Access Control&#xff09;即&#xff1a;基于角色的權限控制。通過角色關聯用戶&#xff0c;角色關聯權限的方式間接賦予用戶權限。 RBAC 模型由 4 個基礎模型組成&#xff1a; 基本模型 RBAC0&#xff08;Core RBAC&#x…

面向AI應用開發實戰分享 - 基礎篇

“前端轉AI&#xff0c;第一講來了” 引言 如果你是一名前端開發&#xff0c;同時又對AI開發很感興趣&#xff0c;那么恭喜你&#xff0c;機會來了。 如果不是也沒關系&#xff0c;同樣能幫大家了解AI應用的開發思路。 本文將帶大家從面向AI開發的基礎知識開始&#xff0c;再…

Vue3:ElementPlus分裝動態列表查詢表單和彈窗動態表單

文章目錄 概要表單組件封裝彈窗組件調用表單組件頁面列表調用查詢表單 表單組件封裝 組件代碼 <template><el-formref"ruleFormRef"class"elForm":inline"true":rules"rules":model"TableList"label-width"…