大數據開發-Sql-涉及迭代數據的sql問題處理思路

在前面一篇裏面,算法-一個經典sql 題和一個Java算法題 大數據開發-Hive-常用日期函數&&日期連續題sql套路有一道經典sql題目,解決連續問題,本文繼續總結關於連續性的套路,來自於實際生產項目的問題,本文略去其他不重要信息字段,來從更深地層次解決問題,由於在生產中,常常是理解需求,轉換需求,讓需求拆解爲更通用的處理方式,同時從解決難題中提高自己,解決這些問題,也是快樂的源泉之一😀。

1.生產問題原始描述

關於給用戶打標籤的問題,對於標籤的數據源在實際環境下幾乎是覆蓋全部門甚至全公司的,有的數據源本身是明細方式,有的是原始ods日誌方式,有的是維度表,有的是名單表,對於需求方來說要的是快速迭代上線標籤,看需求或者數據倉庫劃分或者處理麻煩程度,往往會採用不同的處理方式,另外對於標籤的應用方來說一定會有人查值,值查人,資產分析等,本文的例子就一個名單表,什麼是名單表呢,就是圈客的結果,比如滿足某條件某條件的一堆id,標籤天然就是爲滿足圈客用的,但是原始數據它是圈客的結果,所以同時爲了使得標籤在業務方使用起來更方便,所以把名單表加工成標籤,那麼需求就確定了,從名單表裏面加工出標籤。

原始表如下

# id  dt
1   10
2   10
2   11
3    11

解釋,爲了說明更簡單,假設日期類型都用數字來表示,每天會有一羣去重id,下一天的id更這一天的id必然是兩個交叉圓的形式,即既有多出來的,又有少出來的,又有重疊的。

現在需求就是,

我要篩選任意時間段的用戶,滿足是這段時間首次有效,或者無效,或者存量有效,分別對應描述裏面的多出來,少了重合的每天

至於有效的定義就是,前一天名單沒有這個id,下一天有這個id,這就是首次有效,但是對於名單這種數據來說,一定會有有效,無效,有效,無效,這種,所以標籤的每天分片裏面會有昨天的id加今天的id.

2.生產問題分析拆解

針對上面分析到的問題,有效無效這種狀態不能是最近一次,或者首次的有效,因爲會有區段的概念,比如某歷史一段時間,只要首次出現在這段時間的,而且多天重合的。所以針對這個問題,我這邊處理成每天相對於前一天的有效狀態,分別爲0,1,2,也即對應無效,首次有效,存量有效,另外對應每一段的信息。

所以這樣問題就化解爲,先求有效狀態,然後再在有效狀態的基礎上,加工出最早時間和最晚時間,爲了篩選方便,我另外加工出兩個冗餘子屬性字段,是否首次有效和是否當前有效,對於有效無效,如果用窗口函數,找到同一個id的前一個日期,如果是日期的前一天,即表示2,存量有效,如果不爲前一天則爲增量有效,但是這種方式沒法把無效的取出來,所以我後面想到的是用full join來實現,這樣即可以把前一天後一天的數據都拿到。

3.問題解決

-- 對於有效無效的加工
with t3 as (
select id,dt,CASE
                  WHEN a.did IS NOT NULL
                          AND b.did IS NULL THEN 1
                       WHEN a.did IS NULL
                           AND b.did IS NOT NULL THEN 0
                     WHEN a.did IS NOT NULL
                           AND b.did IS NOT NULL THEN 2
                           end as is_valid
 from t1 a full join b on a.id = b.id
 )

-- 最早時間12,最晚時間14,是否首次有效,是否當前有效
select id,min(dt) as min_dt,max(dt) as max_dt, gid from (
select id,dt,is_valid, (dt - row_number() over (partition by id order by dt)) gid from t3 where is_valid != 0
) tmp group by id,gid

4.總結套路

4.1.首先思考可以用到的日期函數

datediff, date_sub/date_add

4.2.連續日期

連續問題都會用到一個排名函數,但是排名函數的值是數值,要與日期的連續性做到映射,才方便分組,比如可以把日期映射到連續數字,或者數字映射到連續日期,實現這兩個的操作就是通過前面的datedff 和 date_sub組合,原理就是日期與日期相減即可得到連續整數,整數隨便與某個日期做相減即可得到連續的日期,其中date_sub可以是反向排序得到連續日期。

4.3.通過連續的排序日期或者排序id相減,然後分組gid

即可解決此類問題

求連續狀態時間的開始和結束時間

4.4 對於特殊問題,比如想知道前後分區的數據

現有方式,一種是lag和lead窗口函數,另外一種是自表關聯,效率應該窗口函數高一點,基於本題,由於名單表的特殊原因,如果再給全量id打標籤,這樣結果分區的數據和原分區的數據不同,是加上了前一天失效的用戶,所以用的自表fulljoin關聯。

file
吳邪,小三爺,混跡於後臺,大數據,人工智能領域的小菜鳥。
更多請關注
file

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章