題解 | #根據(jù)指定記錄是否存在輸出不同情況#
根據(jù)指定記錄是否存在輸出不同情況
http://www.fangfengwang8.cn/practice/f72d3fc27dc14f3aae76ee9823ccca6b
# 把 當(dāng)有任意一個(gè)0級(jí)用戶未完成試卷數(shù)大于2 作為一個(gè)條件,臨時(shí)表,如果有,那統(tǒng)計(jì)數(shù)量是大于0的 # 總體上輸出全部用戶的指標(biāo),如果是第一種情況,就只篩選出等級(jí)為0的 # 統(tǒng)計(jì)是否有滿足條件的 WITH temp_0 AS( SELECT uid FROM user_info LEFT JOIN exam_record USING(uid) WHERE level = 0 # 選擇0級(jí)用戶 GROUP BY uid HAVING SUM(IF(score, 0, 1)) > 2 # 未完成的記錄數(shù)大于2 ) SELECT uid, # 未完成數(shù)計(jì)算,這里要判斷是否有開(kāi)始的記錄,如果沒(méi)有,就說(shuō)明沒(méi)有做這個(gè),要置為0 SUM(IF(score IS NULL AND start_time IS NOT NULL, 1, 0)) incomplete_cnt, # 未完成率 = 未完成數(shù)/開(kāi)始作答次數(shù),為了不讓分母為0,所以使用if,其實(shí)只要給個(gè)數(shù)就行,這樣在沒(méi)有開(kāi)始記錄的時(shí)候也給個(gè)數(shù),分子始終為0,計(jì)算出來(lái)也是0 ROUND(SUM(IF(score IS NULL AND start_time IS NOT NULL, 1, 0)) / COUNT(IF (start_time, start_time, 0)), 3) incomplete_rate FROM user_info a # 左外聯(lián)結(jié),這是為了防止有些用戶沒(méi)有記錄 LEFT JOIN exam_record b USING(uid) # 使用where語(yǔ)句控制開(kāi)關(guān), # 使用EXISTS謂詞判斷是否存在滿足條件的,如果至少有一個(gè)滿足條件的,那就選擇所有等級(jí)為0的用戶 WHERE ( EXISTS(SELECT 1 FROM temp_0) AND a.level = 0) OR # 沒(méi)有滿足條件的,并且有開(kāi)始記錄的(防止沒(méi)有作答記錄的其余用戶也計(jì)算進(jìn)來(lái)) (NOT EXISTS(SELECT 1 FROM temp_0) AND b.start_time IS NOT NULL) GROUP BY uid ORDER BY incomplete_rate
踩的坑:1.臨時(shí)表選擇臨時(shí)用戶忘了加分組
2.未完成數(shù)計(jì)算要加上檢測(cè)是否有作答開(kāi)始記錄
3.未完成率計(jì)算要給分母一個(gè)常數(shù),如果是null,結(jié)果也會(huì)是null
4.使用exists關(guān)鍵字來(lái)判斷是否存在和不存在
新知識(shí)點(diǎn):
1.當(dāng)然,我很樂(lè)意為您解釋這個(gè)WHERE
子句的邏輯。
在這個(gè)WHERE
子句中,我們有兩個(gè)主要的條件,它們通過(guò)OR
連接。這意味著如果任何一個(gè)條件為真,相應(yīng)的行就會(huì)被選中。讓我們分別看看這兩個(gè)條件:
- EXISTS(SELECT 1 FROM temp_0) AND a.level = 0:EXISTS(SELECT 1 FROM temp_0): 這是一個(gè)EXISTS子查詢,它檢查temp_0中是否有任何行。temp_0是之前定義的臨時(shí)表,用于查找所有0級(jí)用戶中未完成試卷數(shù)大于2的用戶。如果至少有一個(gè)這樣的用戶,那么EXISTS(SELECT 1 FROM temp_0)的結(jié)果為真(TRUE)。a.level = 0: 這是一個(gè)簡(jiǎn)單的條件,檢查用戶信息表(user_info)中用戶的等級(jí)是否為0。這個(gè)復(fù)合條件意味著如果存在至少一個(gè)0級(jí)用戶的未完成試卷數(shù)大于2,那么查詢將選擇所有0級(jí)用戶的信息,不論這些用戶是否有作答記錄。
- NOT EXISTS(SELECT 1 FROM temp_0) AND b.start_time IS NOT NULL:NOT EXISTS(SELECT 1 FROM temp_0): 這是EXISTS的相反情況。它檢查是否沒(méi)有任何0級(jí)用戶的未完成試卷數(shù)大于2。如果沒(méi)有這樣的用戶,那么此條件為真。b.start_time IS NOT NULL: 這個(gè)條件檢查exam_record表中是否存在作答記錄。只有當(dāng)用戶至少開(kāi)始了一次作答,這個(gè)條件才為真。當(dāng)上述兩個(gè)條件都為真時(shí),這意味著如果沒(méi)有任何0級(jí)用戶的未完成試卷數(shù)大于2,那么查詢將選擇所有至少有作答記錄的用戶的信息。
綜上所述,這個(gè)WHERE
子句的邏輯確保了當(dāng)至少有一個(gè)0級(jí)用戶的未完成試卷數(shù)大于2時(shí),只統(tǒng)計(jì)0級(jí)用戶的信息。如果沒(méi)有這樣的用戶,那么統(tǒng)計(jì)所有有作答記錄的用戶的信息。這樣的設(shè)計(jì)符合您之前描述的需求。
2.在EXISTS(SELECT 1 FROM temp_0)
這個(gè)表達(dá)式中,SELECT 1
是一種常見(jiàn)的SQL技巧,特別是在與EXISTS
子句一起使用時(shí)。
在這個(gè)上下文中,SELECT 1
的目的不是為了選擇表中的某個(gè)具體列,而是僅僅用來(lái)檢查是否存在符合特定條件的行。EXISTS
子句的作用是檢查嵌套查詢(在這里是SELECT 1 FROM temp_0
)是否返回至少一個(gè)行。如果返回至少一個(gè)行,EXISTS
就返回TRUE
;如果沒(méi)有返回任何行,EXISTS
返回FALSE
。
因此,在這個(gè)表達(dá)式中:
SELECT 1
只是一個(gè)簡(jiǎn)單的方式來(lái)說(shuō)“我只關(guān)心是否有行存在,而不關(guān)心這些行的具體內(nèi)容”。FROM temp_0
指定了要檢查的表或臨時(shí)表。- 結(jié)合起來(lái),
EXISTS(SELECT 1 FROM temp_0)
就是在檢查temp_0
中是否有任何行存在。
這種方法之所以有效,是因?yàn)?code>EXISTS只關(guān)心是否有數(shù)據(jù)行,而不關(guān)心這些數(shù)據(jù)行的具體值。所以,SELECT 1
在這里是一個(gè)高效且常用的方法,尤其是在只需要檢查行的存在性時(shí)。