【问题标题】:How to get table names from SQL query?如何从 SQL 查询中获取表名?
【发布时间】: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

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

【问题讨论】:

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


    【解决方案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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2020-10-24
            • 2015-04-27
            • 2016-08-16
            • 2016-06-08
            • 2019-05-28
            • 2023-02-25
            • 1970-01-01
            相关资源
            最近更新 更多