更新时间:2023-01-10 GMT+08:00

语法文档

符号约定

本节把需要原样输入的单词用大写表示,需要原样输入的字符用单引号括起来。

'[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