当前位置:首页 » 编程语言 » 将语法树解析成sql
扩展阅读
webinf下怎么引入js 2023-08-31 21:54:13
堡垒机怎么打开web 2023-08-31 21:54:11

将语法树解析成sql

发布时间: 2022-07-22 04:53:23

‘壹’ java解析sql语句是实现不了的

哈哈,楼主没文化了。这个是需要词法解析和语法解析的。总体的思路是设计一个分词器,按规则将语句进行分词。例如,关键字用1表示,字符串用2表示,当分词到 select时,标识1,分词到'select'时标识为2。然后语法解析器用来分析怎么样的词法组合才合理,需要构造语法树等。

整体来说还是很复杂的,但是是完全可以实现的。

最后推荐个很好的java实现: JavaCC

‘贰’ 急求设计SQL语言的语法树

看是用在asp中或是易语言中,abc是变量还是常量,另外是不是模糊查询,这样一来就要分好几种情况了(以下代码不含模糊查询,如果要用需要加%号):
一、abc为常量
不分易语言和asp
如果字段1-4是文本内容,sql语句如下:
"select
*
from
表1
where
字段1
like
'abc'
and
字段2
like
'abc'
and
字段3
like
'abc'
and
字段4
like
'abc'"
如果字段1-4是数值内容,sql语句如下:
"select
*
from
表1
where
字段1=abc
and
字段2=abc
and
字段3=abc
and
字段4=abc"
二、abc为变量
如果字段1-4是文本内容,sql语句如下:
asp中:
“select
*
from
表1
where
字段1
like
'”&abc&"'
and
字段2
like
'”&abc&"'and
字段3
like
'”&abc&"'and
字段4
like
'”&abc&"'"
易语言中:
”select
*
from
表1
where
字段1
like
'“+abc+”'
and
字段2
like
'“+abc+”'
and
字段3
like
'“+abc+”'
and
字段4
like
'“+abc+”'

如果字段1-4是数值内容,sql语句如下:
asp中:
“select
*
from
表1
where
字段1
=”&abc&"and
字段2
=”&abc&"and
字段3=”&abc&"and
字段4=”&abc&"
易语言中:
“select
*
from
表1
where
字段1
=”+abc+"and
字段2
=”+abc+"and
字段3=”+abc+"and
字段4=”+abc+"

‘叁’ 如何获取SQL2005下的SQL语句的语义分析

我想获取一段sql语句在 mssql2005下解析成的语句,
主要是想获取这个sql所用到的所有的表的名字。(ps:复杂的sql语句的)
请高手帮忙 在线等~
我的意思是要从用户输入的sql语句中提取该语句中所用的表
或者是:
sql 执行的步骤

1. 解析器

第 1 阶段是解析器阶段,它将 SQL 文本转换成语法树。这个阶段不查找系统目录中的任何信息,不访问数据库

2. 语义分析

第 2 阶段分析由解析器创建的语法树,并产生用于查询的查询控制块和表达式树。要构建这些内部数据结构,它执行以下操作:

验证对象
解析 UDR
如果可能的话,消除常量
验证对象

第 2 阶段访问数据库中不同的系统目录,以验证查询所引用的所有数据库对象(诸如表、列、视图、类型、UDR 等等)是否都存在。它在数据库中找到这些对象的标识,然后创建查询控制块和表达式树。

我要的就是验证对象步骤里的表的信息

‘肆’ 怎样将一个sql语句转化为相应的语法树

token就是把程序的语句进行类似分词得到的单词。
它是下步语法分析的输入。
typedef struct Token
{
int label;
char name[buf];
int code;
}Token;
是一个结构体。
C语言中单词可以分为
保留字,就是int,while等。
标识符,例如int m;m就是标识符。
数字,有整数和小数
字符,+,-,.,*,;等字符,其中也包括++,--,!=等。
label应该标识token的类型。
name表示的就是程序中对应的字符序列。例如:int等。
最后code的意思,看不出来。。。,不过个人认为,上面的两项就可以表示
token的信息。

‘伍’ spark SQL和hive到底什么关系

Hive是一种基于HDFS的数据仓库,并且提供了基于SQL模型的,针对存储了大数据的数据仓库,进行分布式交互查询的查询引擎。

SparkSQL并不能完全替代Hive,它替代的是Hive的查询引擎,SparkSQL由于其底层基于Spark自身的基于内存的特点,因此速度是Hive查询引擎的数倍以上,Spark本身是不提供存储的,所以不可能替代Hive作为数据仓库的这个功能。

SparkSQL相较于Hive的另外一个优点,是支持大量不同的数据源,包括hive、json、parquet、jdbc等等。SparkSQL由于身处Spark技术堆栈内,基于RDD来工作,因此可以与Spark的其他组件无缝整合使用,配合起来实现许多复杂的功能。比如SparkSQL支持可以直接针对hdfs文件执行sql语句。

‘陆’ entity framework中怎么通过lambda表达式生成sql语句的

Set返回的是IQuerable。然后你Where的时候,lambda表达式不是一个函数,而是一个Expression<函数>,C#编译器会把这段代码的语法树在运行时直接交给IQuerable。所以IQuerable自然就知道你Where了,也知道你Where了什么。但是ToList是要给结果的,IQuerable的ToList就会把之前的Where翻译成SQL,然后提交上去,等结果回来了,搞成列表给你。

‘柒’ hive1和hive2的区别

1.用户接口:Client
CLI(hive shell)、JDBC/ODBC(java访问hive)、WEBUI(浏览器访问hive)

2.元数据:Metastore
元数据包括:表名、表所属的数据库(默认是default)、表的拥有者、列/分区字段、表的类型(是否是外部表)、表的数据所在目录等;
默认存储在自带的derby数据库中,推荐使用MySQL存储Metastore

3.Hadoop
使用HDFS进行存储,使用MapRece进行计算。

4.驱动器:Driver
(1)解析器(SQL Parser):将SQL字符串转换成抽象语法树AST,这一步一般都用第三方工具库完成,比如antlr;对AST进行语法分析,比如表是否存在、字段是否存在、SQL语义是否有误。
(2)编译器(Physical Plan):将AST编译生成逻辑执行计划。
(3)优化器(Query Optimizer):对逻辑执行计划进行优化。
(4)执行器(Execution):把逻辑执行计划转换成可以运行的物理计划。对于Hive来说,就是MR/Spark。

Hive通过给用户提供的一系列交互接口,接收到用户的指令(SQL),使用自己的Driver,结合元数据(MetaStore),将这些指令翻译成MapRece,提交到Hadoop中执行,最后,将执行返回的结果输出到用户交互接口。

二:Hive的作用和优势:
基于Hadoop的数据仓库解决方案
Hive是基于Hadoop的一个数据仓库工具,将结构化的数据文件映射为数据库表。

提供类sql的查询语言HQL(Hive Query Language)

数据不放在hive上,放在HDFS上

由Facebook开源用于解决海量结构化日志的数据统计。

执行程序运行在Yarn上

优势:
提供了简单的优化模型

HQL类sql语法,简化MR开发

支持在HDFS和HBase上临时查询数据

支持用户自定义函数,格式

成熟JDBC和ODBC驱动程序,用于ETL和BI

稳定可靠的批处理

支持在不同计算框架运行

缺点:
Hive的执行延迟比较高,因此Hive常用于数据分析,对实时性要求不高的场合

迭代式算法无法表达

数据挖掘方面不擅长

Hive自动生成的MapRece作业,通常情况下不够智能化

Hive调优比较困难,粒度较粗

‘捌’ 分布式数据库片段查询是什么

一些多机查询计算场景下,要求合并多机数据源,假设某个需求需要将数据再次计算。

计算的列不在select查询中,拿回来的多机数据源因为没有需要计算的列,就无法计算。

通过记录原来select的列数,将需要再次计算的列附加到select列中,待计算完毕后,按照原来的select列数将数据发送给客户端。

本方案应用于多机查询处理中(分布式数据库),结合数据定义配置,使用本方法能够获取到查询需要的额外列是否真实有效,结合数据散列方法优化本方法的使用。

Original query:原始查询,一般是用户发给数据库的查询语句;Sytax tree:语法树,用户发送给数据库的查询语句,通过解析器生成的一个可供代码处理的逻辑结构;Fetch select list:这个动作是获取SELECT查询语句中的查询列。

Have group:这个动作是检查SELECT查询语句中是否存在GROUP关键字。Have order:这个动作是检查SELECT查询语句中是否存在ORDER关键字。Select list:一个存储SELECT语句中查询列的数据结构。

Select list, [group list, order list]:修改后的查询语句格式,括号里面的新增列,是附加到原始列后面的。

原始SQL解析成语法树结构,该语法树能够提供一个代码结构,后续处理流程会使用到这个代码结构。首先扫描SELECT查询的列,将SELECT的列存储到SELECT LIST结构中。

扫描语法树查看是否有GROUP(分组)关键字存在,如果存在,需要判断GROUP分组的列在SELECT LIST中是否已经存在,如果不存在,则将GROUP分组列增加到SELECT LIST中,并将GROUP分组列附加到原查询语句的查询列尾部,并且记录下分组列在查询列中的位置。

扫描语法树查看是否有ORDER(排序)关键字存在,如果存在,需要判断SELECT LIST是否已经存在ORDER排序列,如果ORDER排序列没有包含在SELECT LIST中,则将ORDER排序列放入SELECT LIST中,并且将ORDER排序列附加到查询语句尾部,标记ORDER排序列在查询语句中的位置。

经过处理流程1,2,3,4就将客户端发送给数据库的原始查询语句改写为新的查询语句,下面使用一个具体例子来说明实际处理过程。

例:Original query(原始查询语句,客户端发送给数据库的查询语句):SELECT email FROM userInfo WHERE create_time > ‘2011-11-11’ GROUP BY name order by id desc。

syntax tree:SQL解析后的语法树(略,这是其他独立模块提供的),Fetch select list:扫描语法树,可以发现SELECT查询的列有email,因此,将email存放到SELECT LIST。

Have group:扫描语法树,发现有GROUP关键字,分组列name不存在与SELECT LIST中,因将name放入SELECT LIST中,并且将name附加到查询列后面。

这时候SQL语句为SELECT email, name FROM…,标记分组列name在查询中的位置为1(从左到右,从0开始,email位置为0,name为1)。

Have order扫描语法树,发现有ORDER关键字,排序列为id,该列不在SELECT LIST中,因此将排序列ID附加到查询语句中,查询语句变为SELECT email, name, id FROM … ,标记排序列在查询中的位置为2。

经过一系列处理流程,那么为了实现这次查询,已经将查询重写改写为形成一个新的查询:SELECT email,name, id FROM userInfo WHERE create_time > ‘2011-11-11’ GROUP BY name ORDER BY id DESC。

所得到的信息有:原始查询的列数,改写后的列数,分组列位置,排序列的位置。使用处理后的SQL语句从数据存放点取回数据,根据所得到的信息,依次执行分组,排序,然后再发送的时候,按照原始查询的列数发送数据到客户端。

分库分表后能够支持复杂查询,如GROUP、ORDER等等;数据存储节点参与计算,相比直接把数据全部查询到应用程序中进行计算,具有更小的网络开销,更快的计算速度。

在多机查询中,不需要应用程序参与查询计算;通过关系代数等价变化的方式,重写查询语句,让数据节点参与查询计算的方式,相比常规方案性价比要高。



‘玖’ impala怎么解析sql语句

Impala的SQL解析与执行计划生成部分是由impala-frontend(Java)实现的,监听端口是21000。用户通过Beeswax接口BeeswaxService.query()提交一个请求,在impalad端的处理逻辑是由void ImpalaServer::query(QueryHandle& query_handle, const Query& query)这个函数(在impala-beeswax-server.cc中实现)完成的。
在impala中一条SQL语句先后经历BeeswaxService.Query->TClientRequest->TExecRequest,最后把TExecRequest交由impala-coordinator分发给多个backend处理。本文主要讲一条SQL语句是怎么一步一步变成TExecRequest的。
本文以下内容都以这样的一个SQL为例说明:
select jobinfo.dt,user,
max(taskinfo.finish_time-taskinfo.start_time),
max(jobinfo.finish_time-jobinfo.submit_time)
from taskinfo join jobinfo on jobinfo.jobid=taskinfo.jobid
where jobinfo.job_status='SUCCESS' and taskinfo.task_status='SUCCESS'
group by jobinfo.dt,user

通过调用Status ImpalaServer::GetExecRequest(const TClientRequest& request, TExecRequest* result) 函数把TClientRequest转化成TExecRequest
在这个函数里通过JNI接口调用frontend.createExecRequest()生成TExecRequest。首先调用AnalysisContext.analyze(String stmt)分析提交的SQL语句。
注释:Analyzer对象是个存放这个SQL所涉及到的所有信息(包含Table, conjunct, slot,slotRefMap, eqJoinConjuncts等)的知识库,所有跟这个SQL有关的东西都会存到Analyzer对象里面。
1,SQL的词法分析,语法分析
AnalysisContext.analyze(String stmt)会调用SelectStmt.analyze()函数,这个函数就是对SQL的analyze和向中央知识库Analyzer register各种信息。
(1)处理这个SQL所涉及到的Table(即TableRefs),这些Table是在from从句中提取出来的(包含关键字from, join, on/using)。注意JOIN操作以及on/using条件是存储在参与JOIN操作的右边的表的TableRef中并分析的。依次analyze()每个TableRef,向Analyzer注册registerBaseTableRef(填充TupleDescriptor)。如果对应的TableRef涉及到JOIN操作,还要analyzeJoin()。在analyzeJoin()时会向Analyzer registerConjunct()填充Analyzer的一些成员变量:conjuncts,tuplePredicates(TupleId与conjunct的映射),slotPredicates(SlotId与conjunct的映射),eqJoinConjuncts。本例中on从句是一种BinaryPredicate,然后onClause.analyze(analyzer)会递归analyze这个on从句里的各种组件。
(2)处理select从句(包含关键字select, MAX(), AVG()等聚集函数):分析这个SQL都select了哪几项,每一项都是个Expr类型的子类对象,把这几项填入resultExprs数组和colLabels。然后把resultExprs里面的Expr都递归analyze一下,要分析到树的最底层,向Analyzer注册SlotRef等。
(3)分析where从句(关键字where),首先递归Analyze从句中Expr组成的树,然后向Analyzer registerConjunct()填充Analyzer的一些成员变量(同1,此外还要填充whereClauseConjuncts) 。
(4)处理sort相关信息(关键字order by)。先是解析aliases和ordinals,然后从order by后面的从句中提取Expr填入orderingExprs,接着递归Analyze从句中Expr组成的树,最后创建SortInfo对象。
(5)处理aggregation相关信息(关键字group by, having, avg, max等)。首先递归分析group by从句里的Expr,然后如果有having从句就像where从句一样,先是analyze having从句中Expr组成的树,然后向Analyzer registerConjunct()等。
(6)处理InlineView。
关于SQL解析中所涉及到的各种数据结构表示如下:

至此词法分析,语法分析结束,有点像一个小的编译器。我们现在回到frontend.createExecRequest()函数中。调用完AnalysisContext.analyze()之后,就开始填充TExecRequest内的成员变量。
(1)如果是DDL命令(use, show tables, show databases, describe),那么调用createDdlExecRequest();
(2)另外一种情况就是Query或者DML命令,那么就得创建和填充TQueryExecRequest了。
2,根据SQL语法树生成执行计划(PlanNode和PlanFragment的生成)
下面就是用Planner把SQL解析出的语法树转换成Plan fragments,后者能在各个backend被执行。
Planner planner = new Planner();
ArrayListfragments =
planner.createPlanFragments(analysisResult, request.queryOptions);
这个createPlanFragments()函数是frontend最重要的函数:根据SQL解析的结果和client传入的query options,生成执行计划。执行计划是用PlanFragment的数组表示的,最后会序列化到TQueryExecRequest.fragments然后传给backend的coordinator去调度执行。
下面进入Planner.createPlanFragments()函数看看执行计划是怎么生成的:
首先要搞清楚两个概念:PlanNode和PlanFragment。
PlanNode是SQL解析出来的逻辑功能节点;PlanFragment是真正的执行计划节点。
2.1,创建PlanNode
PlanNode singleNodePlan =
createQueryPlan(queryStmt, analyzer, queryOptions.getDefault_order_by_limit());
(1)这个函数首先根据from从句中的第一个TableRef创建一个PlanNode,一般为ScanNode(HdfsScanNode或者HBaseScanNode)。这个ScanNode关联一个ValueRange的数组(由多个cluster column取值区间组成)表示要读取的Table的范围,还关联一个conjunct(where从句)。
(2)这个SQL语句中TableRef中剩下的其他Table就需要建立HashJoinNode了。进入Planner.createHashJoinNode()函数:首先为这个Table建立ScanNode(同上),然后调用getHashLookupJoinConjuncts()获取两表或者多表JOIN的eqJoinConjuncts和eqJoinPredicates,利用这两个条件创建HashJoinNode。每个HashJoinNode也是树状的,会有孩子节点,对于我们举例的两表JOIN,孩子节点分别是两个表对应的ScanNode。(注意目前impala只支持一大一小两个表的JOIN,默认是左大右小,是通过把右边的小表分发到每个节点的内存中分别于左边大表的一个区间进行JOIN过滤实现的。)
(3)如果有group by从句,创建AggregationNode,并把刚才的HashJoinNode设为它的孩子。这里暂时不考虑DISTINCT aggregation function。
(4)如果有order by… limit从句,创建SortNode。
这样createQueryPlan()函数执行完毕,PlanNode组成的execution tree形成如下:

2.2,创建PlanFragment
接下来就看impala backend节点数目有多少,如果只有一个节点,那么整棵执行树都在同一个impalad上执行;否则调用createPlanFragments(singleNodePlan, isPartitioned, false, fragments)把PlanNode组成的执行树转换成PlanFragment组成的执行计划。
下面进入createPlanFragments()这个函数:
这是一个递归函数,沿着PlanNode组成的执行树递归下去,分别创建对应的Fragment。
(1)如果是ScanNode,创建一个PlanFragment(这个PlanFragment的root node是这个ScanNode,而且这个PlanFragment只包含一个PlanNode)。
(2)如果是HashJoinNode,并不是创建一个新的PlanFragment,而是修改leftChildFragment(是一个ScanNode)为以HashJoinNode作为root node的PlanFragment。因为对于HashJoinNode一般有两个ScanNode孩子,在处理HashJoinNode之前已经把这两个ScanNode变成了对应的PlanFragment。那么此时要得到HashJoinNode作为root node的PlanFragment是通过Planner.createHashJoinFragment()函数完成的:首先把当前HashJoinNode作为HashJoinFragment的root node;然后把leftChildFragment中的root PlanNode(也就是参与JOIN的两个表中左边的那个表对应的ScanNode)作为HashJoinNode的左孩子;通过调用Planner.connectChildFragment()函数把HashJoinNode的右孩子设置为一个ExchangeNode(这个ExchangeNode表示一个1:n的数据流的receiver);同时把rightChildFragment(ScanNode作为root node)的destination设置为这个ExchangeNode。
(3)如果是AggregationNode,聚集操作很复杂了。以我们的例子来说明:如果这个AggregationNode不是DISTINCT aggregation的2nd phase(因为本例中的AggregationNode的孩子是HashJoinNode而不是另外一个AggregationNode),首先把刚才生成的HashJoinNode作为root node对应的PlanFragment的root node设置为该AggregationNode,并把原来的root node(即HashJoinNode)设为新root node的孩子。然后通过Planner.createParentFragment()创建一个包含ExchangeNode作为root node的新的PlanFragment。并把孩子PlanFragment的destination设置为这个ExchangeNode。然后在这个新的PlanFragment中创建一个新的AggregationNode作为新的root node并把刚才的ExchangeNode作为其孩子节点。
至此,createPlanFragments()调用完成,生成的三个PlanFragment如下:

通过createPlanFragments(singleNodePlan, isPartitioned, false, fragments)获取了所以执行计划PlanFragment组成的数组fragments,这个数组的最后一个元素就是根节点PlanFragment。然后就是调用PlanFragment.finalize()把这个执行计划finalize(递归finalize每个PlanNode)同时为每个PlanFragment指定 DataStreamSink。
然后回到frontend.createExecRequest()函数中。执行完Planner.createPlanFragments()返回的ArrayList就是完整的执行计划了。然后就是一次调用PlanFragment.toThrift()把它序列化到TQueryExecRequest。填充TQueryExecRequest的相关变量:dest_fragment_idx,per_node_scan_ranges,query_globals,result_set_metadata等。最后返回TExecRequest型的对象给backend执行。