SQL 语句
SQL 语法
FROM、SELECT 和 WHERE 子句:
规则引擎的 SQL 语句基本格式为:
SELECT <字段名> FROM <主题> [WHERE <条件>]
FROM
子句将规则挂载到某个主题上SELECT
子句用于对数据进行变换,并选择出感兴趣的字段WHERE
子句用于对 SELECT 选择出来的某个字段施加条件过滤
FOREACH、DO 和 INCASE 子句:
如果对于一个数组数据,想针对数组中的每个元素分别执行一些操作并执行 Actions,需要使用 FOREACH-DO-INCASE
语法。其基本格式为:
FOREACH <字段名> [DO <条件>] [INCASE <条件>] FROM <主题> [WHERE <条件>]
FOREACH
子句用于选择需要做 foreach 操作的字段,注意选择出的字段必须为数组类型DO
子句用于对 FOREACH 选择出来的数组中的每个元素进行变换,并选择出感兴趣的字段INCASE
子句用于对 DO 选择出来的某个字段施加条件过滤
其中 DO 和 INCASE 子句都是可选的。DO 相当于针对当前循环中对象的 SELECT 子句,而 INCASE 相当于针对当前循环中对象的 WHERE 语句。
事件和事件主题
规则引擎的 SQL 语句既可以处理消息(消息发布),也可以处理事件(客户端上下线、客户端订阅等)。对于消息,FROM 子句后面直接跟主题名;对于事件,FROM 子句后面跟事件主题。
事件消息的主题以 "$events/"
开头,比如 "$events/client_connected",
"$events/session_subscribed"。
如果想让 emqx 将事件消息发布出来,可以在 emqx_rule_engine.conf
文件中配置。
所有支持的事件及其可用字段详见: 规则事件。
SQL 语句示例:
基本语法举例
- 从 topic 为 “t/a” 的消息中提取所有字段:
SELECT * FROM "t/a"
- 从 topic 为 “t/a” 或 “t/b” 的消息中提取所有字段:
SELECT * FROM "t/a","t/b"
- 从 topic 能够匹配到 ‘t/#’ 的消息中提取所有字段。
SELECT * FROM "t/#"
- 从 topic 能够匹配到 ‘t/#’ 的消息中提取 qos, username 和 clientid 字段:
SELECT qos, username, clientid FROM "t/#"
- 从任意 topic 的消息中提取 username 字段,并且筛选条件为 username = ‘Steven’:
SELECT username FROM "#" WHERE username='Steven'
- 从任意 topic 的 JSON 消息体(payload) 中提取 x 字段,并创建别名 x 以便在 WHERE 子句中使用。WHERE 子句限定条件为 x = 1。下面这个 SQL 语句可以匹配到消息体 {“x”: 1}, 但不能匹配到消息体 {“x”: 2}:
SELECT payload as p FROM "#" WHERE p.x = 1
- 类似于上面的 SQL 语句,但嵌套地提取消息体中的数据,下面的 SQL 语句可以匹配到 JSON 消息体 {“x”: {“y”: 1}}:
SELECT payload as a FROM "#" WHERE a.x.y = 1
- 在 clientid = ‘c1’ 尝试连接时,提取其来源 IP 地址和端口号:
SELECT peername as ip_port FROM "$events/client_connected" WHERE clientid = 'c1'
- 筛选所有订阅 ‘t/#’ 主题且订阅级别为 QoS1 的 clientid:
SELECT clientid FROM "$events/session_subscribed" WHERE topic = 't/#' and qos = 1
- 筛选所有订阅主题能匹配到 ‘t/#’ 且订阅级别为 QoS1 的 clientid。注意与上例不同的是,这里用的是主题匹配操作符 ‘=~’,所以会匹配订阅 ‘t’ 或 ‘t/+/a’ 的订阅事件:
SELECT clientid FROM "$events/session_subscribed" WHERE topic =~ 't/#' and qos = 1
TIP
- FROM 子句后面的主题需要用双引号
""
引起来。 - WHERE 子句后面接筛选条件,如果使用到字符串需要用单引号
''
引起来。 - FROM 子句里如有多个主题,需要用逗号
","
分隔。例如 SELECT * FROM “t/1”, “t/2” 。 - 可以使用使用
"."
符号对 payload 进行嵌套选择。
遍历语法(FOREACH-DO-INCASE) 举例
假设有 ClientID 为 c_steve
、主题为 t/1
的消息,消息体为 JSON 格式,其中 sensors 字段为包含多个 Object 的数组:
{
"date": "2020-04-24",
"sensors": [
{"name": "a", "idx":0},
{"name": "b", "idx":1},
{"name": "c", "idx":2}
]
}
示例1: 要求将 sensors 里的各个对象,分别作为数据输入重新发布消息到 sensors/${idx}
主题,内容为 ${name}
。即最终规则引擎将会发出 3 条消息:
- 主题:sensors/0 内容:a
- 主题:sensors/1 内容:b
- 主题:sensors/2 内容:c
要完成这个规则,我们需要配置如下动作:
- 动作类型:消息重新发布 (republish)
- 目的主题:sensors/${idx}
- 目的 QoS:0
- 消息内容模板:${name}
以及如下 SQL 语句:
FOREACH
payload.sensors
FROM "t/#"
示例解析:
这个 SQL 中,FOREACH 子句指定需要进行遍历的数组 sensors,则选取结果为:
[
{
"name": "a",
"idx": 0
},
{
"name": "b",
"idx": 1
},
{
"name": "c",
"idx": 2
}
]
FOREACH 语句将会对于结果数组里的每个对象分别执行 “消息重新发布” 动作,所以将会执行重新发布动作 3 次。
示例2: 要求将 sensors 里的 idx
值大于或等于 1 的对象,分别作为数据输入重新发布消息到 sensors/${idx}
主题,内容为 clientid=${clientid},name=${name},date=${date}
。即最终规则引擎将会发出 2 条消息:
- 主题:sensors/1 内容:clientid=c_steve,name=b,date=2020-04-24
- 主题:sensors/2 内容:clientid=c_steve,name=c,date=2020-04-24
要完成这个规则,我们需要配置如下动作:
- 动作类型:消息重新发布 (republish)
- 目的主题:sensors/${idx}
- 目的 QoS:0
- 消息内容模板:clientid=${clientid},name=${name},date=${date}
以及如下 SQL 语句:
FOREACH
payload.sensors
DO
clientid,
item.name as name,
item.idx as idx
INCASE
item.idx >= 1
FROM "t/#"
示例解析:
这个 SQL 中,FOREACH 子句指定需要进行遍历的数组 sensors
; DO 子句选取每次操作需要的字段,这里我们选了外层的 clientid
字段,以及当前 sensor 对象的 name
和 idx
两个字段,注意 item
代表 sensors 数组中本次循环的对象。INCASE 子句是针对 DO 语句中字段的筛选条件,仅仅当 idx >= 1 满足条件。所以 SQL 的选取结果为:
[
{
"name": "b",
"idx": 1,
"clientid": "c_emqx"
},
{
"name": "c",
"idx": 2,
"clientid": "c_emqx"
}
]
FOREACH 语句将会对于结果数组里的每个对象分别执行 “消息重新发布” 动作,所以将会执行重新发布动作 2 次。
在 DO 和 INCASE 语句里,可以使用 item
访问当前循环的对象,也可以通过在 FOREACH 使用 as
语法自定义一个变量名。所以本例中的 SQL 语句又可以写为:
FOREACH
payload.sensors as s
DO
clientid,
s.name as name,
s.idx as idx
INCASE
s.idx >= 1
FROM "t/#"
示例3: 在示例2 的基础上,去掉 clientid 字段 c_steve
中的 c_
前缀
在 FOREACH 和 DO 语句中可以调用各类 SQL 函数,若要将 c_steve
变为 steve
,则可以把例2 中的 SQL 改为:
FOREACH
payload.sensors as s
DO
nth(2, tokens(clientid,'_')) as clientid,
s.name as name,
s.idx as idx
INCASE
s.idx >= 1
FROM "t/#"
另外,FOREACH 子句中也可以放多个表达式,只要最后一个表达式是指定要遍历的数组即可。比如我们将消息体改一下,sensors 外面多套一层 Object:
{
"date": "2020-04-24",
"data": {
"sensors": [
{"name": "a", "idx":0},
{"name": "b", "idx":1},
{"name": "c", "idx":2}
]
}
}
则 FOREACH 中可以在决定要遍历的数组之前把 data 选取出来:
FOREACH
payload.data as data
data.sensors as s
...
CASE-WHEN 语法示例
示例1: 将消息中 x 字段的值范围限定在 0~7 之间。
SELECT
CASE WHEN payload.x < 0 THEN 0
WHEN payload.x > 7 THEN 7
ELSE payload.x
END as x
FROM "t/#"
假设消息为:
{"x": 8}
则上面的 SQL 输出为:
{"x": 7}
FROM 子句可用的事件主题
事件主题名 | 释义 |
---|---|
$events/message_delivered | 消息投递 |
$events/message_acked | 消息确认 |
$events/message_dropped | 消息丢弃 |
$events/client_connected | 连接完成 |
$events/client_disconnected | 连接断开 |
$events/session_subscribed | 订阅 |
$events/session_unsubscribed | 取消订阅 |
SELECT 和 WHERE 子句可用的字段
SELECT 和 WHERE 子句可用的字段与事件的类型相关。其中 clientid
, username
和 event
是通用字段,每种事件类型都有。
普通主题 (消息发布)
event | 事件类型,固定为 “message.publish” |
---|---|
id | MQTT 消息 ID |
clientid | Client ID |
username | 用户名 |
payload | MQTT 消息体 |
peerhost | 客户端的 IPAddress |
topic | MQTT 主题 |
qos | MQTT 消息的 QoS |
flags | MQTT 消息的 Flags |
headers | MQTT 消息内部与流程处理相关的额外数据 |
timestamp | 事件触发时间 (ms) |
publish_received_at | PUBLISH 消息到达 Broker 的时间 (ms) |
node | 事件触发所在节点 |
$events/message_delivered (消息投递)
event | 事件类型,固定为 “message.delivered” |
---|---|
id | MQTT 消息 ID |
from_clientid | 消息来源 Client ID |
from_username | 消息来源用户名 |
clientid | 消息目的 Client ID |
username | 消息目的用户名 |
payload | MQTT 消息体 |
peerhost | 客户端的 IPAddress |
topic | MQTT 主题 |
qos | MQTT 消息的 QoS |
flags | MQTT 消息的 Flags |
timestamp | 事件触发时间 (ms) |
publish_received_at | PUBLISH 消息到达 Broker 的时间 (ms) |
node | 事件触发所在节点 |
$events/message_acked (消息确认)
event | 事件类型,固定为 “message.acked” |
---|---|
id | MQTT 消息 ID |
from_clientid | 消息来源 Client ID |
from_username | 消息来源用户名 |
clientid | 消息目的 Client ID |
username | 消息目的用户名 |
payload | MQTT 消息体 |
peerhost | 客户端的 IPAddress |
topic | MQTT 主题 |
qos | MQTT 消息的 QoS |
flags | MQTT 消息的 Flags |
timestamp | 事件触发时间 (ms) |
publish_received_at | PUBLISH 消息到达 Broker 的时间 (ms) |
node | 事件触发所在节点 |
$events/message_dropped (消息丢弃)
event | 事件类型,固定为 “message.dropped” |
---|---|
id | MQTT 消息 ID |
reason | 消息丢弃原因 |
clientid | 消息目的 Client ID |
username | 消息目的用户名 |
payload | MQTT 消息体 |
peerhost | 客户端的 IPAddress |
topic | MQTT 主题 |
qos | MQTT 消息的 QoS |
flags | MQTT 消息的 Flags |
timestamp | 事件触发时间 (ms) |
publish_received_at | PUBLISH 消息到达 Broker 的时间 (ms) |
node | 事件触发所在节点 |
$events/client_connected (终端连接成功)
event | 事件类型,固定为 “client.connected” |
---|---|
clientid | 消息目的 Client ID |
username | 消息目的用户名 |
mountpoint | 主题挂载点(主题前缀) |
peername | 终端的 IPAddress 和 Port |
sockname | emqx 监听的 IPAddress 和 Port |
proto_name | 协议名字 |
proto_ver | 协议版本 |
keepalive | MQTT 保活间隔 |
clean_start | MQTT clean_start |
expiry_interval | MQTT Session 过期时间 |
is_bridge | 是否为 MQTT bridge 连接 |
connected_at | 终端连接完成时间 (s) |
timestamp | 事件触发时间 (ms) |
node | 事件触发所在节点 |
$events/client_disconnected (终端连接断开)
event | 事件类型,固定为 “client.disconnected” |
---|---|
reason | 终端连接断开原因 |
clientid | 消息目的 Client ID |
username | 消息目的用户名 |
peername | 终端的 IPAddress 和 Port |
sockname | emqx 监听的 IPAddress 和 Port |
disconnected_at | 终端连接断开时间 (s) |
timestamp | 事件触发时间 (ms) |
node | 事件触发所在节点 |
$events/session_subscribed (终端订阅成功)
event | 事件类型,固定为 “session.subscribed” |
---|---|
clientid | 消息目的 Client ID |
username | 消息目的用户名 |
peerhost | 客户端的 IPAddress |
topic | MQTT 主题 |
qos | MQTT 消息的 QoS |
timestamp | 事件触发时间 (ms) |
node | 事件触发所在节点 |
$events/session_unsubscribed (取消终端订阅成功)
event | 事件类型,固定为 “session.unsubscribed” |
---|---|
clientid | 消息目的 Client ID |
username | 消息目的用户名 |
peerhost | 客户端的 IPAddress |
topic | MQTT 主题 |
qos | MQTT 消息的 QoS |
timestamp | 事件触发时间 (ms) |
node | 事件触发所在节点 |
SQL 关键字和符号
SELECT - FROM - WHERE 语句
SELECT 语句用于决定最终的输出结果里的字段。比如:
下面 SQL 的输出结果中将只有两个字段 “a” 和 “b”:
SELECT a, b FROM "t/#"
WHERE 语句用于对本事件中可用字段,或 SELECT 语句中定义的字段进行条件过滤。比如:
# 选取 username 为 'abc' 的终端发来的消息,输出结果为所有可用字段:
SELECT * FROM "#" WHERE username = 'abc'
## 选取 clientid 为 'abc' 的终端发来的消息,输出结果将只有 cid 一个字段。
## 注意 cid 变量是在 SELECT 语句中定义的,故可在 WHERE 语句中使用:
SELECT clientid as cid FROM "#" WHERE cid = 'abc'
## 选取 username 为 'abc' 的终端发来的消息,输出结果将只有 cid 一个字段。
## 注意虽然 SELECT 语句中只选取了 cid 一个字段,所有消息发布事件中的可用字段 (比如 clientid, username 等) 仍然可以在 WHERE 语句中使用:
SELECT clientid as cid FROM "#" WHERE username = 'abc'
## 但下面这个 SQL 语句就不能工作了,因为变量 xyz 既不是消息发布事件中的可用字段,又没有在 SELECT 语句中定义:
SELECT clientid as cid FROM "#" WHERE xyz = 'abc'
FROM 语句用于选择事件来源。如果是消息发布则填写消息的主题,如果是事件则填写对应的事件主题。
运算符号
函数名 | 函数作用 | 返回值 | |
---|---|---|---|
+ | 加法,或字符串拼接 | 加和,或拼接之后的字符串 | |
- | 减法 | 差值 | |
* | 乘法 | 乘积 | |
/ | 除法 | 商值 | |
div | 整数除法 | 整数商值 | |
mod | 取模 | 模 | |
= | 比较两者是否完全相等。可用于比较变量和主题 | true/false | |
=~ | 比较主题(topic)是否能够匹配到主题过滤器(topic filter)。只能用于主题匹配 | true/false |
SQL 语句中可用的函数
数学函数
函数名 | 函数作用 | 参数 | 返回值 |
abs | 绝对值 |
| 绝对值 |
cos | 余弦 |
| 余弦值 |
cosh | 双曲余弦 |
| 双曲余弦值 |
acos | 反余弦 |
| 反余弦值 |
acosh | 反双曲余弦 |
| 反双曲余弦值 |
sin | 正弦 |
| 正弦值 |
sinh | 双曲正弦 |
| 双曲正弦值 |
asin | 反正弦 |
| 值 |
asinh | 反双曲正弦 |
| 反双曲正弦值 |
tan | 正切 |
| 正切值 |
tanh | 双曲正切 |
| 双曲正切值 |
atan | 反正切 |
| 反正切值 |
atanh | 反双曲正切 |
| 反双曲正切值 |
ceil | 上取整 |
| 整数值 |
floor | 下取整 |
| 整数值 |
round | 四舍五入 |
| 整数值 |
exp | 幂运算 |
| e 的 x 次幂 |
power | 指数运算 |
| x 的 y 次方 |
sqrt | 平方根运算 |
| 平方根 |
fmod | 负点数取模函数 |
| 模 |
log | 以 e 为底对数 |
| 值 |
log10 | 以 10 为底对数 |
| 值 |
log2 | 以 2 为底对数 |
| 值 |
数据类型判断函数
函数名 | 函数作用 | 参数 | 返回值 |
is_null | 判断变量是否为空值 |
| Boolean 类型的数据。如果为空值(undefined) 则返回 true,否则返回 false |
is_not_null | 判断变量是否为非空值 |
| Boolean 类型的数据。如果为空值(undefined) 则返回 false,否则返回 true |
is_str | 判断变量是否为 String 类型 |
| Boolean 类型的数据。 |
is_bool | 判断变量是否为 Boolean 类型 |
| Boolean 类型的数据。 |
is_int | 判断变量是否为 Integer 类型 |
| Boolean 类型的数据。 |
is_float | 判断变量是否为 Float 类型 |
| Boolean 类型的数据。 |
is_num | 判断变量是否为数字类型,包括 Integer 和 Float 类型 |
| Boolean 类型的数据。 |
is_map | 判断变量是否为 Map 类型 |
| Boolean 类型的数据。 |
is_array | 判断变量是否为 Array 类型 |
| Boolean 类型的数据。 |
数据类型转换函数
函数名 | 函数作用 | 参数 | 返回值 |
str | 将数据转换为 String 类型 |
| String 类型的数据。无法转换将会导致 SQL 匹配失败 |
str_utf8 | 将数据转换为 UTF-8 String 类型 |
| UTF-8 String 类型的数据。无法转换将会导致 SQL 匹配失败 |
bool | 将数据转换为 Boolean 类型 |
| Boolean 类型的数据。无法转换将会导致 SQL 匹配失败 |
int | 将数据转换为整数类型 |
| 整数类型的数据。无法转换将会导致 SQL 匹配失败 |
float | 将数据转换为浮点型类型 |
| 浮点型类型的数据。无法转换将会导致 SQL 匹配失败 |
map | 将数据转换为 Map 类型 |
| Map 类型的数据。无法转换将会导致 SQL 匹配失败 |
字符串函数
函数名 | 函数作用 | 参数 | 返回值 | 举例 |
---|---|---|---|---|
lower | 转为小写 | 1. 原字符串 | 小写字符串 | 1. lower(‘AbC’) = ‘abc’ 2. lower(‘abc’) = ‘abc’ |
upper | 转为大写 | 1. 原字符串 | 大写字符串 | 1. upper(‘AbC’) = ‘ABC’ 2. lower(‘ABC’) = ‘ABC’ |
trim | 去掉左右空格 | 1. 原字符串 | 去掉空格后的字符串 | 1. trim(‘ hello ‘) = ‘hello’ |
ltrim | 去掉左空格 | 1. 原字符串 | 去掉空格后的字符串 | 1. ltrim(‘ hello ‘) = ‘hello ‘ |
rtrim | 去掉右空格 | 1. 原字符串 | 去掉空格后的字符串 | 1. rtrim(‘ hello ‘) = ‘ hello’ |
reverse | 字符串反转 | 1. 原字符串 | 翻转后的字符串 | 1. reverse(‘hello’) = ‘olleh’ |
strlen | 取字符串长度 | 1. 原字符串 | 整数值,字符长度 | 1. strlen(‘hello’) = 5 |
substr | 取字符的子串 | 1. 原字符串 2. 起始位置. 注意: 下标从 0 开始 | 子串 | 1. substr(‘abcdef’, 2) = ‘cdef’ |
substr | 取字符的子串 | 1. 原字符串 2. 起始位置 3. 要取出的子串长度. 注意: 下标从 0 开始 | 子串 | 1. substr(‘abcdef’, 2, 3) = ‘cde’ |
split | 字符串分割 | 1. 原字符串 2. 分割符子串 | 分割后的字符串数组 | 1. split(‘a/b/ c’, ‘/‘) = [‘a’, ‘b’, ‘ c’] |
split | 字符串分割, 只查找左边第一个分隔符 | 1. 原字符串 2. 分割符子串 3. ‘leading’ | 分割后的字符串数组 | 1. split(‘a/b/ c’, ‘/‘, ‘leading’) = [‘a’, ‘b/ c’] |
split | 字符串分割, 只查找右边第一个分隔符 | 1. 原字符串 2. 分割符子串 3. ‘trailing’ | 分割后的字符串数组 | 1. split(‘a/b/ c’, ‘/‘, ‘trailing’) = [‘a/b’, ‘ c’] |
concat | 字符串拼接 | 1. 左字符串 2. 右符子串 | 拼接后的字符串 | 1. concat(‘a’, ‘/bc’) = ‘a/bc’ 2. ‘a’ + ‘/bc’ = ‘a/bc’ |
tokens | 字符串分解(按照指定字符串符分解) | 1. 输入字符串 2. 分割符或字符串 | 分解后的字符串数组 | 1. tokens(‘ a/b/ c’, ‘/‘) = [‘ a’, ‘b’, ‘ c’] 2. tokens(‘ a/b/ c’, ‘/ ‘) = [‘a’, ‘b’, ‘c’] 3. tokens(‘ a/b/ c\n’, ‘/ ‘) = [‘a’, ‘b’, ‘c\n’] |
tokens | 字符串分解(按照指定字符串和换行符分解) | 1. 输入字符串 2. 分割符或字符串 3. ‘nocrlf’ | 分解后的字符串数组 | 1. tokens(‘ a/b/ c\n’, ‘/ ‘, ‘nocrlf’) = [‘a’, ‘b’, ‘c’] 2. tokens(‘ a/b/ c\r\n’, ‘/ ‘, ‘nocrlf’) = [‘a’, ‘b’, ‘c’] |
sprintf | 字符串格式化, 格式字符串的用法详见 https://erlang.org/doc/man/io.html#fwrite-1 里的 Format 部分 | 1. 格式字符串 2,3,4… 参数列表。参数个数不定 | 分解后的字符串数组 | 1. sprintf(‘hello, ~s!’, ‘steve’) = ‘hello, steve!’ 2. sprintf(‘count: ~p~n’, 100) = ‘count: 100\n’ |
pad | 字符串补足长度,补空格,从尾部补足 | 1. 原字符串 2. 字符总长度 | 补足后的字符串 | 1. pad(‘abc’, 5) = ‘abc ‘ |
pad | 字符串补足长度,补空格,从尾部补足 | 1. 原字符串 2. 字符总长度 3. ‘trailing’ | 补足后的字符串 | 1. pad(‘abc’, 5, ‘trailing’) = ‘abc ‘ |
pad | 字符串补足长度,补空格,从两边补足 | 1. 原字符串 2. 字符总长度 3. ‘both’ | 补足后的字符串 | 1. pad(‘abc’, 5, ‘both’) = ‘ abc ‘ |
pad | 字符串补足长度,补空格,从头部补足 | 1. 原字符串 2. 字符总长度 3. ‘leading’ | 补足后的字符串 | 1. pad(‘abc’, 5, ‘leading’) = ‘ abc’ |
pad | 字符串补足长度,补指定字符,从尾部补足 | 1. 原字符串 2. 字符总长度 3. ‘trailing’ 4. 指定用于补足的字符 | 补足后的字符串 | 1. pad(‘abc’, 5, ‘trailing’, ‘‘) = ‘abc**’ 2. pad(‘abc’, 5, ‘trailing’, ‘ #’) = ‘abc##’ |
pad | 字符串补足长度,补指定字符,从两边补足 | 1. 原字符串 2. 字符总长度 3. ‘both’ 4. 指定用于补足的字符 | 补足后的字符串 | 1. pad(‘abc’, 5, ‘both’, ‘‘) = ‘abc‘ 2. pad(‘abc’, 5, ‘both’, ‘ #’) = ‘#abc#’ |
pad | 字符串补足长度,补指定字符,从头部补足 | 1. 原字符串 2. 字符总长度 3. ‘leading’ 4. 指定用于补足的字符 | 补足后的字符串 | 1. pad(‘abc’, 5, ‘leading’, ‘‘) = ‘**abc’ 2. pad(‘abc’, 5, ‘leading’, ‘ #’) = ‘##abc’ |
replace | 替换字符串中的某子串,查找所有匹配子串替换 | 1. 原字符串 2. 要被替换的子串 3. 指定用于替换的字符串 | 替换后的字符串 | 1. replace(‘ababef’, ‘ab’, ‘cd’) = ‘cdcdef’ |
replace | 替换字符串中的某子串,查找所有匹配子串替换 | 1. 原字符串 2. 要被替换的子串 3. 指定用于替换的字符串 4. ‘all’ | 替换后的字符串 | 1. replace(‘ababef’, ‘ab’, ‘cd’, ‘all’) = ‘cdcdef’ |
replace | 替换字符串中的某子串,从尾部查找第一个匹配子串替换 | 1. 原字符串 2. 要被替换的子串 3. 指定用于替换的字符串 4. ‘trailing’ | 替换后的字符串 | 1. replace(‘ababef’, ‘ab’, ‘cd’, ‘trailing’) = ‘abcdef’ |
replace | 替换字符串中的某子串,从头部查找第一个匹配子串替换 | 1. 原字符串 2. 要被替换的子串 3. 指定用于替换的字符串 4. ‘leading’ | 替换后的字符串 | 1. replace(‘ababef’, ‘ab’, ‘cd’, ‘leading’) = ‘cdabef’ |
regex_match | 判断字符串是否与某正则表达式匹配 | 1. 原字符串 2. 正则表达式 | true 或 false | 1. regex_match(‘abc123’, ‘[a-zA-Z1-9]*’) = true |
regex_replace | 替换字符串中匹配到某正则表达式的子串 | 1. 原字符串 2. 正则表达式 3. 指定用于替换的字符串 | 替换后的字符串 | 1. regex_replace(‘ab1cd3ef’, ‘[1-9]’, ‘[&]’) = ‘ab[1]cd[3]ef’ 2. regex_replace(‘ccefacef’, ‘c+’, ‘:’) = ‘:efa:ef’ |
ascii | 返回字符对应的 ASCII 码 | 1. 字符 | 整数值,字符对应的 ASCII 码 | 1. ascii(‘a’) = 97 |
find | 查找并返回字符串中的某个子串,从头部查找 | 1. 原字符串 2. 要查找的子串 | 查抄到的子串,如找不到则返回空字符串 | 1. find(‘eeabcabcee’, ‘abc’) = ‘abcabcee’ |
find | 查找并返回字符串中的某个子串,从头部查找 | 1. 原字符串 2. 要查找的子串 3. ‘leading’ | 查抄到的子串,如找不到则返回空字符串 | 1. find(‘eeabcabcee’, ‘abc’, ‘leading’) = ‘abcabcee’ |
find | 查找并返回字符串中的某个子串,从尾部查找 | 1. 原字符串 2. 要查找的子串 3. ‘trailing’ | 查抄到的子串,如找不到则返回空字符串 | 1. find(‘eeabcabcee’, ‘abc’, ‘trailing’) = ‘abcee’ |
Map 函数
函数名 | 函数作用 | 参数 | 返回值 |
map_get | 取 Map 中某个 Key 的值,如果没有则返回空值 |
| Map 中某个 Key 的值。支持嵌套的 Key,比如 “a.b.c” |
map_get | 取 Map 中某个 Key 的值,如果没有则返回指定默认值 |
| Map 中某个 Key 的值。支持嵌套的 Key,比如 “a.b.c” |
map_put | 向 Map 中插入值 |
| 插入后的 Map。支持嵌套的 Key,比如 “a.b.c” |
数组函数
函数名 | 函数作用 | 参数 | 返回值 |
nth | 取第 n 个元素,下标从 1 开始 |
| 第 n 个元素 |
length | 获取数组的长度 |
| 数组长度 |
sublist | 取从第一个元素开始、长度为 len 的子数组。下标从 1 开始 |
| 子数组 |
sublist | 取从第 n 个元素开始、长度为 len 的子数组。下标从 1 开始 |
| 子数组 |
first | 取第 1 个元素。下标从 1 开始 |
| 第 1 个元素 |
last | 取最后一个元素。 |
| 最后一个元素 |
contains | 判断数据是否在数组里面 |
| Boolean 值 |
哈希函数
函数名 | 函数作用 | 参数 | 返回值 |
md5 | 求 MD5 值 |
| MD5 值 |
sha | 求 SHA 值 |
| SHA 值 |
sha256 | 求 SHA256 值 |
| SHA256 值 |
编解码函数
函数名 | 函数作用 | 参数 | 返回值 |
base64_encode | BASE64 编码 |
| BASE64 字符串 |
base64_decode | BASE64 解码 |
| 数据 |
json_encode | JSON 编码 |
| 内部 Map |
json_decode | JSON 解码 |
| JSON 字符串 |
schema_encode | Schema 编码 |
| 数据 |
schema_encode | Schema 编码 |
| 数据 |
schema_decode | Schema 解码 |
| 内部 Map |
schema_decode | Schema 解码 |
| 内部 Map |
在 Dashboard 中测试 SQL 语句
Dashboard 界面提供了 SQL 语句测试功能,通过给定的 SQL 语句和事件参数,展示 SQL 测试结果。
在创建规则界面,输入 规则SQL,并启用 SQL 测试 开关:
修改模拟事件的字段,或者使用默认的配置,点击 测试 按钮:
SQL 处理后的结果将在 测试输出 文本框里展示: