如果当前日期不可用,请填写前一个日期的值

问题描述 投票:0回答:1

我有两张桌子 -

sales
currency_rate
。我想根据表
CurrRate
col
Sales
和表
sales
col
[Date]
中的月份,将 col
currency_rate
填充到
CurrentPeriod
中的每个交易行。如果表中的日期链发生中断
currency_rate
我想将上个月的前一个
CurrRate
值填充到
Sales
的实际行。值得一提的是,
CurrentPeriod
PreviousPeriod
都是日期时间,表
Date
中的
Sales
是int,例如20240701

摘自

Sales

日期 价值
20230404 1226.55
20230506 8.00
20230717 13834.73
20230916 10120.71
20230904 8.00
20230506 102.14
20230912 8.00
20230526 12813.40
20230805 779.90

来自

currency_rate
的片段(假设一个句号为空)

当前时期 上一期 当前汇率
2023-04-01T00:00:00.0000000 (空) 0.894166
2023-05-01T00:00:00.0000000 2023-04-01T00:00:00.0000000 0.893192
2023-06-01T00:00:00.0000000 2023-05-01T00:00:00.0000000 0.879856
2023-07-01T00:00:00.0000000 2023-06-01T00:00:00.0000000 0.887729
(空) 2023-07-01T00:00:00.0000000 0.896162
2023-09-01T00:00:00.0000000 2023-08-01T00:00:00.0000000 0.898093

预期结果:

日期 价值 当前汇率
20230404 1226.55 0.894166
20230506 8.00 0.893192
20230717 13834.73 0.887729
20230916 10120.71 0.898093
20230904 8.00 0.898093
20230506 102.14 0.893192
20230912 8.00 0.898093
20230526 12813.40 0.893192
20230805 779.90 0.887729

如您所见,

20230805
的值是
0.887729
,属于
2023-07-01T00:00:00.0000000
,因为它是2023年08月的上一个时期

目前我所做的是使用

PreviousPeriod
函数将
currency_rate
转换为
LAG

我的一个疑问是 - LAG 应该按

CurrentPeriod
ASC 还是 DESC 排序?目前是 ASC,但我不知道是否应该是 DESC - 关于这个主题有什么想法吗?

如何使用spark.sql进行连接(可以在T-SQL中,我将其转换为spark),这样我就可以获得适当的当前汇率,即使我在日期中有NULL(不是预期的,但现在更好地覆盖它而不是返回当某事失败时)。为了涵盖我使用的连接的数据类型转换

date_format(rates.currentperiod, 'yyyyMM') = date_format(to_date(cast(sales.date as string), 'yyyyMMdd'), 'yyyyMM')

任何帮助将非常感激

我的询问

SELECT
    inv.*
    IFNULL(cr.CurrRate, 0) AS CurrencyRate
FROM
    v_sales inv
LEFT JOIN (
    SELECT
        CurrentPeriod,
        LAG(CurrentPeriod) OVER (PARTITION BY curr_rate_from, curr_rate_to ORDER BY CurrentRate) AS PreviousPeriod,
        curr_rate_from,
        curr_rate_to,
        CurrRate
    FROM
        schema.currency_rate
) cr ON
    inv.curr_code = cr.curr_rate_from -- not that important
    AND (
        (date_format(to_date(cast(inv.Day AS STRING), 'yyyyMMdd'), 'yyyyMM') = date_format(cr.CurrentPeriod, 'yyyyMM'))
        OR
        (date_format(to_date(cast(inv.Day AS STRING), 'yyyyMMdd'), 'yyyyMM') < date_format(cr.CurrentPeriod, 'yyyyMM') 
        AND date_format(to_date(cast(inv.Day AS STRING), 'yyyyMMdd'), 'yyyyMM') >= date_format(cr.PreviousPeriod, 'yyyyMM'))
    )

我的

CurrencyRate
里还有一些0,不应该是这样的

sql apache-spark-sql
1个回答
0
投票

一个选项是创建一个递归 cte 以生成销售表中从最小日期到最大日期的所有月份的日历。如果您正在处理日期,那么使用日期数据类型(而不是数字或字符串)是最有效的。在下面的答案中,所有日期列都被截断为一个月。
将销售和费率表连接到日历 cte,处理空值并获得预期结果:

WITH    -- recursive cte generating months for period of sales
  cal ( m_id, a_month, month_untill) AS
      ( Select 1 as m_id, month_from as a_month, month_untill
        From ( Select Min(TRUNC(To_Date(dat, 'yyyyMMdd'), 'MM')) as month_from, 
                    Max(TRUNC(To_Date(dat, 'yyyyMMdd'), 'MM')) as month_untill
               From sales
             )
       UNION ALL
        Select m_id + 1, ADD_MONTHS(a_month, 1), month_untill
        From   cal
        Where  a_month < month_untill
      )

...这里的销售表是内连接 - 但如果您想查看期间的所有月份(有销售或没有销售),请将其更改为左连接。费率表已左连接到日历,如果没有当前期间日期,则使用 Coalesce() 函数获取前一个日期...

--    S Q L : 
Select     s.dat, s.val,
           Coalesce(cr.rate, LAG(cr.rate) Over(Order By cal.a_month)) as rate
From       cal  
Inner Join sales s ON( Trunc(To_Date(SubStr(s.dat, 1, 10), 'yyyyMMdd'), 'MM')  = cal.a_month )
Left Join  currency_rate cr ON( Coalesce(Trunc(cr.currentperiod, 'MM'), Trunc(cr.previousperiod, 'MM')) = cal.a_month And 
                                         Trunc(cr.currentperiod, 'MM') = Trunc(To_Date(SubStr(s.dat, 1, 10), 'yyyyMMdd'), 'MM') )
Order By  cal.a_month, s.dat

/*    R e s u l t :
       DAT        VAL       RATE
---------- ---------- ----------
  20230404    1226.55   0.894166   
  20230506          8   0.893192   
  20230506     102.14   0.893192   
  20230526    12813.4   0.893192   
  20230717   13834.73   0.887729   
  20230805      779.9   0.887729   
  20230904          8   0.898093   
  20230912          8   0.898093   
  20230916   10120.71   0.898093    */
© www.soinside.com 2019 - 2024. All rights reserved.