人大金仓KingbaseES数据库SELECT语句

97 阅读4分钟

1概述

simple-select是一条SELECT语句的最核心部分,从simple-select的语法定义可以看出,它由如下子句组成:去除行重复的DISTINCT (标识符opt-distinct)、目标属性(标识符target-list)、 SELECT INTO子句(标识符into-clause)、FROM子句(标识符from-clause)、 WHERE子句(标识符where_clause) 、 CROUP BY子句(标识符group-clause)、HAVING子句(标识符having-clause)和窗口子句(标识符window-clause)。在成功匹配simple-select语法结构后,将创建一个SelectStmt结构体,并将各子句赋值到结构体中相应的字段。

此外, simple-select还可以定义为其他的形式(见文件Gram. y),如VALUES子句、关系表达式以及多个SELECT语句的交并差等,但这些情况最终都会转化成最基本的simple_select形式来处理。而对于simple-select来说,目标属性(标识符target list)、FROM子句(标识符from-clause)、 WHERE子句(标识符where-clause)以及GROUP BY子句(标识符groupclause)是最重要的部分,下面将结合一个具体实例对这些子句的处理加以详细介绍。

1.simple_select:
2.   SELECT opt_distinct target_list
3.   into_clause from_clause where_clause
4.   group_clause having_clause window_clause
5.    {
6.     SelectStmt *n = makeNode(SelectStmt);
7.     n->targetList = $3;
8.     n->intoClause = $4;
9.     n->fromClause = $5;
10.     n->whereClause = $6;
11.     n->groupClause = $7;
12.     n->havingClause = $8;
13.     n->windowClause = $9;
14.     $$ = (Node *)n;
15.    }
16.   | SELECT distinct_clause target_list
17.   into_clause from_clause where_clause
18.   group_clause having_clause window_clause
19.    {
20.     SelectStmt *n = makeNode(SelectStmt);
21.     n->distinctClause = $2;
22.     n->targetList = $3;
23.     n->intoClause = $4;
24.     n->fromClause = $5;
25.     n->whereClause = $6;
26.     n->groupClause = $7;
27.     n->havingClause = $8;
28.     n->windowClause = $9;
29.     $$ = (Node *)n;
30.    }
31.   | values_clause       { $$ = $1; }

2子句

2.1 DISTINCT子句

DISTINCT子句对应语法定义中的标识符opt_distinct。从opt-distinct的语法结构可以看到,它可以匹配DISTINCT, ALL, DISTINCT ON (表达式列表)或者为空,用来决定SELECT语句是否去除重复的行。

当匹配到DISTINCT时, opt_distinct返回一个List,该链表的第一个ListCell的ptr-value字段置为空。

当匹配到DISTINCT ON时, opt_distinct也返回一个List,这个List中包含了跟在DISTINCTON之后的表达式的列表(星号或者表的属性等)。

当匹配到ALL或者空时, opt_distinct返回NIL,表明没有使用DISTINCT。

2.2 目标属性

目标属性是SELECT语句中所要查询的属性列表,对应着语法定义中的标识符targetList, targetList由若干个target_el组成,target_el定义为取别名的表达式、表达式以及“*”等。

1.target_list:
2.   target_el        { $$ = list_make1($1); }
3.   | target_list ',' target_el    { $$ = lappend($1, $3); }
4.  ;
5.
6.target_el: a_expr AS ColLabel
7.    {
8.     $$ = makeNode(ResTarget);
9.     $$->name = $3;
10.     $$->indirection = NIL;
11.     $$->val = (Node *)$1;
12.     $$->location = @1;
13.    }
14.   /*
15.    * We support omitting AS only for column labels that aren't
16.    * any known keyword.  There is an ambiguity against postfix
17.    * operators: is "a ! b" an infix expression, or a postfix
18.    * expression and a column label?  We prefer to resolve this
19.    * as an infix expression, which we accomplish by assigning
20.    * IDENT a precedence higher than POSTFIXOP.
21.    */
22.   | a_expr IDENT
23.    {
24.     $$ = makeNode(ResTarget);
25.     $$->name = $2;
26.     $$->indirection = NIL;
27.     $$->val = (Node *)$1;
28.     $$->location = @1;
29.    }
30.   | a_expr
31.    {
32.     $$ = makeNode(ResTarget);
33.     $$->name = NULL;
34.     $$->indirection = NIL;
35.     $$->val = (Node *)$1;
36.     $$->location = @1;
37.    }
38.   | '*'
39.    {
40.     ColumnRef *n = makeNode(ColumnRef);
41.     n->fields = list_make1(makeNode(A_Star));
42.     n->location = @1;
43.
44.     $$ = makeNode(ResTarget);
45.     $$->name = NULL;
46.     $$->indirection = NIL;
47.     $$->val = (Node *)n;
48.     $$->location = @1;
49.    }
50.  ;

当成功匹配一个targetList时,创建一个ResTarget结构体,该结构体中存储了该属性的全部信息。最终targetList将返回一个由ResTarget构成的List。

file

targetList包括若干ListCell节点,每个节点中的data字段指向结构体ResTarget,用来表示目标属性中的一项。下图展示了目标属性在内存中的组织结构。当目标属性中的某项涉及函数调用时, ResTarget中的字段val会指向结构体FunCall, FunCall的字段funcname存储函数的名称,字段args指向结构体ColumnRef构成的链表,每一个ColumnRef存储了函数调用中所使用到的表的一个属性。如果没有函数调用,则结构体ResTarget中的字段val直接指向结构体ColumnRef,存储该项目标属性所涉及的表的字段(此种情况没有在图中展示)。

file

图1 分析树中目标属性的数据组织结构

2.3 FROM子句

文件gram. y中定义的标识符from_clause表示SELECT语句中的FROM子句, from_clause由FROM关键字和fromList组成。而fromlist则由若干个标识符table_ref组成,每一个table_ref表示FROM子句中用逗号分隔的每个子项,它表示在FROM子句中出现的一个表或者一个子查询。

1.from_clause:
2.   FROM from_list       { $$ = $2; }
3.   | /*EMPTY*/        { $$ = NIL; }
4.  ;
5.
6.from_list:
7.   table_ref        { $$ = list_make1($1); }
8.   | from_list ',' table_ref    { $$ = lappend($1, $3); }
9.  ;
标识符table_ref可以定义为关系表达式、取别名的关系表达式、带括号的SELECT语句、表连接等形式。
由于FROM子句中子项(标识符table_ref的最简单和基本的形式是关系表达式(标识符relation_expr)。因此,下面分析relation_expr的语法定义。
1.relation_expr:
2.   qualified_name
3.    {
4.     /* inheritance query, implicitly */
5.     $$ = $1;
6.     $$->inh = true;
7.     $$->alias = NULL;
8.    }
9.   | qualified_name '*'
10.    {
11.     /* inheritance query, explicitly */
12.     $$ = $1;
13.     $$->inh = true;
14.     $$->alias = NULL;
15.    }
16.   | ONLY qualified_name
17.    {
18.     /* no inheritance */
19.     $$ = $2;
20.     $$->inh = false;
21.     $$->alias = NULL;
22.    }
23.   | ONLY '(' qualified_name ')'
24.    {
25.     /* no inheritance, SQL99-style syntax */
26.     $$ = $3;
27.     $$->inh = false;
28.     $$->alias = NULL;
29.    }
30.  ;
31.
32.
33.relation_expr_list:
34.   relation_expr       { $$ = list_make1($1); }
35.   | relation_expr_list ',' relation_expr { $$ = lappend($1, $3); }
36.  ;

关系表达式relation_expr定义成qualified_name、带ONLY关键字的qualified_name等形式,最后qualified_name定义成relation_name。在成功匹配最终的标识符relation_name后,创建一个RangeVar结构体用来存储该关系的信息。 如图2所示, from_clause子句在分析树中同样被组织成一个List,每一个ListCell中包含一个RangeVar结构(或者其他结构)。

file 图2 分析树中from子句的数据结构

2.4 WHERE子句

WHERE子句中定义的是元组约束信息,对应着语法定义中的标识符where_clause。标识符where_clause定义为关键字WHERE和一个表达式(标识符a_expr)。

1.where_clause:
2.   WHERE a_expr       { $$ = $2; }
3.   | /*EMPTY*/        { $$ NULL; }
4.  ;

由于表达式是递归定义的,因此, A_Expr结构体中字段lexpr和rexpr分别代表操作符的左右两个子表达式,字段A-Expr_kind代表操作的类型。如果该表达式是常量或者属性等(表达式树中的叶子节点),则lexpr和rexpr都为NULL。在WHERE子句中,使用到的表的属性信息用ColumnRef结构体来组织。

2.5 GROUP BY子句

GROUP BY子句的作用是根据所指定的属性进行分组,对应着语法定义中的标识符group_clause, GROUP BY子句的语法结构与WHERE子句非常相似,在此不再详细讨论。Group by子句的语法定义如下:

group_clause:
   GROUP_P BY group_by_list    { $$ = $3; }
   | /*EMPTY*/        { $$ = NIL; }
  ;
expr_list: a_expr
    {
     $$ = list_make1($1);
    }
   | expr_list ',' a_expr
    {
     $$ = lappend($1, $3);
    }
  ;

2.6 HAVING子句和ORDER BY子句

HAVING子句的作用是根据指定的条件对GROUP BY的分组进行过滤,对应于having_clause标识符。ORDER BY子句的作用是根据指定属性对整个查询的结果进行排序,对应于sort_cluse标识符。Having子句和order by子句的语法定义如下:

1.having_clause:
2.   HAVING a_expr       { $$ = $2; }
3.   | /*EMPTY*/        { $$ = NULL; }
4.  ;
5.sort_clause:
6.   ORDER BY sortby_list     { $$ = $3; }
7.  ;
8.
9.sortby_list:
10.   sortby         { $$ = list_make1($1); }
11.   | sortby_list ',' sortby    { $$ = lappend($1, $3); }
12.  ;
13.
14.sortby:  a_expr USING qual_all_Op opt_nulls_order
15.    {
16.     $$ = makeNode(SortBy);
17.     $$->node = $1;
18.     $$->sortby_dir = SORTBY_USING;
19.     $$->sortby_nulls = $4;
20.     $$->useOp = $3;
21.     $$->location = @3;
22.    }
23.   | a_expr opt_asc_desc opt_nulls_order
24.    {
25.     $$ = makeNode(SortBy);
26.     $$->node = $1;
27.     $$->sortby_dir = $2;
28.     $$->sortby_nulls = $3;
29.     $$->useOp = NIL;
30.     $$->location = -1;  /* no operator */
31.    }
32.  ;

更多信息,参见help.kingbase.com.cn/v8/index.ht…