语法文档
符号约定
本节把需要原样输入的单词用大写表示,需要原样输入的字符用单引号括起来。
'[x]'表示语句'x'可以出现一次或不出现。
'(x)'表示语句'x'是个整体。'(x, ...)'表示语句'x'可以出现一次或多次,多次之间用逗号连接。
'|'表示所有可能的替代情况。
'expression'表示任意表达式。特殊地,'bool_expression'表示任意布尔表达式。
'identifier'表示一个合法的标识符。由字符'0-9,a-z,A-Z,_'组成,且不能以数字开头。
'column_name'表示一个合法的字段名。它可以是一个'identifier'或多个嵌套,如'A.id'。
'table_name'表示一个合法的表名。ResourceQL语法规定'table_name'必须为'resources'。
用双引号括起来的单位会被认为是一个整体。例如,若需表示带有特殊字符的列名,需在其前后加双引号。
查询的基本语法
[WITH (with_item, ...)] SELECT [DISTINCT | ALL] (select_item, ...) [FROM (from_item, ...)] [WHERE bool_expression] [GROUP BY [DISTINCT | ALL] (expression, ...)] [HAVING booleanExpression] [ORDER BY (expression [ASC | DESC] [NULLS (FIRST | LAST)], ...)] [LIMIT number]
'select_item'支持对字段名进行重命名和运算,也支持全选。
select_item = (expression [[AS] column_name_aias]) | *
'from_item'支持join函数和嵌套子查询,且支持对表名进行重命名。
from_item = table_name [[AS] table_name_aias] | (from_item join_type from_item [(ON bool_expression) | USING(column_name, ...)]) | '(' query ')'
'with_item'用来定制模板化询问,以方便后续多次调用。
with_item = identifier AS '(' query ')'
例如,查询每个区域内数量大于100的资源类型,可以使用如下语句:
WITH counts AS ( SELECT region_id, provider, type, count(*) AS number FROM resources GROUP BY region_id, provider, type ) SELECT * FROM counts WHERE number > 100
数值运算和布尔运算
ResourceQL支持对整型和浮点型进行二元数学运算,运算符包括'+,-,*,/,%'。
相同类型的值之间可以比较,比较符包括'<,>,<=,>=,=,<>,!='(最后两个符号都表示“不等于”)。数值之间比的是大小,字符串之间比的是字典序。数值和集合之间也可以进行比较,此时比较符右侧为'ALL | SOME | ANY'中的一种,用来限定比较范围。'ALL'表示集合里所有元素都要满足,'SOME/ANY'表示至少一个元素满足即可。
expression ('=' | '<>' | '!=' | '<' | '>' | '<=' | '>=') expression expression ('=' | '<>' | '!=' | '<' | '>' | '<=' | '>=') [ALL | SOME | ANY] '(' query ')'
'bool_expression'表示任意布尔表达式(运算后返回True或False),包括以下几种语法:
NOT bool_expression bool_expression (AND | OR) bool_expression expression [NOT] BETWEEN expression AND expression expression [NOT] IN '(' query ')' EXISTS '(' query ')' expression [NOT] LIKE pattern [ESCAPE escape_characters] expression IS [NOT] NULL expression IS [NOT] DISTINCT FROM expression
特别地,运算符'||'会对左右两边的值进行连接并返回连接后的新值,左右两侧类型相同且均为数组或字符串。
时间类型
ResourceQL支持查询时间类型的字段。查询结果会折算成零时区并以ISODate的标准格式返回,保留至毫秒。
时间类型可以用比较运算符连接。如果想使用表示时间的字面量,请写作timestamp 'time'的形式。其中的'time'可以是任意的ISODate格式或者常用时间格式。以下的'time'写法都是被允许的。
2019-06-17T12:55:42.233Z
2019-06-17T12:55:42Z
2019-06-17 12:55:42
2019-06-17T12:55:42.00 + 08:00
2019-06-17 05:55:40 - 06:00
2019-06-17
2019
如果不加时区则默认为零时区,不加24小时时刻则默认为0:00,不加月份则默认为1月1日。
例如,把2020年9月12日12:55:00以来创建的资源按更新时间降序排序,可以使用如下语句:
select name, created, updated from resources where created >= timestamp '2020-09-12T12:55:00Z' order by updated DESC
模糊查询
string LIKE pattern [ESCAPE escape_characters]
'LIKE'用来判断字符串是否符合某种pattern。如果pattern里想表达'%'或者'_'这两种字符的字面量,可以在'ESCAPE'后指定转义符(如'#'),在pattern里写成'#%'和'#_'即可。
通配符'%'表示匹配0或多个字符。
通配符'_'表示正好匹配一个字符。
对象存储桶的模糊查询,可以写成如下形式:
SELECT name, id FROM resources WHERE provider = 'obs' AND type = 'buckets' AND name LIKE '%figure%'
或
SELECT name, id FROM resources WHERE provider = 'obs' AND type = 'buckets' AND name LIKE '%figure#_%' ESCAPE '#'
条件函数
CASE关键字可以根据情况选择不同的返回值。它有以下两种用法。
- 计算给定表达式expression的值,根据不同的值返回对应的结果。
- 依次计算每一个bool_expression的值,找到第一条符合要求的expression并返回对应的结果。
CASE expression WHEN value1 THEN result1 [WHEN value2 THEN result2] [...] [ELSE result] END CASE WHEN condition1 THEN result1 WHEN condition2 THEN result2 [...] [ELSE result] END
IF关键字的用法有以下两种。
- 'IF(bool_expression, value)':如果布尔表达式值为真就返回'value',否则返回NULL。
- 'IF(bool_expression, value1, value2)':如果布尔表达式值为真就返回'value1',否则返回 'value2'。
用函数来简化查询
ResourceQL提供丰富的函数来简化查询。详细函数说明请参见函数列表。
ResourceQL支持lambda表达式。某些函数的参数可能是另一个函数,此时用lambda表达式就很方便。
例如,查询与所有ECS关联的EVS,可以使用如下的语句:
SELECT ECS.id AS ecs_id, EVS.id AS evs_id FROM (SELECT id, transform(properties.ExtVolumesAttached, x -> x.id) AS evs_list FROM resources WHERE provider = 'ecs' AND type = 'cloudservers') ECS (SELECT id FROM resources WHERE provider = 'evs' AND type = 'volumes') EVS WHERE contains(ecs.evs_list, evs.id)
其中'contains(a, element) →boolean':可以判断某元素是否出现在数组a中。
'transform(array(T), function(T, S))→array(S)'能够把某个类型的数组变换成另一个类型的数组。
Join和Unnest
ResourceQL支持'JOIN'和'UNNEST'。'JOIN'分为以下四种类型。
- [INNER] JOIN
- LEFT [OUTER] JOIN
- RIGHT [OUTER] JOIN
- FULL [OUTER] JOIN
'JOIN'后需紧跟'USING(...)'或'ON <bool_expression>'。
'USING'用来指定参与join的若干个列名。
'ON'接受一个布尔表达式,若值为真则合并。出于性能考虑,布尔表达式的合取范式里需保证至少有一个等式,且该等式左右两端的运算内容被左右两张表独立提供。
'JOIN'前可以冠上'NATURAL'关键词表示自然连接,这样后面不用'USING'或'ON'连接。
'UNNEST'能把数组解包成表,加上'WITH ORDINALITY'会有一个自动计数的列,格式如下:
table_name CROSS JOIN UNNEST '(' (expression, ...) ')' [WITH ORDINALITY]
注意,'CROSS JOIN'只能用于和 'UNNEST'连接,ResourceQL不支持其他格式的'CROSS JOIN'。
上述查询ECS和EVS关联的例子还可以写成如下形式:
SELECT ECS_EVS.id AS ecs_id, EVS.id AS evs_id FROM (SELECT id, evs_id FROM (SELECT id, transform(properties.ExtVolumesAttached, x ->x.id) AS evs_list FROM resources WHERE provider = 'ecs' AND type = 'cloudservers') ECS CROSS JOIN UNNEST(evs_list) AS t (evs_id)) ECS_EVS, (SELECT id FROM resources WHERE provider = 'evs' AND type = 'volumes') EVS WHERE ECS_EVS.evs_id = EVS.id