如何从 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_1
和 table_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 查询中获取表名?的主要内容,如果未能解决你的问题,请参考以下文章