1. 程式人生 > >【轉】關於hive當中獲取時間的操作--取上月日期

【轉】關於hive當中獲取時間的操作--取上月日期

今天突然在網上看到別人的面試題,覺得有點好奇想做一下,突然發現sql server的語法對於hive是不適用的。於是各種查資料。

然後發現hive中沒有直接獲取到當前時間的函式,而且對於時間定義的函式特別少,問題解決起來還是有難度。

下面介紹hive獲取時間的方式:

題目:給定一張表(列有月份,銷售額),要求查詢出月份、本月銷售額、上月銷售額這三個結果,如果當月上個月的銷售額不存在就顯示為“*”。

看到這個我第一個想到的就是根據時間來進行分組然後累加求和,然後對分組累加的資料按照月份進行排序,取出前兩條資料,然後結束。

看起來思路是對的,可是實際推敲有很多的問題。

(1)比如給定的時間是帶日期的並不是按照月份來分的。比如 2018-08-12 像這種的額麼分組。還是要將日期進行擷取,然後分組累加才行。

(2)題目是獲取到當前月份和上個月的資料。萬一表中沒有存當前的月份,上個月的也沒有存怎麼辦。獲取的資料不就不準確了。

針對上面的問題我們肯定要對日期進行擷取,然後分組累加,這是毋庸置疑的。另外就是要限定死當前月份和上個月的額月份。然後用限定死的月份去和表中的資料進行join操作

然後問題來了:在寫hql的時候發現各種問題,hive獲取時間的操作都很少。

SELECT FROM_UNIXTIME(UNIX_TIMESTAMP());
  hive是通過獲取到時間戳的形式來獲取到時間,然後通過函式FROM_UNIXTIME 轉化為日期時間的形式。
OK 2018-08-12 19:02:58
然後通過substr()函式獲取到當前的月份;
SELECT SUBSTR(FROM_UNIXTIME(UNIX_TIMESTAMP()),1,7) AS mo;
   OK
  2018-08

這下問題來了。獲取到了當期的日期怎麼獲取到上個月的時間那。嘗試用下面的函式進行獲取;

SELECT SUBSTR(DATE_SUB(FROM_UNIXTIME(UNIX_TIMESTAMP()),30),1,7) AS mo  

通過DATE_SUB()函式對獲取的時間戳進行操作,對日期進行相減,突然發現要得到上個月的時間,我們的月份的時間都不確定,這裡用30天,肯定不行。

有開始發現新的方法:

SELECT SUBSTR(DATE_SUB(FROM_UNIXTIME(UNIX_TIMESTAMP()),DAYOFMONTH(FROM_UNIXTIME(UNIX_TIMESTAMP()))),1,7) AS mo

還是使用的DATE_SUB對日期進行操作,這次是將後面那個引數設定為獲取到當前的日期,相減就是上個月最後一天,也是代表上個月。

於是問題得到了解決;

下面是改造完成的sql:   

WITH  mon AS (

     SELECT SUBSTR(FROM_UNIXTIME(UNIX_TIMESTAMP()),1,7) AS mo
     UNION ALL
     SELECT SUBSTR(DATE_SUB(FROM_UNIXTIME(UNIX_TIMESTAMP()),DAYOFMONTH(FROM_UNIXTIME(UNIX_TIMESTAMP()))),1,7) AS mo

)  --這裡採用了with as的形式對經常操作的資料進行儲存,起到的相當於中間表的作用。

SELECT 
    mo AS mth, 
    CASE WHEN SUM(nvl(AMOUNT,0))=0 THEN '*'
    ELSE 
    CAST(SUM(nvl(AMOUNT,0) AS VARCHAR(10))) END AS SUM_AMOUN
    FROM 
    mon 
    LEFT JOIN tb2 ON mo=SUBSTR(SALEDATE,1,7)
    GROUP BY mo;

對臨用左連線的方式去連線主表,然後進行查詢

對於Hive 的函式。有時候真的很麻煩。有時候還需要自定義函式進行操作。