【问题标题】:Hive SQL query to fill missing date values in table with nearest values between date rangeHive SQL 查询以使用日期范围之间最接近的值填充表中缺失的日期值
【发布时间】:2021-10-11 06:12:40
【问题描述】:

对于下面的示例,如果我在下面使用相同的数据,并且如果我希望 Mary 和 Peter 帐户都在同一日期范围内,我将如何修改 hive sql 查询来执行此操作?例如,将日期范围设置在“2021-05-24”和“2021-06-03”之间,并填充此期间的所有余额。如果我们以 Mary 为例,我还希望看到 Mary 可用余额 '53028.1' 向前填充到 '2021-06-03' 并且如果 Mary 在 '2021-05-24 上没有值' 将余额填满 '50000'。

with mytable as (--Demo dataset, use your table instead of this
select stack(10, --number of tuples
'Peter',float(50000),'2021-05-24',
'Peter',float(50035),'2021-05-25',
'Peter',float(50035),'2021-05-26',
'Peter',float(50610),'2021-05-28',
'Peter',float(51710),'2021-06-01',
'Peter',float(53028.1),'2021-06-02',
'Peter',float(53916.1),'2021-06-03',
'Mary',float(50000),'2021-05-24',
'Mary',float(50035),'2021-05-25',
'Mary',float(53028.1),'2021-05-30'
) as (account_name,available_balance,Date_of_balance)
) --use your table instead of this CTE

select  account_name, available_balance, date_add(Date_of_balance,e.i) as Date_of_balance
from
( --Get next_date to generate date range
select account_name,available_balance,Date_of_balance,
       lead(Date_of_balance,1, Date_of_balance) over (partition by account_name order by Date_of_balance) next_date    
  from mytable d  --use your table
) s lateral view outer posexplode(split(space(datediff(next_date,Date_of_balance)-1),'')) e as i,x --generate rows
order by account_name desc, Date_of_balance --this is to have order of rows like in your Converted Table

结果:

account_name    available_balance   date_of_balance 
Peter           50000                2021-05-24
Peter           50035                2021-05-25
Peter           50035                2021-05-26
Peter           50035                2021-05-27
Peter           50610                2021-05-28
Peter           50610                2021-05-29
Peter           50610                2021-05-30
Peter           50610                2021-05-31
Peter           51710                2021-06-01
Peter           53028.1              2021-06-02
Peter           53916.1              2021-06-03
Mary            50000                2021-05-24
Mary            50035                2021-05-25
Mary            50035                2021-05-26
Mary            50035                2021-05-27
Mary            50035                2021-05-28
Mary            50035                2021-05-29
Mary            53028.1              2021-05-30

注意,这个左连接帮助我在附加的链接here 中走到了这一步


@左加入

我有一个非常大的表,我需要每天过去 90 天的余额。账户数超过100万账户,余额表庞大,余额记录仅在账户余额发生变化时更新。某些帐户可能一年多没有更新余额日期记录,因此 -left join 提出的以下代码将无法正常工作。

我有两张桌子:

**Accounts lookup table:** 

account_name, observation_date
'Peter','2021-05-24'
'Luis','2021-03-21'

资产负债表

account_name,account_balance,balance_date
'Peter',50000,'2020-03-20'
'Peter',50035,'2021-04-27'
'Peter',43821,'2021-05-21'
'Peter',50610,'2021-05-22'
'Mary',51710,'2019-03-20'
'Mary',53028.1,'2021-04-27'
'Mary',53916.1,'2021-05-21'
'Mary',54632.76,'2021-05-22'
'Roger',55147.76,'2021-03-03'
'Roger',55293.96,'2021-02-03'
'Roger',57142.15,'2021-03-04'
'Roger',67834.15,'2021-04-01'

我正在寻找的 HIVE SQL 查询将能够连接这两个表并提供类似于下面的结果

account_name,account_balance,balance_date
Peter,50000,2020-03-20
Peter,50000,2021-02-24
Peter,50000,2021-02-25
Peter,…,…
Peter,50035,2021-04-27
Peter,50035,2021-04-28
Peter,50035,2021-04-29
Peter,…,…
Peter,43821,2021-05-21
Peter,50610,2021-05-22
Peter,43821,2021-05-23
Peter,43821,2021-05-24
Roger,55147.76,05/01/2021
Roger,55147.76,06/01/2021
Roger,55147.76,07/01/2021
Roger,…,…
Roger,55293.96,2021-02-03
Roger,57142.15,2021-02-04
Roger,57142.15,2021-02-05
Roger,…,…
Roger,67834.15,2021-04-01
Roger,67834.15,2021-04-02
Roger,67834.15,2021-04-03
Roger,67834.15,2021-04-04
Roger,67834.15,2021-04-05

我知道我们可能会从一开始就获取所有余额,然后执行领先功能,但是对于大规模环境,当每天查询数百万时,这将无法正常工作。

【问题讨论】:

    标签: sql date hive hiveql date-range


    【解决方案1】:

    另外计算整个数据集的最小和最大日期以确定所需的日期范围,还计算每个帐户的最小日期以检查最小日期是否需要修复。然后为两个日期添加额外的计算步骤:检查它是否是边界日期,如果它们不是必需的,则相应地分配最小值和最大值。

    在此示例中,Peter 的开始日期是 2021-05-24,而 Mary 的开始日期是 2021-05-23,因此,范围已扩展,并为 Peter 生成了 2021-05-23 记录。 Mary 的最后日期是 2021-05-30,缺少在范围末尾生成的行。

    with mytable as (--Demo dataset, use your table instead of this
    select stack(10, --number of tuples
    'Peter',float(50000),'2021-05-24',
    'Peter',float(50035),'2021-05-25',
    'Peter',float(50035),'2021-05-26',
    'Peter',float(50610),'2021-05-28',
    'Peter',float(51710),'2021-06-01',
    'Peter',float(53028.1),'2021-06-02',
    'Peter',float(53916.1),'2021-06-03', -------------end date greater than Mary
    'Mary',float(50000),'2021-05-23', ----------------start date Less than Peter
    'Mary',float(50035),'2021-05-25',
    'Mary',float(53028.1),'2021-05-30'
    ) as (account_name,available_balance,Date_of_balance)
    ) --use your table instead of this CTE
    
    select  account_name, available_balance, date_add(Date_of_balance,e.i) as Date_of_balance
    from
    (select account_name, available_balance, 
            case when min_date < min_date_account and Date_of_balance = min_date_account then min_date 
                 else Date_of_balance 
             end Date_of_balance,
            
            case when (next_date is null) and (Date_of_balance = max_date) then Date_of_balance 
                 when (Date_of_balance < max_date) then nvl(next_date,date_add(max_date,1)) 
             end as next_date
    from
    ( --Get next_date to generate date range
    select account_name,available_balance,Date_of_balance,
           lead(Date_of_balance,1) over (partition by account_name order by Date_of_balance) next_date,
           max(Date_of_balance) over() max_date, --total min and max dates all accounts should align
           min(Date_of_balance) over() min_date, 
           min(Date_of_balance) over(partition by account_name) min_date_account
      from mytable d  --use your table
    ) s 
    ) s lateral view outer posexplode(split(space(datediff(next_date,Date_of_balance)-1),'')) e as i,x --generate rows
    order by account_name desc, Date_of_balance --this is to have order of rows like in your Converted Table
    

    结果:

    account_name    available_balance   date_of_balance
    Peter             50000              2021-05-23
    Peter             50000              2021-05-24
    Peter             50035              2021-05-25
    Peter             50035              2021-05-26
    Peter             50035              2021-05-27
    Peter             50610              2021-05-28
    Peter             50610              2021-05-29
    Peter             50610              2021-05-30
    Peter             50610              2021-05-31
    Peter             51710              2021-06-01
    Peter             53028.1            2021-06-02
    Peter             53916.1            2021-06-03
    Mary              50000              2021-05-23
    Mary              50000              2021-05-24
    Mary              50035              2021-05-25
    Mary              50035              2021-05-26
    Mary              50035              2021-05-27
    Mary              50035              2021-05-28
    Mary              50035              2021-05-29
    Mary              53028.1            2021-05-30
    Mary              53028.1            2021-05-31
    Mary              53028.1            2021-06-01
    Mary              53028.1            2021-06-02
    Mary              53028.1            2021-06-03
    

    注意lead函数的计算方式也不同,它没有默认值,NULL表示可用的结束日期

    【讨论】:

    • 您好 Leftjoin,首先感谢您再次及时详细的回复。但是,我的情况是数据集中不会有这个数据点:'Mary',float(50000),'2021-05-23'。而且我要求在没有任何数据的情况下将数据回填到“2021-05-23”。我尝试从您提供的数据中删除该数据点,但出现错误。您能否提供有关如何为此优化查询的指导?
    • @AnthonyCape 对不起,我不明白。这是什么意思:“我要求将数据回填到'2021-05-23',而之前没有任何数据”?如果您只想将第一个日期设置为参数,请输入 '2021-05-22' min_date,而不是 min(Date_of_balance) over() min_date,然后将从该日期开始对 Mary 和 Peter 进行相同的查询。您也可以将参数放入其中
    • 我更新了帖子以进一步解释我的查询。如果我现在已经澄清了问题,请告诉我?
    • @AnthonyCape 如果你有这样的表要加入,你可以加入而不是计算 min(date)。请避免完全改变问题,因为这浪费了我们的时间。
    • 好的,谢谢,我会试一试的。不是我改变了问题,只是问题正在根据资源有所改变。但是你帮了很大的忙,谢谢,我现在就关闭这个谢谢
    猜你喜欢
    • 2021-10-09
    • 2023-03-25
    • 2014-12-06
    • 1970-01-01
    • 1970-01-01
    • 2019-07-20
    • 1970-01-01
    • 2021-08-15
    • 2016-12-16
    相关资源
    最近更新 更多