用以前的值填充日历表中的行

Posted

技术标签:

【中文标题】用以前的值填充日历表中的行【英文标题】:Filling rows from calendar table with previous values 【发布时间】:2022-01-16 02:59:06 【问题描述】:

我是 SQL 的新手,刚从 Python 和 R 转过来,并且将 Spark SQL 与 Databricks 结合使用。我正在尝试完成一个基本查询,希望得到指导,尤其是解释与我的问题相关的 SQL 基本概念的指导。

我有一个包含完整连续日期的日历表,以及一个包含date_addeduser_idsalesprice 列的数据表。数据表的日期不完整,因为并非每个用户在每个日期都处于活动状态。以下是每个表格的示例。

日历表

date
2020-01-01
2020-01-02
2020-01-03
2020-01-04
2020-01-05
2020-01-06

数据表

date_added     user_id    sales    price
2020-01-02     01         1        4.00
2020-01-05     01         3        4.00
2020-01-02     02         1        5.00
2020-01-03     02         1        5.00
2020-01-05     02         2        5.00
2020-01-03     03         2        1.00
2020-01-05     03         5        1.00

我正在寻找创建一个新表,其中为每个用户定义了特定范围内的每个日历表日期(活动日期),并且除销售列之外的所有列的空值是由该列中的以下值填充。大致如下:

date           user_id    sales    price         
2020-01-02     01         1        4.00
2020-01-03     01         null     4.00
2020-01-04     01         null     4.00
2020-01-05     01         3        4.00
2020-01-02     02         1        5.00
2020-01-03     02         1        5.00
2020-01-04     02         null     5.00
2020-01-05     02         2        5.00
2020-01-02     03         null     1.00
2020-01-03     03         2        1.00
2020-01-04     03         null     1.00
2020-01-05     03         5        1.00

感谢任何关于我如何进行此输出的指导。我尝试在日期上使用 LEFT JOIN,但没有成功。我知道 UNION 运算符用于将表连接在一起,但不知道如何在此处应用该方法。

【问题讨论】:

【参考方案1】:

您可以将用户与日历表交叉连接,然后与数据表左连接:

spark.sql("""
  SELECT  date, dates.user_id, sales, COALESCE(data.price, dates.price) AS price
  FROM    (
      SELECT  user_id, price, date
      FROM    (SELECT user_id, FIRST(price) as price FROM data_table GROUP BY user_id)
      CROSS JOIN calender_table
      WHERE   date >= (SELECT MIN(date_added) FROM data_table)
      AND     date <= (SELECT MAX(date_added) FROM data_table)
  )   dates
  LEFT JOIN data_table data
  ON      dates.user_id = data.user_id
  AND     dates.date = data.date_added
""").show()

输出:

+----------+-------+-----+-----+
|date      |user_id|sales|price|
+----------+-------+-----+-----+
|2020-01-02|01     |1    |4.0  |
|2020-01-03|01     |null |4.0  |
|2020-01-04|01     |null |4.0  |
|2020-01-05|01     |3    |4.0  |
|2020-01-02|02     |1    |5.0  |
|2020-01-03|02     |1    |5.0  |
|2020-01-04|02     |null |5.0  |
|2020-01-05|02     |2    |5.0  |
|2020-01-02|03     |null |1.0  |
|2020-01-03|03     |2    |1.0  |
|2020-01-04|03     |null |1.0  |
|2020-01-05|03     |5    |1.0  |
+----------+-------+-----+-----+

您还可以使用sequence 函数在不使用日历表的情况下生成日期。请参阅我的其他答案here。

【讨论】:

【参考方案2】:

让您的原始数据框为df1。然后您可以获取每个idminmax 日期并将其设为`df2'。

from pyspark.sql import functions as f
from pyspark.sql import Window

w = Window.partitionBy('user_id').orderBy(f.desc('date_added'))

df2 = df1.groupBy('user_id') \
  .agg(f.sequence(f.min('date_added'), f.max('date_added')).alias('date_added')) \
  .withColumn('date_added', f.explode('date_added'))

df2.join(df, ['user_id', 'date_added'], 'left') \
   .withColumn('price', f.first('price').over(w)) \
   .orderBy('user_id', 'date_added') \
   .show()

+-------+----------+-----+-----+
|user_id|date_added|sales|price|
+-------+----------+-----+-----+
|      1|2020-01-02|    1|  4.0|
|      1|2020-01-03| null|  4.0|
|      1|2020-01-04| null|  4.0|
|      1|2020-01-05|    3|  4.0|
|      2|2020-01-02|    1|  5.0|
|      2|2020-01-03|    1|  5.0|
|      2|2020-01-04| null|  5.0|
|      2|2020-01-05|    2|  5.0|
|      3|2020-01-03|    2|  1.0|
|      3|2020-01-04| null|  1.0|
|      3|2020-01-05|    5|  1.0|
+-------+----------+-----+-----+

【讨论】:

以上是关于用以前的值填充日历表中的行的主要内容,如果未能解决你的问题,请参考以下文章

如何用以前的值填充数据框? [复制]

加入日历表中缺少的日期[重复]

如何在EXCEL单元格中制作可以选择的下拉日历并自动填充

如何从 api 动态填充日历标记的日期 - React Native,redux

ASP.NET MVC 视图需要将选定的下拉列表和日历日期传递给模型

在EXCEL中插入日历控件后,如何添加到单元格上(带下拉箭头),点击后出现日历,选择一个日期自动填充并隐