如何将日期与计数或整数关联

时间:2018-06-25 09:33:58

标签: scala apache-spark apache-spark-sql

我有一个DataFrame,其列为“ id”和“ date”。日期的格式为yyyy-mm-dd,下面是一个示例:

+---------+----------+
|  item_id|        ds|
+---------+----------+
| 25867869|2018-05-01|
| 17190474|2018-01-02|
| 19870756|2018-01-02|
|172248680|2018-07-29|
| 41148162|2018-03-01|
+---------+----------+

我想创建一个新列,其中每个日期都与一个从1开始的整数相关联,这样最小(最早)的日期将得到整数1,下一个(最早的第二个日期)将被分配给2,依此类推。

我希望我的DataFrame看起来像这样...:

+---------+----------+---------+
|  item_id|        ds|   number|
+---------+----------+---------+
| 25867869|2018-05-01|        3|
| 17190474|2018-01-02|        1|
| 19870756|2018-01-02|        1|
|172248680|2018-07-29|        4|
| 41148162|2018-03-01|        2|
+---------+----------+---------+

说明

最早的日期是1月02日,因此它的编号是1。由于有2行具有相同的日期,因此1被定位两次。在2018年1月2日之后,下一个日期为2018年3月1日,因此其编号为2,依此类推...我如何创建此类列?

2 个答案:

答案 0 :(得分:1)

这可以通过dense_rank函数中的Window来实现。

import org.apache.spark.sql.expressions.Window
import org.apache.spark.sql.functions._
val win = Window.orderBy(to_date(col("ds"),"yyyy-MM-dd").asc)
val df1 = df.withColumn("number", dense_rank() over win)

df1将根据需要包含列number

请注意:to_date(col("ds"),"yyyy-MM-dd")是强制性的,否则将被视为字符串,并且无法达到目的。

答案 1 :(得分:-1)

您应该创建一个函数以获取最旧的查询,而无需输入数字,例如:

SELECT * FROM tablename WHERE number IS NULL ORDER BY ds ASC

然后再次查询获得最大号码的地方:

SELECT * FROM tablename ORDER BY number DESC

然后,如果两个查询具有相同的日期,则使用相同的编号更新表:

UPDATE tablename SET number = 'greatest number from first query' WHERE ds = 'the date from first query'

或如果日期不同,则相同,但将数字加1:

UPDATE tablename SET number= 'greatest number from first query' + 1 WHERE ds = 'the date from first query'

要执行此操作,您应该首先将数字1与最早的条目关联。 您应该循环执行此操作,直到第一个查询(检查是否有未设置的任何数字)为空。 第一个查询假设空列全为空,如果是另一种情况,则应更改WHERE条件以检查该列何时为空。