
【每周一期-數(shù)據(jù)蔣堂】SQL的有序分組
我們知道,SQL延用了數(shù)學(xué)上的無序集合概念,所以SQL的分組并不關(guān)注過待分組集合中成員的次序。我們在前面討論過的等值分組和非等值分組,也都沒有關(guān)注過這個問題,分組規(guī)則都是建立在成員取值本身上。但如果我們要拓展SQL,以有序集合為考慮對象時,那就必須考慮成員次序?qū)Ψ纸M的影響了,而且,現(xiàn)實業(yè)務(wù)中有大量的有序分組應(yīng)用場景。
一個簡單的例子:將一個班的學(xué)生平均分成三份(假定人數(shù)能被3整除)。按我們在前面所說的分組定義,這也可以看成是一種分組,但這個運(yùn)算在SQL中卻很難寫出來,因為分組依據(jù)和成員取值沒有關(guān)系。
如果使用我們在前面講有序遍歷語法時的#符號,這個問題就很容易解決了。
A.group( (#-1)*3\A.len() ) // 按序號分成前1/3,中1/3,后1/3
A.group( (#-1)%3 ) // 還可以按序號每三個中取一個構(gòu)成分組子集
用SQL實現(xiàn)這個運(yùn)算就麻煩很多,需要先用子查詢造出一個序號,然后再執(zhí)行類似的分組規(guī)則。
上面這個例子中其實還沒有真正關(guān)注成員的次序,只是說明了序號的作用,待分組集合的成員是其它次序時也可以得到可用的結(jié)果。
我們再看更多例子。
處理文本日志時,有些日志的基本單位不是1行,而可能是3行,即每個事件總是寫出3行文本,這并不是多罕見的情況。對付這種日志時,就需要把文本每3行拆成一個分組子集,然后針對每個分組再進(jìn)行詳細(xì)的分析處理。這時要正確的分組運(yùn)算就必須依賴于待分組集合中成員(文本日志的行)的次序了。
入學(xué)考試之后,把學(xué)生按成績排序蛇行分拆成兩個班,即名次1,4,5,8,...在一個,而2,3,6,7,...在另一個班,這樣能保證兩個班的平均名次是相同的。這個分組也可以用序號做出來:
A.sort@z(score).group(#%4<2)
這里用的分組值不再是常見的普通數(shù)值,而是一個布爾量,相當(dāng)于按“真“值和“假”值分成兩個組,真值對應(yīng)第一個班,假值對應(yīng)另一個班。本質(zhì)上講,這還是個等值分組,只是用到的分組值可以是任意泛型。
顯然,這個分組的正確性也嚴(yán)重依賴于待分組集成的成員次序。
順便說一句,這又是一個只關(guān)注分組子集而不關(guān)心聚合值的例子。按序號分組在很多情況下就是用序號來計算出分組依據(jù),然后就變成普通的等值分組了。那么有沒有不能簡單地轉(zhuǎn)換成等值分組的情況呢?
有一組嬰兒出生記錄,是按出生次序排序的,我們現(xiàn)在關(guān)心連續(xù)出生的同性別嬰兒數(shù)量超過5的有多少批?
簡單想,這就是先GROUP,計算每組COUNT值,然后數(shù)出有幾個大于5的。后兩步很簡單,問題是怎么GROUP?
直接按嬰兒性別分組當(dāng)然是不對的,必須考慮次序,依次掃描記錄,當(dāng)嬰兒性別發(fā)生變化時則產(chǎn)生一個新組。這種分組顯然沒法直接用等值分組做出來了。
我們可以提供一個有序分組方法來實現(xiàn)這種分組:當(dāng)考察值發(fā)生變化時就產(chǎn)生一個新的分組。
A.group@o(gender).count(~.len()>5) // @o選項表示分組值變化時將產(chǎn)生新分組。
用SQL就麻煩很多,需要先造成中間標(biāo)志和變量來生成組的序號,大概是這樣
SELECT COUNT(*) FROM
(SELECT ChangeNumber FROM
(SELECT SUM(ChangeFlag) OVER (ORDER BY birthday) ChangeNumber FROM
(SELECT CASE WHEN gender=LAG(gender) OVER ( ORDER BY birthday) THEN 0 ELSE 1 END ChangeFlag FROM A))
GROUP ChangeNumber HAVING COUNT(*)>5)
這樣的SQL,看懂都不是很容易的。而且必須借助birthday這種字段來形成次序,而前述的有序分組寫法在原數(shù)據(jù)有序時根本用不著這個信息。
這種場景同樣可能出現(xiàn)在文本分析中。每個用戶的事件日志可能多行,而且行數(shù)不確定,但寫日志時會在每個行開始處寫上用戶號。這樣我們可以按這個用戶號進(jìn)行有序分組,它變化時就說明是另一個用戶的事件了。
即使是普通的等值分組,如果事先知道原集合對分組字段有序,也可以使用這種方案來實施,這將獲得更高的性能,比數(shù)據(jù)庫常用的HASH分組方案要快得多,而且特別適合大數(shù)據(jù)遍歷的情況。
再看一個著名的問題:一支股票最長連續(xù)上漲了多少天?
這個問題當(dāng)然可以直接遍歷去解決,不過我們現(xiàn)在用分組的思路來處理,至少在SQL體系下只能這么做(嚴(yán)格些說,這是目前找到的最簡單可行的辦法)。
將股票收盤價按日期排序,然后將連續(xù)上漲的日期分到同一組,這樣只要考慮哪一組成員數(shù)最多即可。更明確地說,就是當(dāng)某天上漲了,就把這一天和前一天分到一個組中,某天下跌了,則產(chǎn)生一個新組。
用SQL實現(xiàn)這個思路,同樣需要用中間標(biāo)志和變量來生成組序號:
SELECT MAX(ContinuousDays) FROM
(SELECT COUNT(*) ContinuousDays FROM
(SELECT SUM(RisingFlag) OVER (ORDER BY TradingDate ) NoRisingDays FROM
(SELECT TradingDate,
CASE WHEN ClosingPrice>LAG(ClosingPrice) OVER (ORDER BY TradingDate THEN 0 ELSE 1 END) RisingFlag
FROM A))
GROUP BY NoRisingDays)
如果有專門的有序分組方法以及以前說過的有序遍歷語法,這個運(yùn)算就很簡單了:
A.sort(TradingDate).group@i(ClosingPrice
與SQL不同,雖然實現(xiàn)思路完全一樣,但寫出來是分步的,而不是一個多層嵌套語句,書寫和理解都要容易得多。
同樣地,這種場景也會在文本分析中有用。不確定行數(shù)的日志中,有時會在事件分始時寫一個標(biāo)志串,當(dāng)掃描到這個標(biāo)志串的時候就產(chǎn)生一個新的分組,有序分析的條件可設(shè)定為當(dāng)前掃描行和指定文字相同,這樣就能保證同一事件的日志信息在同一個組中。
后兩種有序分組的情況,理論上當(dāng)然也可以轉(zhuǎn)換成等值分組來處理(用SQL就要這么做,這也能從另一個側(cè)面說明SQL運(yùn)算體系的完備性),但確實是相當(dāng)麻煩的,所以我們一般不把它再當(dāng)成等值分組來處理了。
到目前為止的分組討論,都是假定待分組集合已經(jīng)準(zhǔn)備好,其成員可以被隨機(jī)訪問到。但如果數(shù)據(jù)量巨大而不能全部讀入時,如果繼續(xù)做這種假定,會導(dǎo)致頻繁的外存交換而性能極差,這時需要再設(shè)計以流方式邊讀入邊分組并且邊聚合的運(yùn)算體系。事實上日志分析中更常見的是這種情況,這些問題我們將再撰文研究,但基本方法思路仍然離不開上面這些內(nèi)容。
數(shù)據(jù)分析咨詢請掃描二維碼
若不方便掃碼,搜微信號:CDAshujufenxi
SQL Server 中 CONVERT 函數(shù)的日期轉(zhuǎn)換:從基礎(chǔ)用法到實戰(zhàn)優(yōu)化 在 SQL Server 的數(shù)據(jù)處理中,日期格式轉(zhuǎn)換是高頻需求 —— 無論 ...
2025-09-18MySQL 大表拆分與關(guān)聯(lián)查詢效率:打破 “拆分必慢” 的認(rèn)知誤區(qū) 在 MySQL 數(shù)據(jù)庫管理中,“大表” 始終是性能優(yōu)化繞不開的話題。 ...
2025-09-18CDA 數(shù)據(jù)分析師:表結(jié)構(gòu)數(shù)據(jù) “獲取 - 加工 - 使用” 全流程的賦能者 表結(jié)構(gòu)數(shù)據(jù)(如數(shù)據(jù)庫表、Excel 表、CSV 文件)是企業(yè)數(shù)字 ...
2025-09-18DSGE 模型中的 Et:理性預(yù)期算子的內(nèi)涵、作用與應(yīng)用解析 動態(tài)隨機(jī)一般均衡(Dynamic Stochastic General Equilibrium, DSGE)模 ...
2025-09-17Python 提取 TIF 中地名的完整指南 一、先明確:TIF 中的地名有哪兩種存在形式? 在開始提取前,需先判斷 TIF 文件的類型 —— ...
2025-09-17CDA 數(shù)據(jù)分析師:解鎖表結(jié)構(gòu)數(shù)據(jù)特征價值的專業(yè)核心 表結(jié)構(gòu)數(shù)據(jù)(以 “行 - 列” 規(guī)范存儲的結(jié)構(gòu)化數(shù)據(jù),如數(shù)據(jù)庫表、Excel 表、 ...
2025-09-17Excel 導(dǎo)入數(shù)據(jù)含缺失值?詳解 dropna 函數(shù)的功能與實戰(zhàn)應(yīng)用 在用 Python(如 pandas 庫)處理 Excel 數(shù)據(jù)時,“缺失值” 是高頻 ...
2025-09-16深入解析卡方檢驗與 t 檢驗:差異、適用場景與實踐應(yīng)用 在數(shù)據(jù)分析與統(tǒng)計學(xué)領(lǐng)域,假設(shè)檢驗是驗證研究假設(shè)、判斷數(shù)據(jù)差異是否 “ ...
2025-09-16CDA 數(shù)據(jù)分析師:掌控表格結(jié)構(gòu)數(shù)據(jù)全功能周期的專業(yè)操盤手 表格結(jié)構(gòu)數(shù)據(jù)(以 “行 - 列” 存儲的結(jié)構(gòu)化數(shù)據(jù),如 Excel 表、數(shù)據(jù) ...
2025-09-16MySQL 執(zhí)行計劃中 rows 數(shù)量的準(zhǔn)確性解析:原理、影響因素與優(yōu)化 在 MySQL SQL 調(diào)優(yōu)中,EXPLAIN執(zhí)行計劃是核心工具,而其中的row ...
2025-09-15解析 Python 中 Response 對象的 text 與 content:區(qū)別、場景與實踐指南 在 Python 進(jìn)行 HTTP 網(wǎng)絡(luò)請求開發(fā)時(如使用requests ...
2025-09-15CDA 數(shù)據(jù)分析師:激活表格結(jié)構(gòu)數(shù)據(jù)價值的核心操盤手 表格結(jié)構(gòu)數(shù)據(jù)(如 Excel 表格、數(shù)據(jù)庫表)是企業(yè)最基礎(chǔ)、最核心的數(shù)據(jù)形態(tài) ...
2025-09-15Python HTTP 請求工具對比:urllib.request 與 requests 的核心差異與選擇指南 在 Python 處理 HTTP 請求(如接口調(diào)用、數(shù)據(jù)爬取 ...
2025-09-12解決 pd.read_csv 讀取長浮點(diǎn)數(shù)據(jù)的科學(xué)計數(shù)法問題 為幫助 Python 數(shù)據(jù)從業(yè)者解決pd.read_csv讀取長浮點(diǎn)數(shù)據(jù)時的科學(xué)計數(shù)法問題 ...
2025-09-12CDA 數(shù)據(jù)分析師:業(yè)務(wù)數(shù)據(jù)分析步驟的落地者與價值優(yōu)化者 業(yè)務(wù)數(shù)據(jù)分析是企業(yè)解決日常運(yùn)營問題、提升執(zhí)行效率的核心手段,其價值 ...
2025-09-12用 SQL 驗證業(yè)務(wù)邏輯:從規(guī)則拆解到數(shù)據(jù)把關(guān)的實戰(zhàn)指南 在業(yè)務(wù)系統(tǒng)落地過程中,“業(yè)務(wù)邏輯” 是連接 “需求設(shè)計” 與 “用戶體驗 ...
2025-09-11塔吉特百貨孕婦營銷案例:數(shù)據(jù)驅(qū)動下的精準(zhǔn)零售革命與啟示 在零售行業(yè) “流量紅利見頂” 的當(dāng)下,精準(zhǔn)營銷成為企業(yè)突圍的核心方 ...
2025-09-11CDA 數(shù)據(jù)分析師與戰(zhàn)略 / 業(yè)務(wù)數(shù)據(jù)分析:概念辨析與協(xié)同價值 在數(shù)據(jù)驅(qū)動決策的體系中,“戰(zhàn)略數(shù)據(jù)分析”“業(yè)務(wù)數(shù)據(jù)分析” 是企業(yè) ...
2025-09-11Excel 數(shù)據(jù)聚類分析:從操作實踐到業(yè)務(wù)價值挖掘 在數(shù)據(jù)分析場景中,聚類分析作為 “無監(jiān)督分組” 的核心工具,能從雜亂數(shù)據(jù)中挖 ...
2025-09-10統(tǒng)計模型的核心目的:從數(shù)據(jù)解讀到?jīng)Q策支撐的價值導(dǎo)向 統(tǒng)計模型作為數(shù)據(jù)分析的核心工具,并非簡單的 “公式堆砌”,而是圍繞特定 ...
2025-09-10