當前位置:首頁 » 編程語言 » 將語法樹解析成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執行。