如何从 SQL 查询中获取表名?

Posted

技术标签:

【中文标题】如何从 SQL 查询中获取表名?【英文标题】:How to get table names from SQL query? 【发布时间】:2018-04-11 23:24:33 【问题描述】:

我想使用 Scala 从 Spark 中的 sql 查询中获取所有表名。

假设用户发送如下 SQL 查询:

select * from table_1 as a left join table_2 as b on a.id=b.id

我想获取所有表格列表,例如 table_1table_2

正则表达式是唯一的选择吗?

【问题讨论】:

【参考方案1】:

非常感谢@Swapnil Chougule 的the answer。这启发了我提供一种在结构化查询中收集所有表的惯用方式。

scala> spark.version
res0: String = 2.3.1

def getTables(query: String): Seq[String] = 
  val logicalPlan = spark.sessionState.sqlParser.parsePlan(query)
  import org.apache.spark.sql.catalyst.analysis.UnresolvedRelation
  logicalPlan.collect  case r: UnresolvedRelation => r.tableName 


val query = "select * from table_1 as a left join table_2 as b on a.id=b.id"
scala> getTables(query).foreach(println)
table_1
table_2

【讨论】:

在pyspark中能实现同样的功能吗? 这不完整,CTE中的表被忽略,“WIth”类型的孩子需要额外访问 @smokeny 你能显示破坏代码的查询吗?那会很有帮助。 就像with e as (select * from temp.tbl3), d as (select * from temp.tbl1) select * from ( select * from temp.tbl1 a cross join temp.tbl2 b) c cross join d cross join e 一样简单。您的 sn-p 将跳过 temp.tbl3 和 temp.tbl3 由于 sessionState 在 Spark 2.4.4 中具有私有访问权限,那么在 Spark 2.4.4 中实现相同功能的首选方法是什么?【参考方案2】:

希望对你有帮助

使用 spark sql 解析器解析给定的查询(spark 内部也是如此)。您可以从会话状态中获取 sqlParser。它将给出查询的逻辑计划。遍历查询的逻辑计划并检查它是否是 UnresolvedRelation 的实例(叶逻辑运算符表示逻辑查询计划中尚未解决的表引用)并从中获取表。

def getTables(query: String) : Seq[String] =
    val logical : LogicalPlan = localsparkSession.sessionState.sqlParser.parsePlan(query)
    val tables = scala.collection.mutable.LinkedHashSet.empty[String]
    var i = 0
    while (true) 
      if (logical(i) == null) 
        return tables.toSeq
       else if (logical(i).isInstanceOf[UnresolvedRelation]) 
        val tableIdentifier = logical(i).asInstanceOf[UnresolvedRelation].tableIdentifier
        tables += tableIdentifier.unquotedString.toLowerCase
      
      i = i + 1
    
    tables.toSeq

【讨论】:

【参考方案3】:

我有一些带有嵌套查询的复杂 sql 查询,并在 @Jacek Laskowski 的答案上进行了迭代以得到这个

  def getTables(spark: SparkSession, query: String): Seq[String] = 
    val logicalPlan = spark.sessionState.sqlParser.parsePlan(query)
    var tables = new ListBuffer[String]()
    var i: Int = 0

    while (logicalPlan(i) != null) 
      logicalPlan(i) match 
        case t: UnresolvedRelation => tables += t.tableName
        case _ => 
      
      i += 1
    

    tables.toList
  

【讨论】:

【参考方案4】:
def __sqlparse2table(self, query):
    '''
    @description: get table name from table
    '''
    plan = self.spark._jsparkSession.sessionState().sqlParser().parsePlan(query)
    plan_string = plan.toString().replace('`.`', '.')
    unr = re.findall(r"UnresolvedRelation `(.*?)`", plan_string)
    cte = re.findall(r"CTE \[(.*?)\]", plan.toString())
    cte = [tt.strip() for tt in cte[0].split(',')] if cte else cte
    schema = set()
    tables = set()
    for table_name in unr:
        if table_name not in cte:
            schema.update([table_name.split('.')[0]])
            tables.update([table_name])

    return schema, tables

【讨论】:

【参考方案5】:

由于您需要列出 table1 和 table2 中列出的所有列名称,因此您可以做的是在 hive db 中显示 db.table_name 中的表。

val tbl_column1 = sqlContext.sql("show tables in table1");
val tbl_column2 = sqlContext.sql("show tables in table2");

您将获得两个表中的列列表。

tbl_column1.show

name      
id  
data    

【讨论】:

grep '覆盖表' .txt | sed -r 's/.?(覆盖表)\s?([^ ]*).*/\2/g' | sort -u ,UNIX 做到了 grep 'INTO\|FROM\|JOIN' .sql | sed -r 's/.?(FROM|INTO|JOIN)\s?([^ ]*).*/\2/g' |排序 -u【参考方案6】:

unix 成功了,grep 'INTO\|FROM\|JOIN' .sql | sed -r 's/.?(FROM|INTO|JOIN)\s?([^ ])./\2/g' |排序-u

grep '覆盖表' .txt | sed -r 's/.?(覆盖表)\s?([^ ])./\2/g' |排序-u

【讨论】:

以上是关于如何从 SQL 查询中获取表名?的主要内容,如果未能解决你的问题,请参考以下文章

如何从sql查询中提取表名和列名?

从 SQL 失败中获取表

如何从 SQL 查询中的 CREATE/UPDATE/INSERT 语句中提取表名?

SQL 查询 SELECT FROM [从表名中选择值]

JDBC:获取 SQL 查询中涉及的表名

如何在python中从以下获取表名