HiveSQL, un pequeño truco al día: cómo calcular con precisión el valor acumulado de fechas no consecutivas [Preguntas de la entrevista de Lightning Express]

0 necesidades

Problema de suma acumulativa de campo disperso

1 Análisis de problemas

De acuerdo con la forma de transformación de datos en la imagen, se puede ver que las fechas que faltan en los datos se completan de acuerdo con el campo término.término es el número de fechas consecutivas.Cuando es 12, significa que es continuo desde 2018-12-21 a 2019-01-02 El número de fechas es 12. Cuando se completa la fecha, el valor acumulado de la cantidad se calcula de acuerdo con el orden de la fecha. Tenga en cuenta que cuando se completa la fecha, el valor de la fecha completada está vacía. Este tipo de problemas a menudo ocurren en los negocios, especialmente cuando se calculan los valores acumulados.Si las fechas no son consecutivas, es fácil pasar por alto los valores acumulativos de algunas fechas, lo que da como resultado datos incompletos. El punto central de este tipo de problema es que las fechas de los datos no son continuas y las fechas continuas deben completarse, entonces, ¿cómo completar las fechas continuas? Los estudiantes que hayan leído mi columna de preguntas SQLBOY1000 deben saber que hay preguntas similares, y aquí hay un enlace.

Análisis de problemas de intervalos de intersección superpuestos de SQL: pregunta 30 de la entrevista de HiveSQL

Un pequeño truco para HiveSql al día: cómo construir fechas continuas_hive genera fechas continuas_Mo Ming Pomegranate Sister's Blog-CSDN Blog

Paso 1: Complete las fechas consecutivas requeridas de acuerdo con la fecha de los datos

Para completar fechas consecutivas, proporcionamos plantillas y extractos básicos

lateral view posexplode(split(space(term), '(?!$)')) temp as pos,val

Entre ellos, la función space() significa tomar espacios, el propósito es expandir el uso de datos, cuántos espacios tomar está determinado por los parámetros internos, la regularidad (?!$) en split() significa hacer coincidir si no termina con un espacio, porque la función split() se cortará. Necesitamos eliminar un espacio más.

Utilice la función posexplode() para generar un índice y todas las fechas se pueden completar de acuerdo con la fecha de inicio (min(value_date)) + paso de crecimiento en los datos. Tenga en cuenta que hay un aumento mensual, usamos la función add_months, es decir

add_months(value_date, pos)

La generación general de declaraciones de fecha continua es la siguiente:

with data as
(
 select 'AAAA' as contract,'2018-12-21' as value_date,9439.30 as amount,12 as term
 union all
 select 'AAAA' as contract,'2019-03-21' as value_date,9439.30 as amount,12 as term
 union all
 select 'AAAA' as contract,'2019-06-21' as value_date,9439.30 as amount,12 as term
 union all
 select 'AAAA' as contract,'2019-09-21' as value_date,9439.30 as amount,12 as term
 union all
 select 'BBBB' as contract,'2018-12-02' as value_date,9439.30 as amount,10 as term
 union all
 select 'BBBB' as contract,'2019-02-02' as value_date,9439.30 as amount,10 as term
 union all
 select 'BBBB' as contract,'2019-06-02' as value_date,9439.30 as amount,10 as term
 union all
 select 'BBBB' as contract,'2019-09-02' as value_date,9439.30 as amount,10 as term
)
select contract
          , add_months(value_date, pos) value_date
          ,term
     from (
              select contract
                   , min(value_date) value_date
                   , max(amount)     amount
                   , max(term)       term
              from data
              group by contract
          ) t1 lateral view posexplode(split(space(term), '(?!$)')) temp as pos,val
 

Paso 2: Utilice las fechas consecutivas completadas como tabla principal para asociar la tabla de datos y calcular el valor acumulativo.

Nota: Es necesario utilizar la fecha continua generada como tabla principal y la tabla de datos asociada , para que el cálculo acumulativo se pueda hacer sin repetición.

El valor de sum en sum() over (partition by order by) debe ser el valor de la tabla derecha de la tabla de datos, y los valores de partición by y order by son los valores de la tabla principal.

在准确计算非连续日期累计值的核心点也在于此,生成补齐的日期维度表一定是主表,然后去关联数据表。

最终具体SQL如下:

with data as
(
 select 'AAAA' as contract,'2018-12-21' as value_date,9439.30 as amount,12 as term
 union all
 select 'AAAA' as contract,'2019-03-21' as value_date,9439.30 as amount,12 as term
 union all
 select 'AAAA' as contract,'2019-06-21' as value_date,9439.30 as amount,12 as term
 union all
 select 'AAAA' as contract,'2019-09-21' as value_date,9439.30 as amount,12 as term
 union all
 select 'BBBB' as contract,'2018-12-02' as value_date,9439.30 as amount,10 as term
 union all
 select 'BBBB' as contract,'2019-02-02' as value_date,9439.30 as amount,10 as term
 union all
 select 'BBBB' as contract,'2019-06-02' as value_date,9439.30 as amount,10 as term
 union all
 select 'BBBB' as contract,'2019-09-02' as value_date,9439.30 as amount,10 as term
)

select  dim.contract
       ,dim.value_date
       ,cast(sum(d.amount) over(partition by dim.contract order by dim.value_date)  as decimal(18,2)) amount
       ,dim.term
from
    (select contract
          , add_months(value_date, pos) value_date
          ,term
     from (
              select contract
                   , min(value_date) value_date
                   , max(amount)     amount
                   , max(term)       term
              from data
              group by contract
          ) t1 lateral view posexplode(split(space(term), '(?!$)')) temp as pos,val
    ) dim
left join
(
  select contract
        ,value_date
        ,amount
  from data
) d
on dim.contract = d.contract and dim.value_date = d.value_date

结果如下:

问题补充:如何将缺失日期及缺失值补充完整呢?

直接根据相邻日期缺失的时间间隔,利用posexplode()函数将缺失日期及数据展开补齐,具体SQL如下:

with data as
         (
             select 'AAAA' as contract, '2018-12-21' as value_date, 9439.30 as amount, 12 as term
             union all
             select 'AAAA' as contract, '2019-03-21' as value_date, 9439.30 as amount, 12 as term
             union all
             select 'AAAA' as contract, '2019-06-21' as value_date, 9439.30 as amount, 12 as term
             union all
             select 'AAAA' as contract, '2019-09-21' as value_date, 9439.30 as amount, 12 as term
             union all
             select 'BBBB' as contract, '2018-12-02' as value_date, 9439.30 as amount, 10 as term
             union all
             select 'BBBB' as contract, '2019-02-02' as value_date, 9439.30 as amount, 10 as term
             union all
             select 'BBBB' as contract, '2019-06-02' as value_date, 9439.30 as amount, 10 as term
             union all
             select 'BBBB' as contract, '2019-09-02' as value_date, 9439.30 as amount, 10 as term
         )
select contract,
       add_months(value_date, pos) value_date,
       amount
from (
         select contract,
                value_date,
                amount,
                term,
                lead(value_date, 1, value_date) over (partition by contract order by value_date) next_value_date
         from data) tmp lateral view  posexplode (
        split (space( cast(months_between(next_value_date, value_date) as int)), " (?!$)")
) tmp AS pos,val;

结果如下:

2 小结

本文给出了一种非连续日期准确求解累计值的通用方法。通过本文可以学习到:

(1)连续日期的构造方法

(2)非连续日期准确求解累计值的方法

注意此类问题又叫稀疏字段累计求和问题

Supongo que te gusta

Origin blog.csdn.net/godlovedaniel/article/details/129318378
Recomendado
Clasificación