如何比较 SQL 语句中两个数据框的架构?

Posted

技术标签:

【中文标题】如何比较 SQL 语句中两个数据框的架构?【英文标题】:How to compare the schema of two dataframes in SQL statement? 【发布时间】:2018-09-04 04:41:23 【问题描述】:

有很多方法可以验证 Spark 中两个数据帧的架构,例如 here。但是我只想在 SQL 中验证两个数据帧的架构,我的意思是 SparkSQL。

示例查询 1:

SELECT DISTINCT target_person FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME IN ('columnA','ColumnB') AND TABLE_SCHEMA='ad_facebook'

示例查询 2:

SELECT count(*) FROM information_schema.columns WHERE table_name = 'ad_facebook'

我知道 spark 中没有数据库(模式)的概念,但我读到 metastore 包含模式信息等。

我们可以在 SparkSQL 中编写上述 SQL 查询吗?

编辑:

我只是在检查为什么 show create table 在 spark sql 上不起作用,是因为它是临时表吗?

scala> val df1=spark.sql("SHOW SCHEMAS")
df1: org.apache.spark.sql.DataFrame = [databaseName: string]

scala> df1.show
+------------+
|databaseName|
+------------+
|     default|
+------------+


scala> val df2=spark.sql("SHOW TABLES in default")
df2: org.apache.spark.sql.DataFrame = [database: string, tableName: string ... 1 more field]

scala> df2.show
+--------+---------+-----------+
|database|tableName|isTemporary|
+--------+---------+-----------+
|        |       df|       true|
+--------+---------+-----------+


scala> val df3=spark.sql("SHOW CREATE TABLE default.df")
org.apache.spark.sql.catalyst.analysis.NoSuchTableException: Table or view 'df' not found in database 'default';
  at org.apache.spark.sql.catalyst.catalog.SessionCatalog.requireTableExists(SessionCatalog.scala:180)
  at org.apache.spark.sql.catalyst.catalog.SessionCatalog.getTableMetadata(SessionCatalog.scala:398)
  at org.apache.spark.sql.execution.command.ShowCreateTableCommand.run(tables.scala:834)
  at org.apache.spark.sql.execution.command.ExecutedCommandExec.sideEffectResult$lzycompute(commands.scala:58)
  at org.apache.spark.sql.execution.command.ExecutedCommandExec.sideEffectResult(commands.scala:56)
  at org.apache.spark.sql.execution.command.ExecutedCommandExec.executeCollect(commands.scala:67)
  at org.apache.spark.sql.Dataset.<init>(Dataset.scala:182)
  at org.apache.spark.sql.Dataset$.ofRows(Dataset.scala:67)
  at org.apache.spark.sql.SparkSession.sql(SparkSession.scala:623)
  ... 48 elided

【问题讨论】:

【参考方案1】:

可以使用DESCRIBE [EXTENDED] [db_name.]table_name查询架构

见https://docs.databricks.com/spark/latest/spark-sql/index.html#spark-sql-language-manual

【讨论】:

嗨@DW你能检查我的问题吗,我刚刚更新了它。当我出于某种原因查询show create table 时,spark sql 不起作用。你能帮我理解为什么会这样吗? @JumpMan 请检查这个“default.df”——默认是数据库名,df 是表名。它说没有名为“df”的表 如果您检查上面的查询“显示表”,它会返回 df 表吗?【参考方案2】:

试试这个提取每个模式的代码并进行比较。这会比较列的名称、列的数据类型、是否可以为空。

val x = df1.schema.sortBy(x => x.name) // get dataframe 1 schema and sort it base on column name.
val y = df2.schema.sortBy(x => x.name) // // get dataframe 2 schema and sort it base on column name.

val out = x.zip(y).filter(x => x._1 != x._2) // zipping 1st column of df1, df2 ...2nd column of df1,df2 and so on for all columns and their datatypes. And filtering if any mismatch is there

if(out.size == 0)  // size of `out` should be 0 if matching
    println("matching")

else println("not matching")

【讨论】:

嗨 Praveen,我只对 spark 中的 sql 感兴趣,而不是 scala 代码,sortBy 和 zip 是 scala 函数而不是 spark sql 函数。 由于我们只比较列名和数据类型(x , y 是 Struct 类型),它们的计数将以 10 或 100 为单位,因此可以使用某种语言轻松完成。我不明白为什么只使用 spark 代码来比较 2 个 Struct 类型值。【参考方案3】:

我们可以在SparkSQL 中通过两种方式获取架构。

方法一:

spark.sql("desc db_name table_name").show()

这将只显示前 20 行,这与 df.show() 的数据框概念完全相同

(意思是任何超过 20 列的表 - 将显示架构 仅适用于前 20 列)

例如:

+--------------------+---------+-------+
|            col_name|data_type|comment|
+--------------------+---------+-------+
|                col1|   bigint|   null|
|                col2|   string|   null|
|                col3|   string|   null|
+--------------------+---------+-------+

方法二:

spark.sql("desc db_name table_name").collect().foreach(println)

这将显示所有列的完整架构。

例如:

[col1,bigint,null]
[col2,string,null]
[col3,string,null]

【讨论】:

以上是关于如何比较 SQL 语句中两个数据框的架构?的主要内容,如果未能解决你的问题,请参考以下文章

sql比对两个表中的差异数据比较的sql语句

sql语句中怎样比较两个日期的大小???

如何以编程方式生成基于数据框的创建表语句

如何避免这两个 SQL 语句之间出现死锁?

SQL语句中怎样比较两个日期的大小?

如何匹配两个数据框的架构