仅在存在字段(SQL或Scala)的情况下选择字段

时间:2019-03-18 17:17:18

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

输入数据框可能并不总是具有所有列。在SQL或SCALA中,我想创建一个select语句,即使数据框没有列,它也不会出错,它只会输出确实存在的列。

例如,此语句将起作用。

Select store, prod, distance from table

+-----+------+--------+
|store|prod  |distance|
+-----+------+--------+
|51   |42    |2     |
|51   |42    |5     |
|89   |44    |9     |

如果数据框如下所示,我希望同一条语句起作用,只忽略不存在的内容,只输出现有的列(在本例中为“存储”和“生产”)

+-----+------+
|store|prod  |
+-----+------+
|51   |42    |
|51   |42    |
|89   |44    |

3 个答案:

答案 0 :(得分:2)

您可以在columns上使用Dataframe方法。看起来像这样:

val result = if(df.columns.contains("distance")) df.select("store", "prod", "distance") 
             else df.select("store", "prod")

编辑:

有许多这样的列,您可以将它们保留在数组中,例如colsfilter

val selectedCols = cols.filter(col -> df.columns.contains("distance")).map(col)
val result = df.select(selectedCols:_*)

答案 1 :(得分:2)

您可以在列表中包含所有列的列表,这些列表可以是硬编码的,也可以是从其他元数据准备的,并使用相交的

val columnNames = Seq("c1","c2","c3","c4")

df.select( df.columns.intersect(columnNames).map(x=>col(x)): _* ).show()

答案 2 :(得分:1)

假设您使用扩展的SQL模板(例如select a,b,c from tab),则可以执行以下类似操作来获得所需的结果。

  1. 获取sql字符串并将其转换为小写。
  2. 在空间或逗号上分割sql以获取单个单词在数组中
  3. 从上面的数组中删除“选择”和“来自”,因为它们是SQL关键字。
  4. 现在您的最后一个索引是表名
  5. 第一个到最后一个索引,但其中包含选择列的列表。
  6. 要获取所需的列,只需针对df2.columns对其进行过滤。 SQL中存在但表中没有的列将被过滤掉
  7. 现在使用各个片段构造sql。
  8. 使用spark.sql(reqd_sel_string)运行它以获取结果。

检查一下

scala> val df2 = Seq((51,42),(51,42),(89,44)).toDF("store","prod")
df2: org.apache.spark.sql.DataFrame = [store: int, prod: int]

scala> df2.createOrReplaceTempView("tab2")

scala> val sel_query="Select store, prod, distance from tab2".toLowerCase
sel_query: String = select store, prod, distance from tab2

scala> val tabl_parse = sel_query.split("[ ,]+").filter(_!="select").filter(_!="from")
tabl_parse: Array[String] = Array(store, prod, distance, tab2)

scala> val tab_name=tabl_parse(tabl_parse.size-1)
tab_name: String = tab2

scala> val tab_cols = (0 until tabl_parse.size-1).map(tabl_parse(_))
tab_cols: scala.collection.immutable.IndexedSeq[String] = Vector(store, prod, distance)

scala> val reqd_cols = tab_cols.filter( x=>df2.columns.contains(x))
reqd_cols: scala.collection.immutable.IndexedSeq[String] = Vector(store, prod)

scala> val reqd_sel_string = "select " + reqd_cols.mkString(",") + " from " + tab_name
reqd_sel_string: String = select store,prod from tab2

scala> spark.sql(reqd_sel_string).show(false)
+-----+----+
|store|prod|
+-----+----+
|51   |42  |
|51   |42  |
|89   |44  |
+-----+----+


scala>