Hive-Sql内实现日期变量

目前的工作需要在公司平台上通过hive导出数据,定时任务的权限没有开放给我,所以只能每天手动导,手动导数时又要天天手工改日期,很麻烦,所以想要where子句能够每天自动有对应的日期。以上是前提,有太多槽点,请忽略。

 

 

首先,要思考的是日期字段的数据类型,以及hive是否也有隐式转换

 

    参考这篇文章                                                           HIVE 数据类型转换

 bltinyintsiintbigintfloatdoubledmstringvctsdateba
booleantruefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalse
tinyintfalsetruetruetruetruetruetruetruetruetruefalsefalsefalse
smallintfalsefalsetruetruetruetruetruetruetruetruefalsefalsefalse
intfalsefalsefalsetruetruetruetruetruetruetruefalsefalsefalse
bigintfalsefalsefalsefalsetruetruetruetruetruetruefalsefalsefalse
floatfalsefalsefalsefalsefalsetruetruetruetruetruefalsefalsefalse
doublefalsefalsefalsefalsefalsefalsetruetruetruetruefalsefalsefalse
decimalfalsefalsefalsefalsefalsefalsefalsetruetruetruefalsefalsefalse
stringfalsefalsefalsefalsefalsefalsetruetruetruetruefalsefalsefalse
varcharfalsefalsefalsefalsefalsefalsetruetruetruetruefalsefalsefalse
tsfalsefalsefalsefalsefalsefalsefalsefalsetruetruetruefalsefalse
datefalsefalsefalsefalsefalsefalsefalsefalsetruetruefalsetruefalse
binaryfalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsefalsetrue

对应表中的日期字段day是以string的类型保存的,类似 '20190618',同时这个字段还是分区字段。。

1、datediff函数的问题

当执行时间为周一时,我希望日期限制的是上周五到周日,其他执行时间则仅昨日。那么加入个if判断以下执行时间是否为周一吧。

用pmod(datediff(current_date, '2012-01-01'), 7)判断,0~6对应周日至周一,没什么问题吧?

然后就出问题了,出来的星期不对。经过排查,锁定以下问题

select datediff(current_date, '2019-06-18')
        , datediff('2019-06-19', '2019-06-18')
        , current_date, current_date = '2019-06-19'

结果如下

012019-06-19true

我百思不得其解,只能百度。

-------------------->                Hive SQL中的datediff、current_date使用问题                                    <---------------------------

[ https://issues.apache.org/jira/browse/HIVE-18304?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16297824#comment-16297824
] 
 
Hengyu Dai commented on HIVE-18304:
-----------------------------------
 
SimpleDateFormat.parse(String source) method will convert String type(UTC) to java.util.Date
type(use current JVM timezone), this may lead deviations in time when JVM timezone is not
UTC, my environment is GMT+8,  8 hours is added comparing to the UTC time.
while for a  date type argument, the default JVM timezone is used. 
The patch uploaded treats String type and Date type at the same way to remove the deviations.
 
> datediff() UDF returns a wrong result when dealing with a (date, string) input
> ------------------------------------------------------------------------------
>
>                 Key: HIVE-18304
>                 URL: https://issues.apache.org/jira/browse/HIVE-18304
>             Project: Hive
>          Issue Type: Bug
>          Components: UDF
>            Reporter: Hengyu Dai
>            Assignee: Hengyu Dai
>            Priority: Minor
>         Attachments: 0001.patch
>
>
> for date type argument, datediff() use DateConverter to convert input to a java Date
object, 
> for example, a '2017-12-18' will get 2017-12-18T00:00:00.000+0800
> for string type argument, datediff() use TextConverter to convert a string to date,
> for '2012-01-01' we will get 2012-01-01T08:00:00.000+0800
> now, datediff() will return a number less than the real date diff
> we should use TextConverter to deal with date input too.
> reproduce:
> {code:java}
> select datediff(cast('2017-12-18' as date), '2012-01-01'); --2177
> select datediff('2017-12-18', '2012-01-01'); --2178
> {code}

大体意思就是对,date类型和string类型的两个参数,hive调用了不同的函数处理,处理出来的带时间的日期数据相减。

而要想解决的话很简单,统一两个参数的数据类型就行了。

select datediff(current_date, cast('2019-06-18' as date))
        , datediff(to_date(current_date), '2019-06-18')

2、使用hiveconf变量

把这么长的式子写在where后面实在太难看,所以我决定使用变量传参的方式

找到了以下文章

hive中的参数

set end_day = '20190618';
select * where day = ${hiveconf:end_day};

另,当某些时候用参数传递给分区字段报错时,加入下面这段

SET hive.exec.dynamic.partition.mode = nonstrict;

3、避免科学计数法

开始时,我使用的是这种方法,

select from_unixtime(unix_timestamp(), 'yyyyMMdd') - 1

结果得到的是 2.0190618E7

用这个作为where分区限制时,报错

Error while compiling statement: FAILED: SemanticException [Error 10041]: No partition predicate found

我猜测又是类型的问题

所以我使用cast显式转换格式成string,但科学计数法表示的数字转换成字符,那画面实在太美。

所以,为了解决这种计算结果改变数据类型的情况,

cast(bigint(from_unixtime(unix_timestamp(), 'yyyyMMdd') - 1 )as string)

我套了一个bigint

好了,没问题了,但是仍然报错。

ps:  string形式形如’20190618‘格式的分区字段,用

cast(bigint(from_unixtime(unix_timestamp(), 'yyyyMMdd') - 1 )as string) 报错

用 cast(bigint('20190619'- 1 )as string) 没事。可能还是数据类型的问题,但我已放弃治疗

 

3、最后的解决方案

 

SET start_day = if(pmod(datediff(to_date(current_date), '2012-01-01'), 7) = 1, regexp_replace(date_sub(current_date, 3), '-', ''), regexp_replace(date_sub(current_date, 1), '-', ''));
SET end_day = regexp_replace(date_sub(current_date, 1), '-', '');

hive的数据类型实在是个坑

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值