如何使用 sql 查询而不是 api 覆盖列

Posted

技术标签:

【中文标题】如何使用 sql 查询而不是 api 覆盖列【英文标题】:How to overwrite column using sql query instead of api 【发布时间】:2020-09-10 11:45:22 【问题描述】:

例如,我有一个表 customers,其中有一列 name 和一列 last_name

我想连接这两个列并用连接的结果覆盖列name

在 Spark sql api 中我们可以做something like:

customers.withColumn("name", concat(col("name"), lit(" "), col("last_name")))

在sql查询中执行以下操作:

select *, concat(name, " ", last_name) AS name from customers

将改为在数据框中添加另一个列名。所以最后有两列同名name

有没有办法在sql查询中覆盖现有列而不添加新列?

【问题讨论】:

不,你不能使用 SQL 来做到这一点。您必须在 select 子句中明确指定每一列。 @blackbishop 当然可以。他只需要停止使用* SELECTs 一切。请看我的回答。 【参考方案1】:

这两种方法都有效。

使用 SQL 方法有效。不要使用*,这将包括旧列,只需使用CONCAT 并重命名为AS

customers.createOrReplaceTempView("customers")
spark.sql("SELECT CONCAT(name, ' ', last_name) AS name FROM customers").show()
//+--------+
//|    name|
//+--------+
//|John Doe|
//|Jane Doe|
//+--------+

withColumn 也可以,同样有一个withColumnRenamed

因此,按照您的意愿执行操作,创建一个新列,然后删除原始列并重命名新列。

// Problem Setup
val customers = = Seq(("John", "Doe"), ("Jane", "Doe")).toDF("name", "last_name")

customers.show()
//+----+---------+
//|name|last_name|
//+----+---------+
//|John|      Doe|
//|Jane|      Doe|
//+----+---------+

import org.apache.spark.sql.functions.lit, col, concat

customers.withColumn(
  "name_last_name", concat(col("name"), lit(" "), col("last_name"))
).drop("name", "last_name").withColumnRenamed("name_last_name", "name").show()
//+--------+
//|    name|
//+--------+
//|John Doe|
//|Jane Doe|
//+--------+

当然,您可以继续在withColumn 函数调用中自行执行操作,为新生成的列提供标签name 替换旧的标签,但您仍然必须删除last_name

customers.withColumn(
  "name", concat(col("name"), lit(" "), col("last_name"))
).drop("last_name").show()
//+--------+
//|    name|
//+--------+
//|John Doe|
//|Jane Doe|
//+--------+

【讨论】:

以上是关于如何使用 sql 查询而不是 api 覆盖列的主要内容,如果未能解决你的问题,请参考以下文章

如何对sql查询引用组中的多列求和

sql中如何使一列中的多个重复数据只显示一次, 求大神指导,使得图中的班简名重复的只显示一次。

sql中如何使一列中的多个重复数据只显示第一条

如何使用 sql 联合或组合某些列而不是其他列

如何在 sql 查询中创建空白/硬编码列?

sql 如何使几个子查询的结果用一列连接起来显示(试过合并、左右连接好像都不行),求大神指导。