当前位置: 首页 > 知识库问答 >
问题:

如何将逗号分隔的多列拆分为多行?

温嘉赐
2023-03-14

我有一个包含N个字段的数据框,如下所述。列的数量和值的长度将有所不同。

输入表:

+--------------+-----------+-----------------------+
|Date          |Amount     |Status                 |
+--------------+-----------+-----------------------+
|2019,2018,2017|100,200,300|IN,PRE,POST            |
|2018          |73         |IN                     |
|2018,2017     |56,89      |IN,PRE                 |
+--------------+-----------+-----------------------+

我必须用一个序列列将其转换为以下格式。

预期输出表:

+-------------+------+---------+
|Date  |Amount|Status| Sequence|
+------+------+------+---------+
|2019  |100   |IN    |   1     |
|2018  |200   |PRE   |   2     |
|2017  |300   |POST  |   3     |
|2018  |73    |IN    |   1     |
|2018  |56    |IN    |   1     |
|2017  |89    |PRE   |   2     |
+-------------+------+---------+

我尝试过使用explode,但explode一次只能使用一个数组。

var df = dataRefined.withColumn("TOT_OVRDUE_TYPE", explode(split($"TOT_OVRDUE_TYPE", "\\"))).toDF

var df1 = df.withColumn("TOT_OD_TYPE_AMT", explode(split($"TOT_OD_TYPE_AMT", "\\"))).show 

有人知道我怎么做吗?谢谢你的帮助。

共有3个答案

黄浩涆
2023-03-14

是的,我个人也觉得explode有点烦人,在你的情况下,我可能会选择flatMap

import spark.implicits._
import org.apache.spark.sql.Row
val df = spark.sparkContext.parallelize(Seq((Seq(2019,2018,2017), Seq(100,200,300), Seq("IN","PRE","POST")),(Seq(2018), Seq(73), Seq("IN")),(Seq(2018,2017), Seq(56,89), Seq("IN","PRE")))).toDF()

val transformedDF = df
  .flatMap{case Row(dates: Seq[Int], amounts: Seq[Int], statuses: Seq[String]) =>
     dates.indices.map(index => (dates(index), amounts(index), statuses(index), index+1))}
  .toDF("Date", "Amount", "Status", "Sequence")

输出:

df.show
+----+------+------+--------+
|Date|Amount|Status|Sequence|
+----+------+------+--------+
|2019|   100|    IN|       1|
|2018|   200|   PRE|       2|
|2017|   300|  POST|       3|
|2018|    73|    IN|       1|
|2018|    56|    IN|       1|
|2017|    89|   PRE|       2|
+----+------+------+--------+
麹凯捷
2023-03-14

您可以通过使用Dataframe内置函数arrays_zip拆分pos爆炸来实现这一点

解释:

scala>val df=Seq((("2019,2018,2017"),("100,200,300"),("IN,PRE,POST")),(("2018"),("73"),("IN")),(("2018,2017"),("56,89"),("IN,PRE"))).toDF("date","amount","status")

scala>:paste
df.selectExpr("""posexplode(
                            arrays_zip(
                                        split(date,","), //split date string with ',' to create array
                                        split(amount,","),
                                        split(status,","))) //zip arrays
                            as (p,colum) //pos explode on zip arrays will give position and column value
            """)
    .selectExpr("colum.`0` as Date", //get 0 column as date
                "colum.`1` as Amount", 
                "colum.`2` as Status", 
                "p+1 as Sequence") //add 1 to the position value
    .show()

结果:

+----+------+------+--------+
|Date|Amount|Status|Sequence|
+----+------+------+--------+
|2019|   100|    IN|       1|
|2018|   200|   PRE|       2|
|2017|   300|  POST|       3|
|2018|    73|    IN|       1|
|2018|    56|    IN|       1|
|2017|    89|   PRE|       2|
+----+------+------+--------+
周威
2023-03-14

下面是另一种方法,对每列使用posexplode,并将所有生成的数据帧连接到一个数据帧中:

导入组织。阿帕奇。火花sql。功能。{posexplode,单调地_递增_id,col}

val df = Seq(
  (Seq("2019", "2018", "2017"), Seq("100", "200", "300"), Seq("IN", "PRE", "POST")),
  (Seq("2018"), Seq("73"), Seq("IN")),
  (Seq("2018", "2017"), Seq("56", "89"), Seq("IN", "PRE")))
.toDF("Date","Amount", "Status")
.withColumn("idx", monotonically_increasing_id)

df.columns.filter(_ != "idx").map{
  c => df.select($"idx", posexplode(col(c))).withColumnRenamed("col", c)
}
.reduce((ds1, ds2) => ds1.join(ds2, Seq("idx", "pos")))
.select($"Date", $"Amount", $"Status", $"pos".plus(1).as("Sequence"))
.show

输出:

+----+------+------+--------+
|Date|Amount|Status|Sequence|
+----+------+------+--------+
|2019|   100|    IN|       1|
|2018|   200|   PRE|       2|
|2017|   300|  POST|       3|
|2018|    73|    IN|       1|
|2018|    56|    IN|       1|
|2017|    89|   PRE|       2|
+----+------+------+--------+
 类似资料:
  • 我想从中的一列创建多个列,使用JavaSpark中的逗号分隔符。 我在中的一列中有一个带逗号的值,并希望使用逗号分隔符将其拆分为多列。我有以下代码: 输入 输出

  • 问题内容: 我返回的值包含255个逗号分隔的值。有没有一种简单的方法可以将其拆分为不具有255 substr的列? 到 问题答案: 您可以使用: 我建议您在Excel(或其他电子表格)中生成255个数字的列,并使用电子表格生成SQL代码。

  • 问题内容: 我有一个未标准化的表,其中的列包含逗号分隔的列表,该列表是另一个表的外键: 我想将此数据读入不提供过程语言的搜索引擎中。 那么,有没有一种方法, 要么 就这一栏中加入 或 该数据运行查询插入相应的条目到一个新的表?结果数据应如下所示: 如果DBMS支持返回表的函数,但MySQL显然不支持,我可以想到一个解决方案。 问题答案: 在MySQL中,可以通过以下方式实现 现在要获取逗号分隔的v

  • 问题内容: 我有看起来像这样的数据: 对于每个customer_id,我需要用逗号分隔的列表,以指示该客户运营的月份: 等等。如何使用SQL Server 2005 SQL(而不是T-SQL)轻松生成此逗号分隔的列表? 我在Stack Overflow和其他地方在这里看到的大多数解决方案似乎都是基于联接多个行值而不是列值来创建逗号分隔的列表: T-SQL FOR XML路径(’‘) 关联的子查询与

  • 问题内容: 我有一个这样的表: Department是另一个具有dept_id和dept_name作为列的表。我想要这样的结果, 有什么帮助吗? 问题答案: 您可以按照以下方式进行操作: 编辑: 基于我需要加入哪一列?在一个表中,我有逗号分隔的ID,而在其他表中,我只有ID

  • 在逗号处划分字符串的最佳方法是什么,这样每个单词都可以成为ArrayList的一个元素? 例如: