IoTDB 为用户提供多种插入实时数据的方式,例如在 Cli/Shell 工具 中直接输入插入数据的 INSERT 语句,或使用 Java API(标准 Java JDBC 接口)单条或批量执行插入数据的 INSERT 语句。
本节主要为您介绍实时数据接入的 INSERT 语句在场景中的实际使用示例,有关 INSERT SQL 语句的详细语法请参见本文 INSERT 语句 节。
使用 INSERT 语句可以向指定的已经创建的一条或多条时间序列中插入数据。对于每一条数据,均由一个时间戳类型的时间戳和一个数值或布尔值、字符串类型的传感器采集值组成。
在本节的场景实例下,以其中的两个时间序列root.ln.wf02.wt02.status和root.ln.wf02.wt02.hardware为例 ,它们的数据类型分别为 BOOLEAN 和 TEXT。
单列数据插入示例代码如下:
IoTDB > insert into root.ln.wf02.wt02(timestamp,status) values(1,true) IoTDB > insert into root.ln.wf02.wt02(timestamp,hardware) values(1, 'v1')
以上示例代码将长整型的 timestamp 以及值为 true 的数据插入到时间序列root.ln.wf02.wt02.status中和将长整型的 timestamp 以及值为”v1”的数据插入到时间序列root.ln.wf02.wt02.hardware中。执行成功后会返回执行时间,代表数据插入已完成。
注意:在 IoTDB 中,TEXT 类型的数据单双引号都可以来表示,上面的插入语句是用的是双引号表示 TEXT 类型数据,下面的示例将使用单引号表示 TEXT 类型数据。
INSERT 语句还可以支持在同一个时间点下多列数据的插入,同时向 2 时间点插入上述两个时间序列的值,多列数据插入示例代码如下:
IoTDB > insert into root.ln.wf02.wt02(timestamp, status, hardware) values (2, false, 'v2')
此外,INSERT 语句支持一次性插入多行数据,同时向 2 个不同时间点插入上述时间序列的值,示例代码如下:
IoTDB > insert into root.ln.wf02.wt02(timestamp, status, hardware) VALUES (3, false, 'v3'),(4, true, 'v4')
插入数据后我们可以使用 SELECT 语句简单查询已插入的数据。
IoTDB > select * from root.ln.wf02 where time < 5
结果如图所示。由查询结果可以看出,单列、多列数据的插入操作正确执行。
+-----------------------------+--------------------------+------------------------+ | Time|root.ln.wf02.wt02.hardware|root.ln.wf02.wt02.status| +-----------------------------+--------------------------+------------------------+ |1970-01-01T08:00:00.001+08:00| v1| true| |1970-01-01T08:00:00.002+08:00| v2| false| |1970-01-01T08:00:00.003+08:00| v3| false| |1970-01-01T08:00:00.004+08:00| v4| true| +-----------------------------+--------------------------+------------------------+ Total line number = 4 It costs 0.170s
本节主要介绍时间切片查询的相关示例,主要使用的是 IoTDB SELECT 语句。同时,您也可以使用 Java JDBC 标准接口来执行相关的查询语句。
SQL 语句为:
select temperature from root.ln.wf01.wt01 where time < 2017-11-01T00:08:00.000
其含义为:
被选择的设备为 ln 集团 wf01 子站 wt01 设备;被选择的时间序列为温度传感器(temperature);该语句要求选择出该设备在“2017-11-01T00:08:00.000”(此处可以使用多种时间格式,详情可参看 2.1 节)时间点以前的所有温度传感器的值。
该 SQL 语句的执行结果如下:
+-----------------------------+-----------------------------+ | Time|root.ln.wf01.wt01.temperature| +-----------------------------+-----------------------------+ |2017-11-01T00:00:00.000+08:00| 25.96| |2017-11-01T00:01:00.000+08:00| 24.36| |2017-11-01T00:02:00.000+08:00| 20.09| |2017-11-01T00:03:00.000+08:00| 20.18| |2017-11-01T00:04:00.000+08:00| 21.13| |2017-11-01T00:05:00.000+08:00| 22.72| |2017-11-01T00:06:00.000+08:00| 20.71| |2017-11-01T00:07:00.000+08:00| 21.45| +-----------------------------+-----------------------------+ Total line number = 8 It costs 0.026s
SQL 语句为:
select status, temperature from root.ln.wf01.wt01 where time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000;
其含义为:
被选择的设备为 ln 集团 wf01 子站 wt01 设备;被选择的时间序列为供电状态(status)和温度传感器(temperature);该语句要求选择出“2017-11-01T00:05:00.000”至“2017-11-01T00:12:00.000”之间的所选时间序列的值。
该 SQL 语句的执行结果如下:
+-----------------------------+------------------------+-----------------------------+ | Time|root.ln.wf01.wt01.status|root.ln.wf01.wt01.temperature| +-----------------------------+------------------------+-----------------------------+ |2017-11-01T00:06:00.000+08:00| false| 20.71| |2017-11-01T00:07:00.000+08:00| false| 21.45| |2017-11-01T00:08:00.000+08:00| false| 22.58| |2017-11-01T00:09:00.000+08:00| false| 20.98| |2017-11-01T00:10:00.000+08:00| true| 25.52| |2017-11-01T00:11:00.000+08:00| false| 22.91| +-----------------------------+------------------------+-----------------------------+ Total line number = 6 It costs 0.018s
IoTDB 支持在一次查询中指定多个时间区间条件,用户可以根据需求随意组合时间区间条件。例如,
SQL 语句为:
select status,temperature from root.ln.wf01.wt01 where (time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000) or (time >= 2017-11-01T16:35:00.000 and time <= 2017-11-01T16:37:00.000);
其含义为:
被选择的设备为 ln 集团 wf01 子站 wt01 设备;被选择的时间序列为“供电状态(status)”和“温度传感器(temperature)”;该语句指定了两个不同的时间区间,分别为“2017-11-01T00:05:00.000 至 2017-11-01T00:12:00.000”和“2017-11-01T16:35:00.000 至 2017-11-01T16:37:00.000”;该语句要求选择出满足任一时间区间的被选时间序列的值。
该 SQL 语句的执行结果如下:
+-----------------------------+------------------------+-----------------------------+ | Time|root.ln.wf01.wt01.status|root.ln.wf01.wt01.temperature| +-----------------------------+------------------------+-----------------------------+ |2017-11-01T00:06:00.000+08:00| false| 20.71| |2017-11-01T00:07:00.000+08:00| false| 21.45| |2017-11-01T00:08:00.000+08:00| false| 22.58| |2017-11-01T00:09:00.000+08:00| false| 20.98| |2017-11-01T00:10:00.000+08:00| true| 25.52| |2017-11-01T00:11:00.000+08:00| false| 22.91| |2017-11-01T16:35:00.000+08:00| true| 23.44| |2017-11-01T16:36:00.000+08:00| false| 21.98| |2017-11-01T16:37:00.000+08:00| false| 21.93| +-----------------------------+------------------------+-----------------------------+ Total line number = 9 It costs 0.018s
该系统支持在一次查询中选择任意列的数据,也就是说,被选择的列可以来源于不同的设备。例如,SQL 语句为:
select wf01.wt01.status,wf02.wt02.hardware from root.ln where (time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000) or (time >= 2017-11-01T16:35:00.000 and time <= 2017-11-01T16:37:00.000);
其含义为:
被选择的时间序列为“ln 集团 wf01 子站 wt01 设备的供电状态”以及“ln 集团 wf02 子站 wt02 设备的硬件版本”;该语句指定了两个时间区间,分别为“2017-11-01T00:05:00.000 至 2017-11-01T00:12:00.000”和“2017-11-01T16:35:00.000 至 2017-11-01T16:37:00.000”;该语句要求选择出满足任意时间区间的被选时间序列的值。
该 SQL 语句的执行结果如下:
+-----------------------------+------------------------+--------------------------+ | Time|root.ln.wf01.wt01.status|root.ln.wf02.wt02.hardware| +-----------------------------+------------------------+--------------------------+ |2017-11-01T00:06:00.000+08:00| false| v1| |2017-11-01T00:07:00.000+08:00| false| v1| |2017-11-01T00:08:00.000+08:00| false| v1| |2017-11-01T00:09:00.000+08:00| false| v1| |2017-11-01T00:10:00.000+08:00| true| v2| |2017-11-01T00:11:00.000+08:00| false| v1| |2017-11-01T16:35:00.000+08:00| true| v2| |2017-11-01T16:36:00.000+08:00| false| v1| |2017-11-01T16:37:00.000+08:00| false| v1| +-----------------------------+------------------------+--------------------------+ Total line number = 9 It costs 0.014s
IoTDB 在 0.11 版本开始支持 ‘order by time’ 语句,用于对结果按照时间进行降序展示。例如,SQL 语句为:
select * from root.ln.** where time > 1 order by time desc limit 10;
语句执行的结果为:
+-----------------------------+--------------------------+------------------------+-----------------------------+------------------------+ | Time|root.ln.wf02.wt02.hardware|root.ln.wf02.wt02.status|root.ln.wf01.wt01.temperature|root.ln.wf01.wt01.status| +-----------------------------+--------------------------+------------------------+-----------------------------+------------------------+ |2017-11-07T23:59:00.000+08:00| v1| false| 21.07| false| |2017-11-07T23:58:00.000+08:00| v1| false| 22.93| false| |2017-11-07T23:57:00.000+08:00| v2| true| 24.39| true| |2017-11-07T23:56:00.000+08:00| v2| true| 24.44| true| |2017-11-07T23:55:00.000+08:00| v2| true| 25.9| true| |2017-11-07T23:54:00.000+08:00| v1| false| 22.52| false| |2017-11-07T23:53:00.000+08:00| v2| true| 24.58| true| |2017-11-07T23:52:00.000+08:00| v1| false| 20.18| false| |2017-11-07T23:51:00.000+08:00| v1| false| 22.24| false| |2017-11-07T23:50:00.000+08:00| v2| true| 23.7| true| +-----------------------------+--------------------------+------------------------+-----------------------------+------------------------+ Total line number = 10 It costs 0.016s
更多语法请参照 SQL REFERENCE.
支持的运算符:+, -
输入数据类型要求:INT32, INT64, FLOAT和 DOUBLE
输出数据类型:与输入数据类型一致
支持的运算符:+, -, *, /, %
输入数据类型要求:INT32, INT64, FLOAT和 DOUBLE
输出数据类型:DOUBLE
注意:当某个时间戳下左操作数和右操作数都不为空(null)时,二元运算操作才会有输出结果
例如:
select s1, - s1, s2, + s2, s1 + s2, s1 - s2, s1 * s2, s1 / s2, s1 % s2 from root.sg.d1
结果:
+-----------------------------+-------------+--------------+-------------+-------------+-----------------------------+-----------------------------+-----------------------------+-----------------------------+-----------------------------+ | Time|root.sg.d1.s1|-root.sg.d1.s1|root.sg.d1.s2|root.sg.d1.s2|root.sg.d1.s1 + root.sg.d1.s2|root.sg.d1.s1 - root.sg.d1.s2|root.sg.d1.s1 * root.sg.d1.s2|root.sg.d1.s1 / root.sg.d1.s2|root.sg.d1.s1 % root.sg.d1.s2| +-----------------------------+-------------+--------------+-------------+-------------+-----------------------------+-----------------------------+-----------------------------+-----------------------------+-----------------------------+ |1970-01-01T08:00:00.001+08:00| 1.0| -1.0| 1.0| 1.0| 2.0| 0.0| 1.0| 1.0| 0.0| |1970-01-01T08:00:00.002+08:00| 2.0| -2.0| 2.0| 2.0| 4.0| 0.0| 4.0| 1.0| 0.0| |1970-01-01T08:00:00.003+08:00| 3.0| -3.0| 3.0| 3.0| 6.0| 0.0| 9.0| 1.0| 0.0| |1970-01-01T08:00:00.004+08:00| 4.0| -4.0| 4.0| 4.0| 8.0| 0.0| 16.0| 1.0| 0.0| |1970-01-01T08:00:00.005+08:00| 5.0| -5.0| 5.0| 5.0| 10.0| 0.0| 25.0| 1.0| 0.0| +-----------------------------+-------------+--------------+-------------+-------------+-----------------------------+-----------------------------+-----------------------------+-----------------------------+-----------------------------+ Total line number = 5 It costs 0.014s
时间序列生成函数可接受若干原始时间序列作为输入,产生一列时间序列输出。与聚合函数不同的是,时间序列生成函数的结果集带有时间戳列。
所有的时间序列生成函数都可以接受 * 作为输入,都可以与原始查询混合进行。
目前 IoTDB 支持下列数学函数,这些数学函数的行为与这些函数在 Java Math 标准库中对应实现的行为一致。
| 函数名 | 输入序列类型 | 输出序列类型 | Java 标准库中的对应实现 |
|---|---|---|---|
| SIN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#sin(double) |
| COS | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#cos(double) |
| TAN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#tan(double) |
| ASIN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#asin(double) |
| ACOS | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#acos(double) |
| ATAN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#atan(double) |
| SINH | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#sinh(double) |
| COSH | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#cosh(double) |
| TANH | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#tanh(double) |
| DEGREES | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#toDegrees(double) |
| RADIANS | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#toRadians(double) |
| ABS | INT32 / INT64 / FLOAT / DOUBLE | 与输入序列的实际类型一致 | Math#abs(int) / Math#abs(long) /Math#abs(float) /Math#abs(double) |
| SIGN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#signum(double) |
| CEIL | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#ceil(double) |
| FLOOR | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#floor(double) |
| ROUND | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#rint(double) |
| EXP | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#exp(double) |
| LN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#log(double) |
| LOG10 | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#log10(double) |
| SQRT | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#sqrt(double) |
例如:
select s1, sin(s1), cos(s1), tan(s1) from root.sg1.d1 limit 5 offset 1000;
结果:
+-----------------------------+-------------------+-------------------+--------------------+-------------------+ | Time| root.sg1.d1.s1|sin(root.sg1.d1.s1)| cos(root.sg1.d1.s1)|tan(root.sg1.d1.s1)| +-----------------------------+-------------------+-------------------+--------------------+-------------------+ |2020-12-10T17:11:49.037+08:00|7360723084922759782| 0.8133527237573284| 0.5817708713544664| 1.3980636773094157| |2020-12-10T17:11:49.038+08:00|4377791063319964531|-0.8938962705202537| 0.4482738644511651| -1.994085181866842| |2020-12-10T17:11:49.039+08:00|7972485567734642915| 0.9627757585308978|-0.27030138509681073|-3.5618602479083545| |2020-12-10T17:11:49.040+08:00|2508858212791964081|-0.6073417341629443| -0.7944406950452296| 0.7644897069734913| |2020-12-10T17:11:49.041+08:00|2817297431185141819|-0.8419358900502509| -0.5395775727782725| 1.5603611649667768| +-----------------------------+-------------------+-------------------+--------------------+-------------------+ Total line number = 5 It costs 0.008s
目前 IoTDB 支持下列字符串处理函数:
| 函数名 | 输入序列类型 | 必要的属性参数 | 输出序列类型 | 功能描述 |
|---|---|---|---|---|
| STRING_CONTAINS | TEXT | s: 待搜寻的字符串 | BOOLEAN | 判断字符串中是否存在s |
| STRING_MATCHES | TEXT | regex: Java 标准库风格的正则表达式 | BOOLEAN | 判断字符串是否能够被正则表达式regex匹配 |
例如:
select s1, string_contains(s1, 's'='warn'), string_matches(s1, 'regex'='[^\\s]+37229') from root.sg1.d4;
结果:
+-----------------------------+--------------+-------------------------------------------+------------------------------------------------------+ | Time|root.sg1.d4.s1|string_contains(root.sg1.d4.s1, "s"="warn")|string_matches(root.sg1.d4.s1, "regex"="[^\\s]+37229")| +-----------------------------+--------------+-------------------------------------------+------------------------------------------------------+ |1970-01-01T08:00:00.001+08:00| warn:-8721| true| false| |1970-01-01T08:00:00.002+08:00| error:-37229| false| true| |1970-01-01T08:00:00.003+08:00| warn:1731| true| false| +-----------------------------+--------------+-------------------------------------------+------------------------------------------------------+ Total line number = 3 It costs 0.007s
目前 IoTDB 支持如下选择函数:
| 函数名 | 输入序列类型 | 必要的属性参数 | 输出序列类型 | 功能描述 |
|---|---|---|---|---|
| TOP_K | INT32 / INT64 / FLOAT / DOUBLE / TEXT | k: 最多选择的数据点数,必须大于 0 小于等于 1000 | 与输入序列的实际类型一致 | 返回某时间序列中值最大的k个数据点。若多于k个数据点的值并列最大,则返回时间戳最小的数据点。 |
| BOTTOM_K | INT32 / INT64 / FLOAT / DOUBLE / TEXT | k: 最多选择的数据点数,必须大于 0 小于等于 1000 | 与输入序列的实际类型一致 | 返回某时间序列中值最小的k个数据点。若多于k个数据点的值并列最小,则返回时间戳最小的数据点。 |
例如:
select s1, top_k(s1, 'k'='2'), bottom_k(s1, 'k'='2') from root.sg1.d2 where time > 2020-12-10T20:36:15.530+08:00;
结果:
+-----------------------------+--------------------+------------------------------+---------------------------------+ | Time| root.sg1.d2.s1|top_k(root.sg1.d2.s1, "k"="2")|bottom_k(root.sg1.d2.s1, "k"="2")| +-----------------------------+--------------------+------------------------------+---------------------------------+ |2020-12-10T20:36:15.531+08:00| 1531604122307244742| 1531604122307244742| null| |2020-12-10T20:36:15.532+08:00|-7426070874923281101| null| null| |2020-12-10T20:36:15.533+08:00|-7162825364312197604| -7162825364312197604| null| |2020-12-10T20:36:15.534+08:00|-8581625725655917595| null| -8581625725655917595| |2020-12-10T20:36:15.535+08:00|-7667364751255535391| null| -7667364751255535391| +-----------------------------+--------------------+------------------------------+---------------------------------+ Total line number = 5 It costs 0.006s
目前 IoTDB 支持如下趋势计算函数:
| 函数名 | 输入序列类型 | 输出序列类型 | 功能描述 |
|---|---|---|---|
| TIME_DIFFERENCE | INT32 / INT64 / FLOAT / DOUBLE / BOOLEAN / TEXT | INT64 | 统计序列中某数据点的时间戳与前一数据点时间戳的差。范围内第一个数据点没有对应的结果输出。 |
| DIFFERENCE | INT32 / INT64 / FLOAT / DOUBLE | 与输入序列的实际类型一致 | 统计序列中某数据点的值与前一数据点的值的差。范围内第一个数据点没有对应的结果输出。 |
| NON_NEGATIVE_DIFFERENCE | INT32 / INT64 / FLOAT / DOUBLE | 与输入序列的实际类型一致 | 统计序列中某数据点的值与前一数据点的值的差的绝对值。范围内第一个数据点没有对应的结果输出。 |
| DERIVATIVE | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | 统计序列中某数据点相对于前一数据点的变化率,数量上等同于 DIFFERENCE / TIME_DIFFERENCE。范围内第一个数据点没有对应的结果输出。 |
| NON_NEGATIVE_DERIVATIVE | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | 统计序列中某数据点相对于前一数据点的变化率的绝对值,数量上等同于 NON_NEGATIVE_DIFFERENCE / TIME_DIFFERENCE。范围内第一个数据点没有对应的结果输出。 |
例如:
select s1, time_difference(s1), difference(s1), non_negative_difference(s1), derivative(s1), non_negative_derivative(s1) from root.sg1.d1 limit 5 offset 1000;
结果:
+-----------------------------+-------------------+-------------------------------+--------------------------+---------------------------------------+--------------------------+---------------------------------------+ | Time| root.sg1.d1.s1|time_difference(root.sg1.d1.s1)|difference(root.sg1.d1.s1)|non_negative_difference(root.sg1.d1.s1)|derivative(root.sg1.d1.s1)|non_negative_derivative(root.sg1.d1.s1)| +-----------------------------+-------------------+-------------------------------+--------------------------+---------------------------------------+--------------------------+---------------------------------------+ |2020-12-10T17:11:49.037+08:00|7360723084922759782| 1| -8431715764844238876| 8431715764844238876| -8.4317157648442388E18| 8.4317157648442388E18| |2020-12-10T17:11:49.038+08:00|4377791063319964531| 1| -2982932021602795251| 2982932021602795251| -2.982932021602795E18| 2.982932021602795E18| |2020-12-10T17:11:49.039+08:00|7972485567734642915| 1| 3594694504414678384| 3594694504414678384| 3.5946945044146785E18| 3.5946945044146785E18| |2020-12-10T17:11:49.040+08:00|2508858212791964081| 1| -5463627354942678834| 5463627354942678834| -5.463627354942679E18| 5.463627354942679E18| |2020-12-10T17:11:49.041+08:00|2817297431185141819| 1| 308439218393177738| 308439218393177738| 3.0843921839317773E17| 3.0843921839317773E17| +-----------------------------+-------------------+-------------------------------+--------------------------+---------------------------------------+--------------------------+---------------------------------------+ Total line number = 5 It costs 0.014s
常序列生成函数用于生成所有数据点的值都相同的时间序列。
常序列生成函数接受一个或者多个时间序列输入,其输出的数据点的时间戳集合是这些输入序列时间戳集合的并集。
目前 IoTDB 支持如下常序列生成函数:
| 函数名 | 必要的属性参数 | 输出序列类型 | 功能描述 |
|---|---|---|---|
| CONST | value: 输出的数据点的值 type: 输出的数据点的类型,只能是 INT32 / INT64 / FLOAT / DOUBLE / BOOLEAN / TEXT | 由输入属性参数 type 决定 | 根据输入属性 value 和 type 输出用户指定的常序列。 |
| PI | 无 | DOUBLE | 常序列的值:π 的 double 值,圆的周长与其直径的比值,即圆周率,等于 Java标准库 中的Math.PI。 |
| E | 无 | DOUBLE | 常序列的值:e 的 double 值,自然对数的底,它等于 Java 标准库 中的 Math.E。 |
例如:
select s1, s2, const(s1, 'value'='1024', 'type'='INT64'), pi(s2), e(s1, s2) from root.sg1.d1;
结果:
select s1, s2, const(s1, 'value'='1024', 'type'='INT64'), pi(s2), e(s1, s2) from root.sg1.d1; +-----------------------------+--------------+--------------+-----------------------------------------------------+------------------+---------------------------------+ | Time|root.sg1.d1.s1|root.sg1.d1.s2|const(root.sg1.d1.s1, "value"="1024", "type"="INT64")|pi(root.sg1.d1.s2)|e(root.sg1.d1.s1, root.sg1.d1.s2)| +-----------------------------+--------------+--------------+-----------------------------------------------------+------------------+---------------------------------+ |1970-01-01T08:00:00.000+08:00| 0.0| 0.0| 1024| 3.141592653589793| 2.718281828459045| |1970-01-01T08:00:00.001+08:00| 1.0| null| 1024| null| 2.718281828459045| |1970-01-01T08:00:00.002+08:00| 2.0| null| 1024| null| 2.718281828459045| |1970-01-01T08:00:00.003+08:00| null| 3.0| null| 3.141592653589793| 2.718281828459045| |1970-01-01T08:00:00.004+08:00| null| 4.0| null| 3.141592653589793| 2.718281828459045| +-----------------------------+--------------+--------------+-----------------------------------------------------+------------------+---------------------------------+ Total line number = 5 It costs 0.005s
当前IoTDB支持6种数据类型,其中包括INT32、INT64、FLOAT、DOUBLE、BOOLEAN以及TEXT。当我们对数据进行查询或者计算时可能需要进行数据类型的转换, 比如说将TEXT转换为INT32,或者提高数据精度,比如说将FLOAT转换为DOUBLE。所以,IoTDB支持使用cast函数对数据类型进行转换。
| 函数名 | 必要的属性参数 | 输出序列类型 | 功能类型 |
|---|---|---|---|
| CAST | type:输出的数据点的类型,只能是 INT32 / INT64 / FLOAT / DOUBLE / BOOLEAN / TEXT | 由输入属性参数type决定 | 将数据转换为type参数指定的类型。 |
1.当INT32、INT64类型的值不为0时,FLOAT与DOUBLE类型的值不为0.0时,TEXT类型不为空字符串或者“false”时,转换为BOOLEAN类型时值为true,否则为false。
2.当BOOLEAN类型的值为true时,转换为INT32与INT64类型的值为1,转换为FLOAT或者DOUBLE类型时值为1.0,转换为TEXT类型时值为“true”。当BOOLEAN类型的值为false时,转换为INT32与INT64类型的值为0,转换为FLOAT或者DOUBLE类型时值为0.0,转换为TEXT类型时值为“false”。
3.当TEXT类型转换为INT32、INT64、FLOAT类型时,会先将TEXT类型的数据转换为DOUBLE类型,然后再转换为对应的类型,此时可能会存在损失精度的问题。如果无法转换的话则直接跳过。
测试数据:
IoTDB> select text from root.test; +-----------------------------+--------------+ | Time|root.test.text| +-----------------------------+--------------+ |1970-01-01T08:00:00.001+08:00| 1.1| |1970-01-01T08:00:00.002+08:00| 1| |1970-01-01T08:00:00.003+08:00| hello world| |1970-01-01T08:00:00.004+08:00| false| +-----------------------------+--------------+
SQL语句:
select cast(text, 'type'='BOOLEAN'), cast(text, 'type'='INT32'), cast(text, 'type'='INT64'), cast(text, 'type'='FLOAT'), cast(text, 'type'='DOUBLE') from root.test;
结果:
+-----------------------------+--------------------------------------+------------------------------------+------------------------------------+------------------------------------+-------------------------------------+ | Time|cast(root.test.text, "type"="BOOLEAN")|cast(root.test.text, "type"="INT32")|cast(root.test.text, "type"="INT64")|cast(root.test.text, "type"="FLOAT")|cast(root.test.text, "type"="DOUBLE")| +-----------------------------+--------------------------------------+------------------------------------+------------------------------------+------------------------------------+-------------------------------------+ |1970-01-01T08:00:00.001+08:00| true| 1| 1| 1.1| 1.1| |1970-01-01T08:00:00.002+08:00| true| 1| 1| 1.0| 1.0| |1970-01-01T08:00:00.003+08:00| true| null| null| null| null| |1970-01-01T08:00:00.004+08:00| false| null| null| null| null| +-----------------------------+--------------------------------------+------------------------------------+------------------------------------+------------------------------------+-------------------------------------+ Total line number = 4 It costs 0.078s
请参考 UDF (用户定义函数)。
已知的自定义时间序列生成函数库实现:
IoTDB 支持在 select 字句中执行由**数字常量,时间序列、算数运算表达式和时间序列生成函数(包括用户自定义函数)**组成的任意嵌套表达式。
下面是 select 子句的语法定义:
selectClause : SELECT resultColumn (',' resultColumn)* ; resultColumn : expression (AS ID)? ; expression : '(' expression ')' | '-' expression | expression ('*' | '/' | '%') expression | expression ('+' | '-') expression | functionName '(' expression (',' expression)* functionAttribute* ')' | timeSeriesSuffixPath | number ;
输入:
select a, b, ((a + 1) * 2 - 1) % 2 + 1.5, sin(a + sin(a + sin(b))), -(a + b) * (sin(a + b) * sin(a + b) + cos(a + b) * cos(a + b)) from root.sg1.d1;
结果:
+-----------------------------+-------------+-------------+-------------------------------------------+------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Time|root.sg1.d1.a|root.sg1.d1.b|((((root.sg1.d1.a + 1) * 2) - 1) % 2) + 1.5|sin(root.sg1.d1.a + sin(root.sg1.d1.a + sin(root.sg1.d1.b)))|-root.sg1.d1.a + root.sg1.d1.b * ((sin(root.sg1.d1.a + root.sg1.d1.b) * sin(root.sg1.d1.a + root.sg1.d1.b)) + (cos(root.sg1.d1.a + root.sg1.d1.b) * cos(root.sg1.d1.a + root.sg1.d1.b)))| +-----------------------------+-------------+-------------+-------------------------------------------+------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ |1970-01-01T08:00:00.000+08:00| 0| 0| 2.5| 0.0| -0.0| |1970-01-01T08:00:00.001+08:00| 1| 1| 2.5| 0.9238430524420609| -2.0| |1970-01-01T08:00:00.002+08:00| 2| 2| 2.5| 0.7903505371876317| -4.0| +-----------------------------+-------------+-------------+-------------------------------------------+------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ Total line number = 3 It costs 0.170s
在 IoTDB 的实际使用中,当进行时间序列的查询操作时,可能会出现在某些时间点值为 null 的情况,这会妨碍用户进行进一步的分析。 为了更好地反映数据更改的程度,用户希望可以自动填充缺失值。 因此,IoTDB 系统引入了自动填充功能。
自动填充功能是指对单列或多列执行时间序列查询时,根据用户指定的方法和有效时间范围填充空值。 如果查询点的值不为 null,则填充功能将不起作用。
IoTDB 目前支持 previous, linear, value 三种空值填充方式,数据类型和支持的填充方法如表 3-1 所示。
表 3-1 数据类型和支持的填充方法
| 数据类型 | 支持的填充方法 |
|---|---|
| boolean | previous, value |
| int32 | previous, linear, value |
| int64 | previous, linear, value |
| float | previous, linear, value |
| double | previous, linear, value |
| text | previous, value |
注意:在 Fill 语句中只能指定一种填充方法。空值填充兼容 0.12 版本及以前的语法(即 fill((<data_type>[<fill_method>(, <before_range>, <after_range>)?])+)),但老的语法也不能同时指定多种填充方式
当某一特定时间戳的数据为空时,可以使用单值填充对空值进行填充,详细说明如下:
当查询的时间戳值为空时,将使用前一个时间戳的值来填充空白。 形式化的先前方法如下:
select <path> from <prefixPath> where time = <T> fill(previous(, <before_range>)?)
表 3-2 给出了所有参数的详细说明。
表 3-2 previous 填充参数列表
| 参数名称(不区分大小写) | 解释 |
|---|---|
| path, prefixPath | 查询路径; 必填项 |
| T | 查询时间戳(只能指定一个); 必填项 |
| before_range | 表示前一种方法的有效时间范围。 当 [T-before_range,T] 范围内的值存在时,前一种方法将起作用。 如果未指定 before_range,则 before_range 会使用默认值 default_fill_interval; -1 表示无穷大; 可选字段 |
在这里,我们举一个使用先前方法填充空值的示例。 SQL 语句如下:
select temperature from root.sgcc.wf03.wt01 where time = 2017-11-01T16:37:50.000 fill(previous, 1m)
意思是:
由于时间根目录 root.sgcc.wf03.wt01.temperature 在 2017-11-01T16:37:50.000 为空,因此系统使用以前的时间戳 2017-11-01T16:37:00.000(且时间戳位于 [2017-11-01T16:36:50.000, 2017-11-01T16:37:50.000] 范围)进行填充和显示。
在 样例数据中, 该语句的执行结果如下所示:
+-----------------------------+-------------------------------+ | Time|root.sgcc.wf03.wt01.temperature| +-----------------------------+-------------------------------+ |2017-11-01T16:37:50.000+08:00| 21.93| +-----------------------------+-------------------------------+ Total line number = 1 It costs 0.016s
值得注意的是,如果在指定的有效时间范围内没有值,系统将不会填充空值,如下所示:
IoTDB> select temperature from root.sgcc.wf03.wt01 where time = 2017-11-01T16:37:50.000 fill(previous, 1s) +-----------------------------+-------------------------------+ | Time|root.sgcc.wf03.wt01.temperature| +-----------------------------+-------------------------------+ |2017-11-01T16:37:50.000+08:00| null| +-----------------------------+-------------------------------+ Total line number = 1 It costs 0.004s
当查询的时间戳值为空时,将使用前一个和下一个时间戳的值来填充空白。 形式化线性方法如下:
select <path> from <prefixPath> where time = <T> fill(linear(, <before_range>, <after_range>)?)
表 3-3 中给出了所有参数的详细说明。
表 3-3 线性填充参数列表
| 参数名称(不区分大小写) | 解释 |
|---|---|
| path, prefixPath | 查询路径; 必填项 |
| T | 查询时间戳(只能指定一个); 必填项 |
| before_range, after_range | 表示线性方法的有效时间范围。 当 [T - before_range,T + after_range] 范围内的值存在时,前一种方法将起作用。 如果未明确指定 before_range 和 after_range,则使用 default_fill_interval。 -1 表示无穷大; 可选字段 |
需要注意的是一旦时间序列在查询时间戳 T 时刻存在有效值,线性填充就会使用这个值作为结果返回。 除此之外,如果在 [T - before_range, T] 或 [T, T + after_range] 两个范围中任意一个范围内不存在有效填充值,则线性填充返回 null 值。
在这里,我们举一个使用线性方法填充空值的示例。 SQL 语句如下:
select temperature from root.sgcc.wf03.wt01 where time = 2017-11-01T16:37:50.000 fill(linear, 1m, 1m)
意思是:
由于时间根目录 root.sgcc.wf03.wt01.temperature 在 2017-11-01T16:37:50.000 为空,因此系统使用以前的时间戳 2017-11-01T16:37:00.000(且时间戳位于 [2017-11-01T16:36:50.000,2017-11-01T16:37:50.000) 时间范围)及其值 21.927326,下一个时间戳记 2017-11-01T16:38:00.000(且时间戳记位于 (2017-11-01T16:37:50.000, 2017-11-01T16:38:50.000) 时间范围)及其值 25.311783 以执行线性拟合计算:
21.927326 +(25.311783-21.927326)/ 60s * 50s = 24.747707
在 样例数据, 该语句的执行结果如下所示:
+-----------------------------+-------------------------------+ | Time|root.sgcc.wf03.wt01.temperature| +-----------------------------+-------------------------------+ |2017-11-01T16:37:50.000+08:00| 24.747707| +-----------------------------+-------------------------------+ Total line number = 1 It costs 0.017s
当查询的时间戳值为空时,将使用给定的值来填充空白。 特定值填充方法如下:
select <path> from <prefixPath> where time = <T> fill(constant)
表 3-4 中给出了所有参数的详细说明。
表 3-4 特定值填充参数列表
| 参数名称(不区分大小写) | 解释 |
|---|---|
| path, prefixPath | 查询路径; 必填项 |
| T | 查询时间戳(只能指定一个); 必填项 |
| constant | 给定的填充值;必填项 |
需要注意的是一旦时间序列在查询时间戳T时刻存在有效值,特定值填充就会使用这个值作为结果返回。
在这里,我们举一个使用特定值方法填充空值的示例。 SQL语句如下:
select temperature from root.sgcc.wf03.wt01 where time = 2017-11-01T16:37:50.000 fill(2.0)
意思是:
由于时间根目录root.sgcc.wf03.wt01.temperature在2017-11-01T16:37:50.000为空,因此使用给定的值2.0进行填充:
在 样例数据, 该语句的执行结果如下所示:
+-----------------------------+-------------------------------+ | Time|root.sgcc.wf03.wt01.temperature| +-----------------------------+-------------------------------+ |2017-11-01T16:37:50.000+08:00| 2.0 | +-----------------------------+-------------------------------+ Total line number = 1 It costs 0.007s
在使用 VALUE 方法填充时需要注意,如果查询结果的数据类型与输入常量值不同,IoTDB 将不进行填充
示例:
select temperature from root.sgcc.wf03.wt01 where time = 2017-11-01T16:37:50.000 fill('test')
结果:
+-----------------------------+-------------------------------+ | Time|root.sgcc.wf03.wt01.temperature| +-----------------------------+-------------------------------+ |2017-11-01T16:37:50.000+08:00| null | +-----------------------------+-------------------------------+ Total line number = 1 It costs 0.007s
本章节主要介绍聚合查询的相关示例, 主要使用的是 IoTDB SELECT 语句的聚合查询函数。
select count(status) from root.ln.wf01.wt01;
结果:
+-------------------------------+ |count(root.ln.wf01.wt01.status)| +-------------------------------+ | 10080| +-------------------------------+ Total line number = 1 It costs 0.016s
在时间序列层级结构中,分层聚合查询用于对某一层级下同名的序列进行聚合查询。 这里使用 LEVEL 来统计指定需要聚合的层级,该语句约定 root 为第 0 层序列,若统计 “root.ln” 下所有序列则需指定 level 为 1。
例如:不同存储组下均存在名为 status 的序列, 如 “root.ln.wf01.wt01.status”, “root.ln.wf02.wt02.status”, 以及 " root.sgcc.wf03.wt01.status", 如果需要统计不同存储组下 status 序列的数据点个数,使用以下查询:
select count(status) from root.** group by level = 1
运行结果为:
+-------------------------+---------------------------+ |count(root.ln.*.*.status)|count(root.sgcc.*.*.status)| +-------------------------+---------------------------+ | 20160| 10080| +-------------------------+---------------------------+ Total line number = 1 It costs 0.003s
同理,如果需要统计不同设备下 status 序列的数据点个数,可以规定 level = 3,
select count(status) from root.** group by level = 3
运行结果为:
+---------------------------+---------------------------+ |count(root.*.*.wt01.status)|count(root.*.*.wt02.status)| +---------------------------+---------------------------+ | 20160| 10080| +---------------------------+---------------------------+ Total line number = 1 It costs 0.003s
注意,这时会将存储组 ln 和 sgcc 下名为 wt01 的设备视为同名设备聚合在一起。而如果需要进一步统计不同存储组下的不同设备中 status 序列的数据点个数,可以使用以下查询:
select count(status) from root.** group by level = 1, 3
运行结果为:
+----------------------------+----------------------------+------------------------------+ |count(root.ln.*.wt01.status)|count(root.ln.*.wt02.status)|count(root.sgcc.*.wt01.status)| +----------------------------+----------------------------+------------------------------+ | 10080| 10080| 10080| +----------------------------+----------------------------+------------------------------+ Total line number = 1 It costs 0.003s
假设需要查询所有序列下温度传感器 temperature 的最大值,可以使用下列查询语句:
select max_value(temperature) from root.** group by level = 0
运行结果:
+---------------------------------+ |max_value(root.*.*.*.temperature)| +---------------------------------+ | 26.0| +---------------------------------+ Total line number = 1 It costs 0.013s
上面的查询都是针对某一个传感器,特别地,如果想要查询某一层级下所有传感器拥有的总数据点数,则需要显式规定测点为 *
select count(*) from root.ln.** group by level = 2
运行结果:
+----------------------+----------------------+ |count(root.*.wf01.*.*)|count(root.*.wf02.*.*)| +----------------------+----------------------+ | 20160| 20160| +----------------------+----------------------+ Total line number = 1 It costs 0.013s
分层聚合查询也可被用于其他聚合函数,当前所支持的聚合函数为:count, sum, avg, last_value, first_value, min_time, max_time, min_value, max_value, extreme
对于 sum, avg, min_value, max_value, extreme 五种聚合函数,需保证所有聚合的时间序列数据类型相同。其他聚合函数没有此限制。
本章节主要介绍时间区间分组聚合查询的相关示例, 主要使用的是 IoTDB SELECT 语句的 GROUP BY 子句, 该子句是 IoTDB 中用于根据用户给定划分条件对结果集进行划分,并对已划分的结果集进行聚合计算的语句。 IoTDB 支持根据时间间隔和自定义的滑动步长(默认值与时间间隔相同,自定义的值必须大于等于时间间隔)对结果集进行划分,默认结果按照时间升序排列。 同时,您也可以使用 Java JDBC 标准接口来执行相关的查询语句。
GROUP BY 语句为用户提供三类指定参数:
三类参数的实际含义已经在下图中指出,这三类参数里,第三个参数是可选的。 接下来,我们将给出三种典型的降频聚合查询的例子: 滑动步长未指定, 指定滑动步长, 带值过滤条件。
对应的 SQL 语句是:
select count(status), max_value(temperature) from root.ln.wf01.wt01 group by ([2017-11-01T00:00:00, 2017-11-07T23:00:00),1d);
这条查询的含义是:
由于用户没有指定滑动步长,滑动步长将会被默认设置为跟时间间隔参数相同,也就是1d。
上面这个例子的第一个参数是显示窗口参数,决定了最终的显示范围是 [2017-11-01T00:00:00, 2017-11-07T23:00:00)。
上面这个例子的第二个参数是划分时间轴的时间间隔参数,将1d当作划分间隔,显示窗口参数的起始时间当作分割原点,时间轴即被划分为连续的时间间隔:[0,1d), [1d, 2d), [2d, 3d) 等等。
然后系统将会用 WHERE 子句中的时间和值过滤条件以及 GROUP BY 语句中的第一个参数作为数据的联合过滤条件,获得满足所有过滤条件的数据(在这个例子里是在 [2017-11-01T00:00:00, 2017-11-07 T23:00:00) 这个时间范围的数据),并把这些数据映射到之前分割好的时间轴中(这个例子里是从 2017-11-01T00:00:00 到 2017-11-07T23:00:00:00 的每一天)
每个时间间隔窗口内都有数据,SQL 执行后的结果集如下所示:
+-----------------------------+-------------------------------+----------------------------------------+ | Time|count(root.ln.wf01.wt01.status)|max_value(root.ln.wf01.wt01.temperature)| +-----------------------------+-------------------------------+----------------------------------------+ |2017-11-01T00:00:00.000+08:00| 1440| 26.0| |2017-11-02T00:00:00.000+08:00| 1440| 26.0| |2017-11-03T00:00:00.000+08:00| 1440| 25.99| |2017-11-04T00:00:00.000+08:00| 1440| 26.0| |2017-11-05T00:00:00.000+08:00| 1440| 26.0| |2017-11-06T00:00:00.000+08:00| 1440| 25.99| |2017-11-07T00:00:00.000+08:00| 1380| 26.0| +-----------------------------+-------------------------------+----------------------------------------+ Total line number = 7 It costs 0.024s
对应的 SQL 语句是:
select count(status), max_value(temperature) from root.ln.wf01.wt01 group by ([2017-11-01 00:00:00, 2017-11-07 23:00:00), 3h, 1d);
这条查询的含义是:
由于用户指定了滑动步长为1d,GROUP BY 语句执行时将会每次把时间间隔往后移动一天的步长,而不是默认的 3 小时。
也就意味着,我们想要取从 2017-11-01 到 2017-11-07 每一天的凌晨 0 点到凌晨 3 点的数据。
上面这个例子的第一个参数是显示窗口参数,决定了最终的显示范围是 [2017-11-01T00:00:00, 2017-11-07T23:00:00)。
上面这个例子的第二个参数是划分时间轴的时间间隔参数,将3h当作划分间隔,显示窗口参数的起始时间当作分割原点,时间轴即被划分为连续的时间间隔:[2017-11-01T00:00:00, 2017-11-01T03:00:00), [2017-11-02T00:00:00, 2017-11-02T03:00:00), [2017-11-03T00:00:00, 2017-11-03T03:00:00) 等等。
上面这个例子的第三个参数是每次时间间隔的滑动步长。
然后系统将会用 WHERE 子句中的时间和值过滤条件以及 GROUP BY 语句中的第一个参数作为数据的联合过滤条件,获得满足所有过滤条件的数据(在这个例子里是在 [2017-11-01T00:00:00, 2017-11-07 T23:00:00) 这个时间范围的数据),并把这些数据映射到之前分割好的时间轴中(这个例子里是从 2017-11-01T00:00:00 到 2017-11-07T23:00:00:00 的每一天的凌晨 0 点到凌晨 3 点)
每个时间间隔窗口内都有数据,SQL 执行后的结果集如下所示:
+-----------------------------+-------------------------------+----------------------------------------+ | Time|count(root.ln.wf01.wt01.status)|max_value(root.ln.wf01.wt01.temperature)| +-----------------------------+-------------------------------+----------------------------------------+ |2017-11-01T00:00:00.000+08:00| 180| 25.98| |2017-11-02T00:00:00.000+08:00| 180| 25.98| |2017-11-03T00:00:00.000+08:00| 180| 25.96| |2017-11-04T00:00:00.000+08:00| 180| 25.96| |2017-11-05T00:00:00.000+08:00| 180| 26.0| |2017-11-06T00:00:00.000+08:00| 180| 25.85| |2017-11-07T00:00:00.000+08:00| 180| 25.99| +-----------------------------+-------------------------------+----------------------------------------+ Total line number = 7 It costs 0.006s
对应的 SQL 语句是:
select count(status) from root.ln.wf01.wt01 where time > 2017-11-01T01:00:00 group by([2017-11-01T00:00:00, 2019-11-07T23:00:00), 1mo, 2mo);
这条查询的含义是:
由于用户指定了滑动步长为2mo,GROUP BY 语句执行时将会每次把时间间隔往后移动 2 个自然月的步长,而不是默认的 1 个自然月。
也就意味着,我们想要取从 2017-11-01 到 2019-11-07 每 2 个自然月的第一个月的数据。
上面这个例子的第一个参数是显示窗口参数,决定了最终的显示范围是 [2017-11-01T00:00:00, 2019-11-07T23:00:00)。
起始时间为 2017-11-01T00:00:00,滑动步长将会以起始时间作为标准按月递增,取当月的 1 号作为时间间隔的起始时间。
上面这个例子的第二个参数是划分时间轴的时间间隔参数,将1mo当作划分间隔,显示窗口参数的起始时间当作分割原点,时间轴即被划分为连续的时间间隔:[2017-11-01T00:00:00, 2017-12-01T00:00:00), [2018-02-01T00:00:00, 2018-03-01T00:00:00), [2018-05-03T00:00:00, 2018-06-01T00:00:00) 等等。
上面这个例子的第三个参数是每次时间间隔的滑动步长。
然后系统将会用 WHERE 子句中的时间和值过滤条件以及 GROUP BY 语句中的第一个参数作为数据的联合过滤条件,获得满足所有过滤条件的数据(在这个例子里是在 [2017-11-01T00:00:00, 2019-11-07T23:00:00) 这个时间范围的数据),并把这些数据映射到之前分割好的时间轴中(这个例子里是从 2017-11-01T00:00:00 到 2019-11-07T23:00:00:00 的每两个自然月的第一个月)
每个时间间隔窗口内都有数据,SQL 执行后的结果集如下所示:
+-----------------------------+-------------------------------+ | Time|count(root.ln.wf01.wt01.status)| +-----------------------------+-------------------------------+ |2017-11-01T00:00:00.000+08:00| 259| |2018-01-01T00:00:00.000+08:00| 250| |2018-03-01T00:00:00.000+08:00| 259| |2018-05-01T00:00:00.000+08:00| 251| |2018-07-01T00:00:00.000+08:00| 242| |2018-09-01T00:00:00.000+08:00| 225| |2018-11-01T00:00:00.000+08:00| 216| |2019-01-01T00:00:00.000+08:00| 207| |2019-03-01T00:00:00.000+08:00| 216| |2019-05-01T00:00:00.000+08:00| 207| |2019-07-01T00:00:00.000+08:00| 199| |2019-09-01T00:00:00.000+08:00| 181| |2019-11-01T00:00:00.000+08:00| 60| +-----------------------------+-------------------------------+
对应的 SQL 语句是:
select count(status) from root.ln.wf01.wt01 group by([2017-10-31T00:00:00, 2019-11-07T23:00:00), 1mo, 2mo);
这条查询的含义是:
由于用户指定了滑动步长为2mo,GROUP BY 语句执行时将会每次把时间间隔往后移动 2 个自然月的步长,而不是默认的 1 个自然月。
也就意味着,我们想要取从 2017-10-31 到 2019-11-07 每 2 个自然月的第一个月的数据。
与上述示例不同的是起始时间为 2017-10-31T00:00:00,滑动步长将会以起始时间作为标准按月递增,取当月的 31 号(即最后一天)作为时间间隔的起始时间。若起始时间设置为 30 号,滑动步长会将时间间隔的起始时间设置为当月 30 号,若不存在则为最后一天。
上面这个例子的第一个参数是显示窗口参数,决定了最终的显示范围是 [2017-10-31T00:00:00, 2019-11-07T23:00:00)。
上面这个例子的第二个参数是划分时间轴的时间间隔参数,将1mo当作划分间隔,显示窗口参数的起始时间当作分割原点,时间轴即被划分为连续的时间间隔:[2017-10-31T00:00:00, 2017-11-31T00:00:00), [2018-02-31T00:00:00, 2018-03-31T00:00:00), [2018-05-31T00:00:00, 2018-06-31T00:00:00) 等等。
上面这个例子的第三个参数是每次时间间隔的滑动步长。
然后系统将会用 WHERE 子句中的时间和值过滤条件以及 GROUP BY 语句中的第一个参数作为数据的联合过滤条件,获得满足所有过滤条件的数据(在这个例子里是在 [2017-10-31T00:00:00, 2019-11-07T23:00:00) 这个时间范围的数据),并把这些数据映射到之前分割好的时间轴中(这个例子里是从 2017-10-31T00:00:00 到 2019-11-07T23:00:00:00 的每两个自然月的第一个月)
每个时间间隔窗口内都有数据,SQL 执行后的结果集如下所示:
+-----------------------------+-------------------------------+ | Time|count(root.ln.wf01.wt01.status)| +-----------------------------+-------------------------------+ |2017-10-31T00:00:00.000+08:00| 251| |2017-12-31T00:00:00.000+08:00| 250| |2018-02-28T00:00:00.000+08:00| 259| |2018-04-30T00:00:00.000+08:00| 250| |2018-06-30T00:00:00.000+08:00| 242| |2018-08-31T00:00:00.000+08:00| 225| |2018-10-31T00:00:00.000+08:00| 216| |2018-12-31T00:00:00.000+08:00| 208| |2019-02-28T00:00:00.000+08:00| 216| |2019-04-30T00:00:00.000+08:00| 208| |2019-06-30T00:00:00.000+08:00| 199| |2019-08-31T00:00:00.000+08:00| 181| |2019-10-31T00:00:00.000+08:00| 69| +-----------------------------+-------------------------------+
每个区间的结果时间戳为区间右端点,对应的 SQL 语句是:
select count(status) from root.ln.wf01.wt01 group by ((2017-11-01T00:00:00, 2017-11-07T23:00:00],1d);
这条查询语句的时间区间是左开右闭的,结果中不会包含时间点 2017-11-01 的数据,但是会包含时间点 2017-11-07 的数据。
SQL 执行后的结果集如下所示:
+-----------------------------+-------------------------------+ | Time|count(root.ln.wf01.wt01.status)| +-----------------------------+-------------------------------+ |2017-11-02T00:00:00.000+08:00| 1440| |2017-11-03T00:00:00.000+08:00| 1440| |2017-11-04T00:00:00.000+08:00| 1440| |2017-11-05T00:00:00.000+08:00| 1440| |2017-11-06T00:00:00.000+08:00| 1440| |2017-11-07T00:00:00.000+08:00| 1440| |2017-11-07T23:00:00.000+08:00| 1380| +-----------------------------+-------------------------------+ Total line number = 7 It costs 0.004s
IoTDB 支持对原降采样结果进行空值填充,previous, linear, value 填充方式均可作用于查询语句中的任一聚合算子,但一条查询语句只能使用一种空值填充方式。此外,使用时需要注意以下两点:
降采样补空值查询语法同单点补空值查询语法相似,下面列出简单的示例和使用细节:
首先检查一下 root.ln.wf01.wt01.temperature 在时间 2017-11-07T23:49:00 以后的值
IoTDB> SELECT temperature FROM root.ln.wf01.wt01 where time >= 2017-11-07T23:49:00 +-----------------------------+-----------------------------+ | Time|root.ln.wf01.wt01.temperature| +-----------------------------+-----------------------------+ |2017-11-07T23:49:00.000+08:00| 23.7| |2017-11-07T23:51:00.000+08:00| 22.24| |2017-11-07T23:53:00.000+08:00| 24.58| |2017-11-07T23:54:00.000+08:00| 22.52| |2017-11-07T23:57:00.000+08:00| 24.39| |2017-11-08T00:00:00.000+08:00| 21.07| +-----------------------------+-----------------------------+ Total line number = 6 It costs 0.010s
root.ln.wf01.wt01.temperature 最早时间和值是 2017-11-07T23:49:00 和 23.7;最后时间和值是 2017-11-08T00:00:00 和 21.07
SQL 示例:
SELECT last_value(temperature) FROM root.ln.wf01.wt01 GROUP BY([2017-11-07T23:50:00, 2017-11-07T23:59:00),1m) FILL (PREVIOUSUNTILLAST); SELECT last_value(temperature) FROM root.ln.wf01.wt01 GROUP BY([2017-11-07T23:50:00, 2017-11-07T23:59:00),1m) FILL (PREVIOUS);
结果:
IoTDB> SELECT last_value(temperature) FROM root.ln.wf01.wt01 GROUP BY([2017-11-07T23:50:00, 2017-11-07T23:59:00),1m) FILL (PREVIOUSUNTILLAST); +-----------------------------+-----------------------------------------+ | Time|last_value(root.ln.wf01.wt01.temperature)| +-----------------------------+-----------------------------------------+ |2017-11-07T23:50:00.000+08:00| null| |2017-11-07T23:51:00.000+08:00| 22.24| |2017-11-07T23:52:00.000+08:00| 22.24| |2017-11-07T23:53:00.000+08:00| 24.58| |2017-11-07T23:54:00.000+08:00| 22.52| |2017-11-07T23:55:00.000+08:00| 22.52| |2017-11-07T23:56:00.000+08:00| 22.52| |2017-11-07T23:57:00.000+08:00| 24.39| |2017-11-07T23:58:00.000+08:00| null| +-----------------------------+-----------------------------------------+ Total line number = 9 It costs 0.007s IoTDB> SELECT last_value(temperature) FROM root.ln.wf01.wt01 GROUP BY([2017-11-07T23:50:00, 2017-11-07T23:59:00),1m) FILL (PREVIOUS); +-----------------------------+-----------------------------------------+ | Time|last_value(root.ln.wf01.wt01.temperature)| +-----------------------------+-----------------------------------------+ |2017-11-07T23:50:00.000+08:00| null| |2017-11-07T23:51:00.000+08:00| 22.24| |2017-11-07T23:52:00.000+08:00| 22.24| |2017-11-07T23:53:00.000+08:00| 24.58| |2017-11-07T23:54:00.000+08:00| 22.52| |2017-11-07T23:55:00.000+08:00| 22.52| |2017-11-07T23:56:00.000+08:00| 22.52| |2017-11-07T23:57:00.000+08:00| 24.39| |2017-11-07T23:58:00.000+08:00| 24.39| +-----------------------------+-----------------------------------------+ Total line number = 9 It costs 0.006s
解释:
使用 PREVIOUSUNTILLAST 将不会填充 2017-11-07T23:57:00 以后的值。
IoTDB 的空值填充方式可以分为 PreviousFill, LinearFill, ValueFill 三大类。其中,PreviousFill 需要知道空值前的第一个非空数据,LinearFill 需要知道空值前后的第一个非空数据才能进行填充。假使某条查询语句返回的结果中第一个或最后一个值为空,就可能导致结果集在首尾存在一段连续的空值,不满足 GroupByFill 的业务期望。
在上例中,第一个时间区间 [2017-11-07T23:50:00, 2017-11-07T23:51:00) 内没有任何数据,上一个有数据的时间区间是 [2017-11-01T23:49:00, 2017-11-07T23:50:00),可以通过设置 PREVIOUS 填充向前查询参数 beforeRange 来填充第一个区间的数据,示例如下:
SELECT last_value(temperature) FROM root.ln.wf01.wt01 GROUP BY([2017-11-07T23:50:00, 2017-11-07T23:59:00),1m) FILL (PREVIOUS, 1m);
结果:
IoTDB> SELECT last_value(temperature) FROM root.ln.wf01.wt01 GROUP BY([2017-11-07T23:50:00, 2017-11-07T23:59:00),1m) FILL (PREVIOUS, 1m); +-----------------------------+-----------------------------------------+ | Time|last_value(root.ln.wf01.wt01.temperature)| +-----------------------------+-----------------------------------------+ |2017-11-07T23:50:00.000+08:00| 23.7| |2017-11-07T23:51:00.000+08:00| 22.24| |2017-11-07T23:52:00.000+08:00| 22.24| |2017-11-07T23:53:00.000+08:00| 24.58| |2017-11-07T23:54:00.000+08:00| 22.52| |2017-11-07T23:55:00.000+08:00| 22.52| |2017-11-07T23:56:00.000+08:00| null| |2017-11-07T23:57:00.000+08:00| 24.39| |2017-11-07T23:58:00.000+08:00| 24.39| +-----------------------------+-----------------------------------------+ Total line number = 9 It costs 0.005s
解释:
为了不与原有语义冲突,当不设置 before_range, after_range 参数时,GroupByFill 的空值填充取空值的前一个/后一个非空值完成;当设置 before_range, after_range 参数时,设空值所在记录的时间戳为 t,GroupByFill 取 [t-before_range, t+after_range) 内的前一个/后一个非空值完成填充。
因为时间区间 [2017-11-07T23:55:00, 2017-11-07T23:57:00) 内均没有数据,所以本例虽然通过设置 before_range 填充了 [2017-11-07T23:50:00, 2017-11-07T23:51:00) 的数据,但由于 before_range 较小,[2017-11-07T23:56:00, 2017-11-07T23:57:00) 的数据无法填充。
before_range, after_range 参数也可辅助 LINEAR 方式进行填充,示例如下:
SELECT last_value(temperature) FROM root.ln.wf01.wt01 GROUP BY([2017-11-07T23:50:00, 2017-11-07T23:59:00),1m) FILL (LINEAR, 5m, 5m);
结果:
IoTDB> SELECT last_value(temperature) FROM root.ln.wf01.wt01 GROUP BY([2017-11-07T23:50:00, 2017-11-07T23:59:00),1m) FILL (LINEAR, 5m, 5m); +-----------------------------+-----------------------------------------+ | Time|last_value(root.ln.wf01.wt01.temperature)| +-----------------------------+-----------------------------------------+ |2017-11-07T23:50:00.000+08:00| 22.970001| |2017-11-07T23:51:00.000+08:00| 22.24| |2017-11-07T23:52:00.000+08:00| 23.41| |2017-11-07T23:53:00.000+08:00| 24.58| |2017-11-07T23:54:00.000+08:00| 22.52| |2017-11-07T23:55:00.000+08:00| 23.143333| |2017-11-07T23:56:00.000+08:00| 23.766666| |2017-11-07T23:57:00.000+08:00| 24.39| |2017-11-07T23:58:00.000+08:00| 23.283333| +-----------------------------+-----------------------------------------+ Total line number = 9 It costs 0.008s
注意:设原始降采样查询区间为 [start_time, end_time),在指定 before_range, after_range 参数后,降采样查询结果不变,但查询区间将转变为 [start_time - before_range, end_time + after_range)。因此这两个参数设置较大时会影响效率,使用时需注意。
值填充方式会将输入的常量值解析为字符串,填充时尝试将字符串常量转换为对应类型的数据,若转换成功则进行填充,否则就不填充。举例如下:
SELECT last_value(temperature) FROM root.ln.wf01.wt01 GROUP BY([2017-11-07T23:50:00, 2017-11-07T23:59:00),1m) FILL (20.0) SELECT last_value(temperature) FROM root.ln.wf01.wt01 GROUP BY([2017-11-07T23:50:00, 2017-11-07T23:59:00),1m) FILL ('temperature')
结果:
IoTDB> SELECT last_value(temperature) FROM root.ln.wf01.wt01 GROUP BY([2017-11-07T23:50:00, 2017-11-07T23:59:00),1m) FILL (20.0);
+-----------------------------+-----------------------------------------+
| Time|last_value(root.ln.wf01.wt01.temperature)|
+-----------------------------+-----------------------------------------+
|2017-11-07T23:50:00.000+08:00| 20.0|
|2017-11-07T23:51:00.000+08:00| 22.24|
|2017-11-07T23:52:00.000+08:00| 20.0|
|2017-11-07T23:53:00.000+08:00| 24.58|
|2017-11-07T23:54:00.000+08:00| 22.52|
|2017-11-07T23:55:00.000+08:00| 20.0|
|2017-11-07T23:56:00.000+08:00| 20.0|
|2017-11-07T23:57:00.000+08:00| 24.39|
|2017-11-07T23:58:00.000+08:00| 20.0|
+-----------------------------+-----------------------------------------+
Total line number = 9
It costs 0.007s
IoTDB> SELECT last_value(temperature) FROM root.ln.wf01.wt01 GROUP BY([2017-11-07T23:50:00, 2017-11-07T23:59:00),1m) FILL ('temperature');
+-----------------------------+-----------------------------------------+
| Time|last_value(root.ln.wf01.wt01.temperature)|
+-----------------------------+-----------------------------------------+
|2017-11-07T23:50:00.000+08:00| null|
|2017-11-07T23:51:00.000+08:00| 22.24|
|2017-11-07T23:52:00.000+08:00| null|
|2017-11-07T23:53:00.000+08:00| 24.58|
|2017-11-07T23:54:00.000+08:00| 22.52|
|2017-11-07T23:55:00.000+08:00| null|
|2017-11-07T23:56:00.000+08:00| null|
|2017-11-07T23:57:00.000+08:00| 24.39|
|2017-11-07T23:58:00.000+08:00| null|
+-----------------------------+-----------------------------------------+
Total line number = 9
It costs 0.005s
除此之外,还可以通过定义 LEVEL 来统计指定层级下的数据点个数。
例如:
统计降采样后的数据点个数
select count(status) from root.ln.wf01.wt01 group by ((2017-11-01T00:00:00, 2017-11-07T23:00:00],1d), level=1;
结果:
+-----------------------------+-------------------------+ | Time|COUNT(root.ln.*.*.status)| +-----------------------------+-------------------------+ |2017-11-02T00:00:00.000+08:00| 1440| |2017-11-03T00:00:00.000+08:00| 1440| |2017-11-04T00:00:00.000+08:00| 1440| |2017-11-05T00:00:00.000+08:00| 1440| |2017-11-06T00:00:00.000+08:00| 1440| |2017-11-07T00:00:00.000+08:00| 1440| |2017-11-07T23:00:00.000+08:00| 1380| +-----------------------------+-------------------------+ Total line number = 7 It costs 0.006s
加上滑动 Step 的降采样后的结果也可以汇总
select count(status) from root.ln.wf01.wt01 group by ([0,20),2ms,3ms), level=1;
+-----------------------------+-------------------------+ | Time|COUNT(root.ln.*.*.status)| +-----------------------------+-------------------------+ |2017-11-01T00:00:00.000+08:00| 180| |2017-11-02T00:00:00.000+08:00| 180| |2017-11-03T00:00:00.000+08:00| 180| |2017-11-04T00:00:00.000+08:00| 180| |2017-11-05T00:00:00.000+08:00| 180| |2017-11-06T00:00:00.000+08:00| 180| |2017-11-07T00:00:00.000+08:00| 180| +-----------------------------+-------------------------+ Total line number = 7 It costs 0.004s
IoTDB 支持在 SELECT 字句中执行由聚合查询和其他运算组成的任意嵌套表达式。
GROUP BY 的聚合查询。输入:
select avg(temperature), sin(avg(temperature)), avg(temperature) + 1, -sum(hardware), avg(temperature) + sum(hardware) from root.ln.wf01.wt01;
结果:
+----------------------------------+---------------------------------------+--------------------------------------+--------------------------------+--------------------------------------------------------------------+ |avg(root.ln.wf01.wt01.temperature)|sin(avg(root.ln.wf01.wt01.temperature))|avg(root.ln.wf01.wt01.temperature) + 1|-sum(root.ln.wf01.wt01.hardware)|avg(root.ln.wf01.wt01.temperature) + sum(root.ln.wf01.wt01.hardware)| +----------------------------------+---------------------------------------+--------------------------------------+--------------------------------+--------------------------------------------------------------------+ | 15.927999999999999| -0.21826546964855045| 16.927999999999997| -7426.0| 7441.928| +----------------------------------+---------------------------------------+--------------------------------------+--------------------------------+--------------------------------------------------------------------+ Total line number = 1 It costs 0.009s
输入:
select count(a), count(b), ((count(a) + 1) * 2 - 1) % 2 + 1.5, -(count(a) + count(b)) * (count(a) * count(b)) + count(a) / count(b) from root.sg;
结果:
+----------------+----------------+----------------------------------------------+----------------------------------------------------------------------------------------------------------------------+ |count(root.sg.a)|count(root.sg.b)|((((count(root.sg.a) + 1) * 2) - 1) % 2) + 1.5|(-count(root.sg.a) + count(root.sg.b) * (count(root.sg.a) * count(root.sg.b))) + (count(root.sg.a) / count(root.sg.b))| +----------------+----------------+----------------------------------------------+----------------------------------------------------------------------------------------------------------------------+ | 4| 3| 2.5| -82.66666666666667| +----------------+----------------+----------------------------------------------+----------------------------------------------------------------------------------------------------------------------+ Total line number = 1 It costs 0.013s
GROUP BY 的聚合查询。输入:
select avg(temperature), sin(avg(temperature)), avg(temperature) + 1, -sum(hardware), avg(temperature) + sum(hardware) as custom_sum from root.ln.wf01.wt01 GROUP BY([10, 90), 10ms);
结果:
+-----------------------------+----------------------------------+---------------------------------------+--------------------------------------+--------------------------------+----------+ | Time|avg(root.ln.wf01.wt01.temperature)|sin(avg(root.ln.wf01.wt01.temperature))|avg(root.ln.wf01.wt01.temperature) + 1|-sum(root.ln.wf01.wt01.hardware)|custom_sum| +-----------------------------+----------------------------------+---------------------------------------+--------------------------------------+--------------------------------+----------+ |1970-01-01T08:00:00.010+08:00| 13.987499999999999| 0.9888207947857667| 14.987499999999999| -3211.0| 3224.9875| |1970-01-01T08:00:00.020+08:00| 29.6| -0.9701057337071853| 30.6| -3720.0| 3749.6| |1970-01-01T08:00:00.030+08:00| null| null| null| null| null| |1970-01-01T08:00:00.040+08:00| null| null| null| null| null| |1970-01-01T08:00:00.050+08:00| null| null| null| null| null| |1970-01-01T08:00:00.060+08:00| null| null| null| null| null| |1970-01-01T08:00:00.070+08:00| null| null| null| null| null| |1970-01-01T08:00:00.080+08:00| null| null| null| null| null| +-----------------------------+----------------------------------+---------------------------------------+--------------------------------------+--------------------------------+----------+ Total line number = 8 It costs 0.012s
目前此功能尚不支持填充算子(
FILL)和按层级聚合(GROUP BY LEVEL)查询, 在后续版本会支持。聚合计算目前只能当做最底层表达式输入,暂不支持聚合函数内部出现表达式。
即不支持以下查询
SELECT avg(s1+1) FROM root.sg.d1; -- 聚合函数内部有表达式 SELECT avg(s1) + avg(s2) FROM root.sg.* GROUP BY LEVEL=1; -- 按层级聚合 SELECT avg(s1) + avg(s2) FROM root.sg.d1 GROUP BY([0, 10000), 1s) FILL(previous); -- 空值填充
SQL 语法:
select last <Path> [COMMA <Path>]* from < PrefixPath > [COMMA < PrefixPath >]* <WhereClause>
其含义是:查询时间序列 prefixPath.path 中最近时间戳的数据
<WhereClause>中当前只支持含有'>‘或’>='的时间过滤条件,任何其他过滤条件都将会返回异常。
结果集为四列的结构
+----+----------+-----+--------+ |Time|timeseries|value|dataType| +----+----------+-----+--------+
示例 1:查询 root.ln.wf01.wt01.status 的最新数据点
IoTDB> select last status from root.ln.wf01.wt01 +-----------------------------+------------------------+-----+--------+ | Time| timeseries|value|dataType| +-----------------------------+------------------------+-----+--------+ |2017-11-07T23:59:00.000+08:00|root.ln.wf01.wt01.status|false| BOOLEAN| +-----------------------------+------------------------+-----+--------+ Total line number = 1 It costs 0.000s
示例 2:查询 root.ln.wf01.wt01 下 status,temperature 时间戳大于等于 2017-11-07T23:50:00 的最新数据点。
IoTDB> select last status, temperature from root.ln.wf01.wt01 where time >= 2017-11-07T23:50:00 +-----------------------------+-----------------------------+---------+--------+ | Time| timeseries| value|dataType| +-----------------------------+-----------------------------+---------+--------+ |2017-11-07T23:59:00.000+08:00| root.ln.wf01.wt01.status| false| BOOLEAN| |2017-11-07T23:59:00.000+08:00|root.ln.wf01.wt01.temperature|21.067368| DOUBLE| +-----------------------------+-----------------------------+---------+--------+ Total line number = 2 It costs 0.002s
模糊查询分为Like语句和Regexp语句,都可以支持对Text类型的数据进行模糊匹配
Like语句:
示例 1:查询 root.sg.device 下 value 含有'cc'的数据。 % 表示任意0个或多个字符。
IoTDB> select * from root.sg.device where value like '%cc%' +-----------------------------+--------------------+ | Time|root.sg.device.value| +-----------------------------+--------------------+ |2017-11-07T23:59:00.000+08:00| aabbccdd| |2017-11-07T23:59:00.000+08:00| cc| +-----------------------------+--------------------+ Total line number = 2 It costs 0.002s
示例 2:查询 root.sg.device 下 value 中间为 'b'、前后为任意单个字符的数据。 _ 表示任意单个字符。
IoTDB> select * from root.sg.device where value like '_b_' +-----------------------------+--------------------+ | Time|root.sg.device.value| +-----------------------------+--------------------+ |2017-11-07T23:59:00.000+08:00| abc| +-----------------------------+--------------------+ Total line number = 1 It costs 0.002s
Regexp语句:
需要传入的过滤条件为 Java 标准库风格的正则表达式
示例 1:查询 root.sg.device 下 value 值为26个英文字符组成的字符串
IoTDB> select * from root.sg.device where value regexp '^[A-Za-z]+$' +-----------------------------+--------------------+ | Time|root.sg.device.value| +-----------------------------+--------------------+ |2017-11-07T23:59:00.000+08:00| aabbccdd| |2017-11-07T23:59:00.000+08:00| cc| +-----------------------------+--------------------+ Total line number = 2 It costs 0.002s
示例 2:查询 root.sg.device 下 value 值为26个小写英文字符组成的字符串 且时间大于100的
IoTDB> select * from root.sg.device where value regexp '^[a-z]+$' and time > 100 +-----------------------------+--------------------+ | Time|root.sg.device.value| +-----------------------------+--------------------+ |2017-11-07T23:59:00.000+08:00| aabbccdd| |2017-11-07T23:59:00.000+08:00| cc| +-----------------------------+--------------------+ Total line number = 2 It costs 0.002s
常见的正则匹配举例:
长度为3-20的所有字符:^.{3,20}$
大写英文字符:^[A-Z]+$
数字和英文字符:^[A-Za-z0-9]+$
以a开头的:^a.*
更多语法请参照 SQL REFERENCE.
由于 IoTDB 独特的数据模型,在每个传感器前都附带有设备等诸多额外信息。有时,我们只针对某个具体设备查询,而这些前缀信息频繁显示造成了冗余,影响了结果集的显示与分析。这时我们可以使用 IoTDB 提供的 AS 函数,将查询中出现的时间序列给定一个别名。
例如:
select s1 as temperature, s2 as speed from root.ln.wf01.wt01;
则结果集将显示为:
| Time | temperature | speed |
|---|---|---|
| ... | ... | ... |
IoTDB 提供 LIMIT/SLIMIT 子句和 OFFSET/SOFFSET 子句,以使用户可以更好地控制查询结果。使用 LIMIT 和 SLIMIT 子句可让用户控制查询结果的行数和列数, 并且使用 OFFSET 和 SOFSET 子句允许用户设置结果显示的起始位置。
请注意,按组查询不支持 LIMIT 和 OFFSET。
本章主要介绍查询结果的行和列控制的相关示例。你还可以使用 Java JDBC 标准接口执行查询。
通过使用 LIMIT 和 OFFSET 子句,用户可以以与行相关的方式控制查询结果。 我们将通过以下示例演示如何使用 LIMIT 和 OFFSET 子句。
SQL 语句是:
select status, temperature from root.ln.wf01.wt01 limit 10
意思是:
所选设备为 ln 组 wf01 工厂 wt01 设备; 选择的时间序列是“状态”和“温度”。 SQL 语句要求返回查询结果的前 10 行。
结果如下所示:
+-----------------------------+------------------------+-----------------------------+ | Time|root.ln.wf01.wt01.status|root.ln.wf01.wt01.temperature| +-----------------------------+------------------------+-----------------------------+ |2017-11-01T00:00:00.000+08:00| true| 25.96| |2017-11-01T00:01:00.000+08:00| true| 24.36| |2017-11-01T00:02:00.000+08:00| false| 20.09| |2017-11-01T00:03:00.000+08:00| false| 20.18| |2017-11-01T00:04:00.000+08:00| false| 21.13| |2017-11-01T00:05:00.000+08:00| false| 22.72| |2017-11-01T00:06:00.000+08:00| false| 20.71| |2017-11-01T00:07:00.000+08:00| false| 21.45| |2017-11-01T00:08:00.000+08:00| false| 22.58| |2017-11-01T00:09:00.000+08:00| false| 20.98| +-----------------------------+------------------------+-----------------------------+ Total line number = 10 It costs 0.000s
SQL 语句是:
select status, temperature from root.ln.wf01.wt01 limit 5 offset 3
意思是:
所选设备为 ln 组 wf01 工厂 wt01 设备; 选择的时间序列是“状态”和“温度”。 SQL 语句要求返回查询结果的第 3 至 7 行(第一行编号为 0 行)。
结果如下所示:
+-----------------------------+------------------------+-----------------------------+ | Time|root.ln.wf01.wt01.status|root.ln.wf01.wt01.temperature| +-----------------------------+------------------------+-----------------------------+ |2017-11-01T00:03:00.000+08:00| false| 20.18| |2017-11-01T00:04:00.000+08:00| false| 21.13| |2017-11-01T00:05:00.000+08:00| false| 22.72| |2017-11-01T00:06:00.000+08:00| false| 20.71| |2017-11-01T00:07:00.000+08:00| false| 21.45| +-----------------------------+------------------------+-----------------------------+ Total line number = 5 It costs 0.342s
SQL 语句是:
select status,temperature from root.ln.wf01.wt01 where time > 2017-11-01T00:05:00.000 and time< 2017-11-01T00:12:00.000 limit 5 offset 3
意思是:
所选设备为 ln 组 wf01 工厂 wt01 设备; 选择的时间序列是“状态”和“温度”。 SQL 语句要求返回时间“ 2017-11-01T00:05:00.000”和“ 2017-11-01T00:12:00.000”之间的状态和温度传感器值的第 3 至 4 行(第一行) 编号为第 0 行)。
结果如下所示:
+-----------------------------+------------------------+-----------------------------+ | Time|root.ln.wf01.wt01.status|root.ln.wf01.wt01.temperature| +-----------------------------+------------------------+-----------------------------+ |2017-11-01T00:03:00.000+08:00| false| 20.18| |2017-11-01T00:04:00.000+08:00| false| 21.13| |2017-11-01T00:05:00.000+08:00| false| 22.72| |2017-11-01T00:06:00.000+08:00| false| 20.71| |2017-11-01T00:07:00.000+08:00| false| 21.45| +-----------------------------+------------------------+-----------------------------+ Total line number = 5 It costs 0.000s
SQL 语句是:
select count(status), max_value(temperature) from root.ln.wf01.wt01 group by ([2017-11-01T00:00:00, 2017-11-07T23:00:00),1d) limit 4 offset 3
意思是:
SQL 语句子句要求返回查询结果的第 3 至 6 行(第一行编号为 0 行)。
结果如下所示:
+-----------------------------+-------------------------------+----------------------------------------+ | Time|count(root.ln.wf01.wt01.status)|max_value(root.ln.wf01.wt01.temperature)| +-----------------------------+-------------------------------+----------------------------------------+ |2017-11-04T00:00:00.000+08:00| 1440| 26.0| |2017-11-05T00:00:00.000+08:00| 1440| 26.0| |2017-11-06T00:00:00.000+08:00| 1440| 25.99| |2017-11-07T00:00:00.000+08:00| 1380| 26.0| +-----------------------------+-------------------------------+----------------------------------------+ Total line number = 4 It costs 0.016s
值得注意的是,由于当前的 FILL 子句只能在某个时间点填充时间序列的缺失值,也就是说,FILL 子句的执行结果恰好是一行,因此 LIMIT 和 OFFSET 不会是 与 FILL 子句结合使用,否则将提示错误。 例如,执行以下 SQL 语句:
select temperature from root.sgcc.wf03.wt01 where time = 2017-11-01T16:37:50.000 fill(previous, 1m) limit 10
SQL 语句将不会执行,并且相应的错误提示如下:
Msg: 401: Error occured while parsing SQL to physical plan: line 1:101 mismatched input 'limit' expecting {<EOF>, ';'}
通过使用 SLIMIT 和 SOFFSET 子句,用户可以与列相关的方式控制查询结果。 我们将通过以下示例演示如何使用 SLIMIT 和 SOFFSET 子句。
SQL 语句是:
select * from root.ln.wf01.wt01 where time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000 slimit 1
意思是:
所选设备为 ln 组 wf01 工厂 wt01 设备; 所选时间序列是该设备下的第二列,即温度。 SQL 语句要求在“2017-11-01T00:05:00.000”和“2017-11-01T00:12:00.000”的时间点之间选择温度传感器值。
结果如下所示:
+-----------------------------+-----------------------------+ | Time|root.ln.wf01.wt01.temperature| +-----------------------------+-----------------------------+ |2017-11-01T00:06:00.000+08:00| 20.71| |2017-11-01T00:07:00.000+08:00| 21.45| |2017-11-01T00:08:00.000+08:00| 22.58| |2017-11-01T00:09:00.000+08:00| 20.98| |2017-11-01T00:10:00.000+08:00| 25.52| |2017-11-01T00:11:00.000+08:00| 22.91| +-----------------------------+-----------------------------+ Total line number = 6 It costs 0.000s
SQL 语句是:
select * from root.ln.wf01.wt01 where time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000 slimit 1 soffset 1
意思是:
所选设备为 ln 组 wf01 工厂 wt01 设备; 所选时间序列是该设备下的第一列,即电源状态。 SQL 语句要求在" 2017-11-01T00:05:00.000“和”2017-11-01T00:12:00.000"的时间点之间选择状态传感器值。
结果如下所示:
+-----------------------------+------------------------+ | Time|root.ln.wf01.wt01.status| +-----------------------------+------------------------+ |2017-11-01T00:06:00.000+08:00| false| |2017-11-01T00:07:00.000+08:00| false| |2017-11-01T00:08:00.000+08:00| false| |2017-11-01T00:09:00.000+08:00| false| |2017-11-01T00:10:00.000+08:00| true| |2017-11-01T00:11:00.000+08:00| false| +-----------------------------+------------------------+ Total line number = 6 It costs 0.003s
SQL 语句是:
select max_value(*) from root.ln.wf01.wt01 group by ([2017-11-01T00:00:00, 2017-11-07T23:00:00),1d) slimit 1 soffset 1
结果如下所示:
+-----------------------------+-----------------------------------+ | Time|max_value(root.ln.wf01.wt01.status)| +-----------------------------+-----------------------------------+ |2017-11-01T00:00:00.000+08:00| true| |2017-11-02T00:00:00.000+08:00| true| |2017-11-03T00:00:00.000+08:00| true| |2017-11-04T00:00:00.000+08:00| true| |2017-11-05T00:00:00.000+08:00| true| |2017-11-06T00:00:00.000+08:00| true| |2017-11-07T00:00:00.000+08:00| true| +-----------------------------+-----------------------------------+ Total line number = 7 It costs 0.000s
SQL 语句是:
select * from root.sgcc.wf03.wt01 where time = 2017-11-01T16:37:50.000 fill(previous, 1m) slimit 1 soffset 1
结果如下所示:
+-----------------------------+--------------------------+ | Time|root.sgcc.wf03.wt01.status| +-----------------------------+--------------------------+ |2017-11-01T16:35:00.000+08:00| true| +-----------------------------+--------------------------+ Total line number = 1 It costs 0.007s
除了对查询结果进行行或列控制之外,IoTDB 还允许用户控制查询结果的行和列。 这是同时包含 LIMIT 子句和 SLIMIT 子句的完整示例。
SQL 语句是:
select * from root.ln.wf01.wt01 limit 10 offset 100 slimit 2 soffset 0
意思是:
所选设备为 ln 组 wf01 工厂 wt01 设备; 所选时间序列是此设备下的第 0 列至第 1 列(第一列编号为第 0 列)。 SQL 语句子句要求返回查询结果的第 100 至 109 行(第一行编号为 0 行)。
结果如下所示:
+-----------------------------+-----------------------------+------------------------+ | Time|root.ln.wf01.wt01.temperature|root.ln.wf01.wt01.status| +-----------------------------+-----------------------------+------------------------+ |2017-11-01T01:40:00.000+08:00| 21.19| false| |2017-11-01T01:41:00.000+08:00| 22.79| false| |2017-11-01T01:42:00.000+08:00| 22.98| false| |2017-11-01T01:43:00.000+08:00| 21.52| false| |2017-11-01T01:44:00.000+08:00| 23.45| true| |2017-11-01T01:45:00.000+08:00| 24.06| true| |2017-11-01T01:46:00.000+08:00| 22.6| false| |2017-11-01T01:47:00.000+08:00| 23.78| true| |2017-11-01T01:48:00.000+08:00| 24.72| true| |2017-11-01T01:49:00.000+08:00| 24.68| true| +-----------------------------+-----------------------------+------------------------+ Total line number = 10 It costs 0.009s
当 LIMIT / SLIMIT 的参数 N / SN 超过结果集的大小时,IoTDB 将按预期返回所有结果。 例如,原始 SQL 语句的查询结果由六行组成,我们通过 LIMIT 子句选择前 100 行:
select status,temperature from root.ln.wf01.wt01 where time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000 limit 100
结果如下所示:
+-----------------------------+------------------------+-----------------------------+ | Time|root.ln.wf01.wt01.status|root.ln.wf01.wt01.temperature| +-----------------------------+------------------------+-----------------------------+ |2017-11-01T00:06:00.000+08:00| false| 20.71| |2017-11-01T00:07:00.000+08:00| false| 21.45| |2017-11-01T00:08:00.000+08:00| false| 22.58| |2017-11-01T00:09:00.000+08:00| false| 20.98| |2017-11-01T00:10:00.000+08:00| true| 25.52| |2017-11-01T00:11:00.000+08:00| false| 22.91| +-----------------------------+------------------------+-----------------------------+ Total line number = 6 It costs 0.005s
当 LIMIT / SLIMIT 子句的参数 N / SN 超过允许的最大值(N / SN 的类型为 int32)时,系统将提示错误。 例如,执行以下 SQL 语句:
select status,temperature from root.ln.wf01.wt01 where time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000 limit 1234567890123456789
SQL 语句将不会执行,并且相应的错误提示如下:
Msg: 303: check metadata error: Out of range. LIMIT <N>: N should be Int32.
当 LIMIT / LIMIT 子句的参数 N / SN 不是正整数时,系统将提示错误。 例如,执行以下 SQL 语句:
select status,temperature from root.ln.wf01.wt01 where time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000 limit 13.1
SQL 语句将不会执行,并且相应的错误提示如下:
Msg: 401: line 1:129 mismatched input '.' expecting {<EOF>, ';'}
当 LIMIT 子句的参数 OFFSET 超过结果集的大小时,IoTDB 将返回空结果集。 例如,执行以下 SQL 语句:
select status,temperature from root.ln.wf01.wt01 where time > 2017-11-01T00:05:00.000 and time < 2017-11-01T00:12:00.000 limit 2 offset 6
结果如下所示:
+----+------------------------+-----------------------------+ |Time|root.ln.wf01.wt01.status|root.ln.wf01.wt01.temperature| +----+------------------------+-----------------------------+ Empty set. It costs 0.005s
select * from root.ln.** where time <= 2017-11-01T00:01:00 WITHOUT NULL ANY
select * from root.ln.** where time <= 2017-11-01T00:01:00 WITHOUT NULL ALL
IoTDB 支持另外两种结果返回形式:按设备时间对齐 ‘align by device’ 和 时序不对齐 ‘disable align’.
‘align by device’ 对齐方式下,设备 ID 会单独作为一列出现。在 select 子句中写了多少列,最终结果就会有该列数+2 (时间列和设备名字列)。SQL 形如:
select * from root.ln.** where time <= 2017-11-01T00:01:00 align by device
结果如下:
+-----------------------------+-----------------+-----------+------+--------+ | Time| Device|temperature|status|hardware| +-----------------------------+-----------------+-----------+------+--------+ |2017-11-01T00:00:00.000+08:00|root.ln.wf01.wt01| 25.96| true| null| |2017-11-01T00:01:00.000+08:00|root.ln.wf01.wt01| 24.36| true| null| |1970-01-01T08:00:00.001+08:00|root.ln.wf02.wt02| null| true| v1| |1970-01-01T08:00:00.002+08:00|root.ln.wf02.wt02| null| false| v2| |2017-11-01T00:00:00.000+08:00|root.ln.wf02.wt02| null| true| v2| |2017-11-01T00:01:00.000+08:00|root.ln.wf02.wt02| null| true| v2| +-----------------------------+-----------------+-----------+------+--------+ Total line number = 6 It costs 0.012s
‘disable align’ 意味着每条时序就有 2 列存在。Disable Align 只能用于查询语句句尾,不能用于聚合查询、Fill 语句、Group by 或 Group by device 语句,但可用于 Limit 语句。结果显示若无数据显示为空白。
SQL 形如:
select * from root.ln.** where time <= 2017-11-01T00:01:00 disable align
结果如下:
+-----------------------------+--------------------------+-----------------------------+------------------------+-----------------------------+-----------------------------+-----------------------------+------------------------+ | Time|root.ln.wf02.wt02.hardware| Time|root.ln.wf02.wt02.status| Time|root.ln.wf01.wt01.temperature| Time|root.ln.wf01.wt01.status| +-----------------------------+--------------------------+-----------------------------+------------------------+-----------------------------+-----------------------------+-----------------------------+------------------------+ |1970-01-01T08:00:00.001+08:00| v1|1970-01-01T08:00:00.001+08:00| true|2017-11-01T00:00:00.000+08:00| 25.96|2017-11-01T00:00:00.000+08:00| true| |1970-01-01T08:00:00.002+08:00| v2|1970-01-01T08:00:00.002+08:00| false|2017-11-01T00:01:00.000+08:00| 24.36|2017-11-01T00:01:00.000+08:00| true| |2017-11-01T00:00:00.000+08:00| v2|2017-11-01T00:00:00.000+08:00| true| null| null| null| null| |2017-11-01T00:01:00.000+08:00| v2|2017-11-01T00:01:00.000+08:00| true| null| null| null| null| +-----------------------------+--------------------------+-----------------------------+------------------------+-----------------------------+-----------------------------+-----------------------------+------------------------+ Total line number = 4 It costs 0.018s
更多语法请参照 SQL REFERENCE。
用户使用 DELETE 语句 可以删除指定的时间序列中符合时间删除条件的数据。在删除数据时,用户可以选择需要删除的一个或多个时间序列、时间序列的前缀、时间序列带、*路径对某一个时间区间内的数据进行删除。
在 JAVA 编程环境中,您可以使用 JDBC API 单条或批量执行 DELETE 语句。
以测控 ln 集团为例,存在这样的使用场景:
wf02 子站的 wt02 设备在 2017-11-01 16:26:00 之前的供电状态出现多段错误,且无法分析其正确数据,错误数据影响了与其他设备的关联分析。此时,需要将此时间段前的数据删除。进行此操作的 SQL 语句为:
delete from root.ln.wf02.wt02.status where time<=2017-11-01T16:26:00;
如果我们仅仅想要删除 2017 年内的在 2017-11-01 16:26:00 之前的数据,可以使用以下 SQL:
delete from root.ln.wf02.wt02.status where time>=2017-01-01T00:00:00 and time<=2017-11-01T16:26:00;
IoTDB 支持删除一个时间序列任何一个时间范围内的所有时序点,用户可以使用以下 SQL 语句指定需要删除的时间范围:
delete from root.ln.wf02.wt02.status where time < 10 delete from root.ln.wf02.wt02.status where time <= 10 delete from root.ln.wf02.wt02.status where time < 20 and time > 10 delete from root.ln.wf02.wt02.status where time <= 20 and time >= 10 delete from root.ln.wf02.wt02.status where time > 20 delete from root.ln.wf02.wt02.status where time >= 20 delete from root.ln.wf02.wt02.status where time = 20
需要注意,当前的删除语句不支持 where 子句后的时间范围为多个由 OR 连接成的时间区间。如下删除语句将会解析出错:
delete from root.ln.wf02.wt02.status where time > 4 or time < 0 Msg: 303: Check metadata error: For delete statement, where clause can only contain atomic expressions like : time > XXX, time <= XXX, or two atomic expressions connected by 'AND'
如果 delete 语句中未指定 where 子句,则会删除时间序列中的所有数据。
delete from root.ln.wf02.status
当 ln 集团 wf02 子站的 wt02 设备在 2017-11-01 16:26:00 之前的供电状态和设备硬件版本都需要删除,此时可以使用含义更广的 路径模式(Path Pattern) 进行删除操作,进行此操作的 SQL 语句为:
delete from root.ln.wf02.wt02.* where time <= 2017-11-01T16:26:00;
需要注意的是,当删除的路径不存在时,IoTDB 不会提示路径不存在,而是显示执行成功,因为 SQL 是一种声明式的编程方式,除非是语法错误、权限不足等,否则都不认为是错误,如下所示。
IoTDB> delete from root.ln.wf03.wt02.status where time < now() Msg: TimeSeries does not exist and its data cannot be deleted
您可以通过如下语句来删除某一个存储组下的指定时间分区:
DELETE PARTITION root.ln 0,1,2
上例中的 0,1,2 为待删除时间分区的 id,您可以通过查看 IoTDB 的数据文件夹找到它,或者可以通过计算timestamp / partitionInterval(向下取整), 手动地将一个时间戳转换为对应的 id,其中的partitionInterval可以在 IoTDB 的配置文件中找到(如果您使用的版本支持时间分区)。
请注意该功能目前只是实验性的,如果您不是开发者,使用时请务必谨慎。