maxcompute根据起始时间,生成时间段多行日期数据

具体需求是这样,有一张旅馆住宿表,表内有入住时间、离店时间等字段,现需要根据入住时间与离店时间生成入住期间的房晚数据。

PS:实验环境为maxcompute,hive的同学请自行调整  (杂乱的命名请忽略= =)

住宿测试表(test_get_dates):

数据:

需要生产的房晚数据:

在大佬的鞭策下一共想了三种实现方案:

1)mapjoin日期码表,使用不等值关联生成

2)编写UDTF,传入开始与结束日期生成

3)使用函数 LATERAL VIEW explode生成

具体实现如下:

(一)生成一张日期码表,并使用mapjoin的不等值关联

  1、创建时间码表dim_dates,如图

(id可以省略)

 2、使用mapjoin关联码表生成所需数据

select /*+MAPJOIN(a) */
a.times,
b.rzsj,
b.tfsj,
COALESCE(b.tfsj,b.rzsj) as bftfrq, --关联使用的住房日期
b.sfzhm
from dim_dates a
join test_get_dates b
on  a.times>=TO_DATE(to_char(b.rzsj,'yyyy-mm-dd'),'yyyy-mm-dd') and a.times<= TO_DATE(to_char(b.tfsj,'yyyy-mm-dd'),'yyyy-mm-dd')  

查询结果如下

(二)编写UDTF,返回多行日期数据

1、编写UDTF,代码如下

import com.aliyun.odps.udf.UDTF;
import com.aliyun.odps.udf.annotation.Resolve;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

@Resolve({"datetime,datetime,string,string->datetime,string,string,datetime,datetime"})
public class GetDatesUDTF extends UDTF {
    /**
     * @param args rzrq,tfrq,dwd_zjid,zjhm
     *             args[0] 入住日期
     *             args[1] 退房日期
     *             args[2] dwdid
     *             args[3] 身份证号码
     * @return 房晚日期,dwdid,身份证号码,入住时间,退房时间
     */
    @Override
    public void process(Object[] args) {
        Date bDate = (Date) args[0]; //获取入住时间
        Date eDate = (Date) args[1]; //获取退房时间
        Date bfDate = formateDate(bDate);
        Date efDate = formateDate(bDate!=null&&eDate==null?bDate:eDate);
        String dwdId = (String) args[2];
        String sfzhm = (String) args[3];
        if (bDate != null && efDate != null) {
            int days = getDateDiff(bfDate, efDate);
            try {
                Date d;
                for (int i = 0; i < days; i++) {
                    d = formateDate(getAddDate(bfDate,i));
                    forward(d, dwdId,sfzhm,bDate,eDate);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }

    public Date getAddDate(Date date,int days){
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(formateDate(date));
        calendar.add(Calendar.DAY_OF_MONTH, days);
        return calendar.getTime();
    }

    public Date formateDate(Date date) {
        if (date != null) {
            try {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                String fdateStr = sdf.format(date);
                date = sdf.parse(fdateStr);
                return date;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    public Date getEndDate(Date sdate, Date edate) {
        if (sdate != null && edate == null) {
           return formateDate(sdate);
        }
        return edate;
    }

    public int getDateDiff(Date sdate, Date edate) {
        long days = (edate.getTime() - sdate.getTime()) / (1000 * 60 * 60 * 24);
        return new Long(days).intValue();
    }
}

2、打包上传至maxcompute、创建函数getdates

3、使用UDTF

 (三) 使用函数 LATERAL VIEW explode

select tf.*,t.*, dateadd(start_date,pos,'dd')
from (
select 'a' as a, '2018-11-01 00:00:00' as start_date, '2018-12-01 00:00:00' as end_date from test_get_dates limit 1
) t
lateral view posexplode(split(space(datediff(end_date,start_date,'dd')),' ')) tf as pos,val ;
原文地址:https://www.cnblogs.com/zzzmublog/p/11098710.html