使用Hive SQL創建日期維度表


使用Hive SQL創建日期維度表

一、需求

​ 需要在Hive數倉中創建一張時間跨度為2010年-2025年的時間維度表,字段如下:

類型 Comment 計算邏輯(用於需求溝通)
date string 標准日期格式 2020-01-01
date_ds string ds日期格式 20200101
year string 年份 2020
month string 月份 01
day string 日期 01
day_of_week bigint 星期幾【1-7】
week_of_year bigint 本年度第幾周 1. 以本年度第一個周一開始計算 2. 本年度前幾日如屬於上一年度的最后一周,則與上一年度最后一周的序號相同
week_of_month bigint 本月第幾周 與weekOfYear類似

二、代碼

SELECT
    `date`,
    date_ds,
    year,
    month,
    day,
    day_of_week,
    weekofyear(`date`) as week_of_year, 
    --from_unixtime(unix_timestamp(`date`, "yyyy-MM-dd"), "W") as week_of_month  
    CAST((day(theMonday) - 1) / 7 + 1 AS BIGINT) as week_of_month
FROM (
  SELECT
    `date`,
    regexp_replace(`date`, '-', '') as date_ds,
    year(`date`) as year,
    month(`date`) as month,
    day(`date`) as day,
    -- 請參看代碼拆析 2   date_sub(next_day(`date`, 'Mon'), 7) as theMonday,
    if(datediff(next_day(`date`, 1), `date`) == 7, date_sub(`date`, 6), date_sub(next_day(`date`, 2), 7)) as theMonday,
    -- 版本支持date_format,可以使用: date_format(`date`, 'u') as day_of_week 
    from_unixtime(unix_timestamp(`date`, "yyyy-MM-dd"), "u") as day_of_week 
  FROM (
    SELECT date_add(`start_date`,pos) AS `date`
    from (
      SELECT `start_date` 
      FROM table_contains_startDate
    ) t 
    lateral view posexplode(split(repeat(", ", 9495), ",")) tf AS pos,val --  9495為時間跨度
  ) dates
) dates_expanded
SORT BY `date`
;
-- 需要一張包含起始日期的table_contains_startDate表

代碼拆析

-- dates:獲取從start_date到往后n天的date字段數據
SELECT date_add(`start_date`,pos) AS `date`
from (
    SELECT `start_date` 
    FROM table_contains_startDate
) t 
lateral view posexplode(split(repeat(", ", 9495), ",")) tf AS pos,val --9495為時間跨度

​ 由於筆者所使用的Hive版本子句中不允許沒有FROM語句: FAILED: Error in semantic analysis: ERROR-0-HIVE:00003:{semantic error => sub query must have a from clause!!}},所以創建了一張只包含起始日期的表table_contains_startDate,如果版本允許可以直接改為:

-- dates:獲取從start_date到往后n天的date字段數據
SELECT date_add(`start_date`,pos) AS `date`
from (
    SELECT '2010-01-01'
) t 
lateral view posexplode(split(repeat(", ", 9495), ",")) tf AS pos,val --9495為時間跨度
-- dates_expanded:
if(datediff(next_day(`date`, 1), `date`) == 7, date_sub(`date`, 6), date_sub(next_day(`date`, 2), 7)) as theMonday,
-- 標准Hive函數  date_sub(next_day(`date`, 'Mon'), 7) as theMonday,

--
CAST((day(theMonday) - 1) / 7 + 1 AS BIGINT) as week_of_month

​ 由於week_of_month 字段邏輯與SimpleDateFormat提供的W參數邏輯不同,所以需要另謀他法。總體的思路是:取date所在周的周一 theMonday,使用theMonday的 后兩位 減一的差 對7取商 再加一 即可(說起來很拗口,看代碼即可。該思路由 力丞 大佬特別贊助!)。

​ 筆者公司next_day()函數並非標准的Hive函數且有bug,使用標准Hive函數庫的同學使用注釋中的語句即可。

三、結果預覽

​ SQL結果插入維度表得到結果如下:

參考資料:

  1. Create calendar dimension table in hive query language (HQL)
  2. HIVE posexplode 時間區間拆分成單獨行
  3. Class SimpleDateFormat 參數含義


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM