查询数据

主要查询功能

TDengine 采用 SQL 作为查询语言。应用程序可以通过 REST API 或连接器发送 SQL 语句,用户还可以通过 TDengine 命令行工具 taos 手动执行 SQL 即席查询(Ad-Hoc Query)。TDengine 支持如下查询功能:

  • 单列、多列数据查询
  • 标签和数值的多种过滤条件:>, <, =, <>, like 等
  • 聚合结果的分组(Group by)、排序(Order by)、约束输出(Limit/Offset)
  • 时间窗口(Interval)、会话窗口(Session)和状态窗口(State_window)等窗口切分聚合查询
  • 数值列及聚合结果的四则运算
  • 时间戳对齐的连接查询(Join Query: 隐式连接)操作
  • 多种聚合/计算函数: count, max, min, avg, sum, twa, stddev, leastsquares, top, bottom, first, last, percentile, apercentile, last_row, spread, diff 等

例如:在命令行工具 taos 中,从表 d1001 中查询出 voltage > 215 的记录,按时间降序排列,仅仅输出 2 条。

1. taos> select * from d1001 where voltage > 215 order by ts desc limit 2;
2. ts            |       current        |   voltage   |        phase         |
3. ======================================================================================
4. 2018-10-03 14:38:16.800 |             12.30000 |         221 |              0.31000 |
5. 2018-10-03 14:38:15.000 |             12.60000 |         218 |              0.33000 |
6. Query OK, 2 row(s) in set (0.001100s)

为满足物联网场景的需求,TDengine 支持几个特殊的函数,比如 twa(时间加权平均),spread (最大值与最小值的差),last_row(最后一条记录)等,更多与物联网场景相关的函数将添加进来。

具体的查询语法请看 TDengine SQL 的数据查询 章节。

多表聚合查询

物联网场景中,往往同一个类型的数据采集点有多个。TDengine 采用超级表(STable)的概念来描述某一个类型的数据采集点,一张普通的表来描述一个具体的数据采集点。同时 TDengine 使用标签来描述数据采集点的静态属性,一个具体的数据采集点有具体的标签值。通过指定标签的过滤条件,TDengine 提供了一高效的方法将超级表(某一类型的数据采集点)所属的子表进行聚合查询。对普通表的聚合函数以及绝大部分操作都适用于超级表,语法完全一样。

示例一

在 TDengine CLI,查找加利福尼亚州所有智能电表采集的电压平均值,并按照 location 分组。

1. taos> SELECT AVG(voltage), location FROM meters GROUP BY location;
2. avg(voltage)        |                             location                             |
3. ===============================================================================================
4. 219.200000000 | California.SanFrancisco                                          |
5. 221.666666667 | California.LosAngeles                                            |
6. Query OK, 2 rows in database (0.005995s)

示例二

在 TDengine CLI, 查找 groupId 为 2 的所有智能电表的记录条数,电流的最大值。

1. taos> SELECT count(*), max(current) FROM meters where groupId = 2;
2. cunt(*)  |    max(current)  |
3. ==================================
4. 5 |             13.4 |
5. Query OK, 1 row(s) in set (0.002136s)

在 TDengine SQL 的数据查询 一章,查询类操作都会注明是否支持超级表。

降采样查询、插值

物联网场景里,经常需要通过降采样(down sampling)将采集的数据按时间段进行聚合。TDengine 提供了一个简便的关键词 interval 让按照时间窗口的查询操作变得极为简单。比如,将智能电表 d1001 采集的电流值每 10 秒钟求和

1. taos> SELECT _wstart, sum(current) FROM d1001 INTERVAL(10s);
2. _wstart         |       sum(current)        |
3. ======================================================
4. 2018-10-03 14:38:00.000 |              10.300000191 |
5. 2018-10-03 14:38:10.000 |              24.900000572 |
6. Query OK, 2 rows in database (0.003139s)

降采样操作也适用于超级表,比如:将加利福尼亚州所有智能电表采集的电流值每秒钟求和

1. taos> SELECT _wstart, SUM(current) FROM meters where location like "California%" INTERVAL(1s);
2. _wstart         |       sum(current)        |
3. ======================================================
4. 2018-10-03 14:38:04.000 |              10.199999809 |
5. 2018-10-03 14:38:05.000 |              23.699999809 |
6. 2018-10-03 14:38:06.000 |              11.500000000 |
7. 2018-10-03 14:38:15.000 |              12.600000381 |
8. 2018-10-03 14:38:16.000 |              34.400000572 |
9. Query OK, 5 rows in database (0.007413s)

降采样操作也支持时间偏移,比如:将所有智能电表采集的电流值每秒钟求和,但要求每个时间窗口从 500 毫秒开始

1. taos> SELECT _wstart, SUM(current) FROM meters INTERVAL(1s, 500a);
2. _wstart         |       sum(current)        |
3. ======================================================
4. 2018-10-03 14:38:03.500 |              10.199999809 |
5. 2018-10-03 14:38:04.500 |              10.300000191 |
6. 2018-10-03 14:38:05.500 |              13.399999619 |
7. 2018-10-03 14:38:06.500 |              11.500000000 |
8. 2018-10-03 14:38:14.500 |              12.600000381 |
9. 2018-10-03 14:38:16.500 |              34.400000572 |
10. Query OK, 6 rows in database (0.005515s)

物联网场景里,每个数据采集点采集数据的时间是难同步的,但很多分析算法(比如 FFT)需要把采集的数据严格按照时间等间隔的对齐,在很多系统里,需要应用自己写程序来处理,但使用 TDengine 的降采样操作就轻松解决。

如果一个时间间隔里,没有采集的数据,TDengine 还提供插值计算的功能。

语法规则细节请见 TDengine SQL 的按时间窗口切分聚合 章节。

示例代码

查询数据

在 SQL 写入 一章,我们创建了 power 数据库,并向 meters 表写入了一些数据,以下示例代码展示如何查询这个表的数据。

  • Java
  • Python
  • Go
  • Rust
  • Node.js
  • C#
  • C
  • PHP
1. package com.taos.example;

3. import java.sql.*;

5. public class RestQueryExample {
6. private static Connection getConnection() throws SQLException {
7. String jdbcUrl = "jdbc:TAOS-RS://localhost:6041/power?user=root&password=taosdata";
8. return DriverManager.getConnection(jdbcUrl);
9. }

11. private static void printRow(ResultSet rs) throws SQLException {
12. ResultSetMetaData meta = rs.getMetaData();
13. for (int i = 1; i <= meta.getColumnCount(); i++) {
14. String value = rs.getString(i);
15. System.out.print(value);
16. System.out.print("\t");
17. }
18. System.out.println();
19. }

21. private static void printColName(ResultSet rs) throws SQLException {
22. ResultSetMetaData meta = rs.getMetaData();
23. for (int i = 1; i <= meta.getColumnCount(); i++) {
24. String colLabel = meta.getColumnLabel(i);
25. System.out.print(colLabel);
26. System.out.print("\t");
27. }
28. System.out.println();
29. }

31. private static void processResult(ResultSet rs) throws SQLException {
32. printColName(rs);
33. while (rs.next()) {
34. printRow(rs);
35. }
36. }

38. private static void queryData() throws SQLException {
39. try (Connection conn = getConnection()) {
40. try (Statement stmt = conn.createStatement()) {
41. ResultSet rs = stmt.executeQuery("SELECT AVG(voltage) FROM meters GROUP BY location");
42. processResult(rs);
43. }
44. }
45. }

47. public static void main(String[] args) throws SQLException {
48. queryData();
49. }
50. }

52. // possible output:
53. // avg(voltage) location
54. // 222.0    California.LosAngeles
55. // 219.0    California.SanFrancisco

查看源码

通过迭代逐行获取查询结果。

1. def query_api_demo(conn: taos.TaosConnection):
2. result: taos.TaosResult = conn.query("SELECT tbname, * FROM meters LIMIT 2")
3. print("field count:", result.field_count)
4. print("meta of fields[1]:", result.fields[1])
5. print("======================Iterate on result=========================")
6. for row in result:
7. print(row)

10. # field count: 7
11. # meta of fields[1]: {name: ts, type: 9, bytes: 8}
12. # ======================Iterate on result=========================
13. # ('d1003', datetime.datetime(2018, 10, 3, 14, 38, 5, 500000), 11.800000190734863, 221, 0.2800000011920929, 'california.losangeles', 2)
14. # ('d1003', datetime.datetime(2018, 10, 3, 14, 38, 16, 600000), 13.399999618530273, 223, 0.28999999165534973, 'california.losangeles', 2)

查看源码

一次获取所有查询结果,并把每一行转化为一个字典返回。

1. def fetch_all_demo(conn: taos.TaosConnection):
2. result: taos.TaosResult = conn.query("SELECT ts, current FROM meters LIMIT 2")
3. rows = result.fetch_all_into_dict()
4. print("row count:", result.row_count)
5. print("===============all data===================")
6. print(rows)

9. # row count: 2
10. # ===============all data===================
11. # [{'ts': datetime.datetime(2018, 10, 3, 14, 38, 5, 500000), 'current': 11.800000190734863},
12. # {'ts': datetime.datetime(2018, 10, 3, 14, 38, 16, 600000), 'current': 13.399999618530273}]

查看源码

1. package main

3. import (
4. "database/sql"
5. "log"
6. "time"

8. _ "github.com/taosdata/driver-go/v3/taosRestful"
9. )

11. func main() {
12. var taosDSN = "root:taosdata@http(localhost:6041)/power"
13. taos, err := sql.Open("taosRestful", taosDSN)
14. if err != nil {
15. log.Fatalln("failed to connect TDengine, err:", err)
16. }
17. defer taos.Close()
18. rows, err := taos.Query("SELECT ts, current FROM meters LIMIT 2")
19. if err != nil {
20. log.Fatalln("failed to select from table, err:", err)
21. }

23. defer rows.Close()
24. for rows.Next() {
25. var r struct {
26. ts      time.Time
27. current float32
28. }
29. err := rows.Scan(&r.ts, &r.current)
30. if err != nil {
31. log.Fatalln("scan error:\n", err)
32. return
33. }
34. log.Println(r.ts, r.current)
35. }
36. }

查看源码

1. use taos::sync::*;

3. fn main() -> anyhow::Result<()> {
4. let taos = TaosBuilder::from_dsn("ws:///power")?.build()?;
5. let mut result = taos.query("SELECT ts, current FROM meters LIMIT 2")?;
6. // print column names
7. let meta = result.fields();
8. println!("{}", meta.iter().map(|field| field.name()).join("\t"));

10. // print rows
11. let rows = result.rows();
12. for row in rows {
13. let row = row?;
14. for (_name, value) in row {
15. print!("{}\t", value);
16. }
17. println!();
18. }
19. Ok(())
20. }

22. // output(suppose you are in +8 timezone):
23. // ts      current
24. // 2018-10-03T14:38:05+08:00       10.3
25. // 2018-10-03T14:38:15+08:00       12.6

查看源码

1. const taos = require("@tdengine/client");

3. const conn = taos.connect({ host: "localhost", database: "power" });
4. const cursor = conn.cursor();
5. const query = cursor.query("SELECT ts, current FROM meters LIMIT 2");
6. query.execute().then(function (result) {
7. result.pretty();
8. });

10. // output:
11. // Successfully connected to TDengine
12. //            ts             |         current          |
13. // =======================================================
14. // 2018-10-03 14:38:05.000   | 10.3                     |
15. // 2018-10-03 14:38:15.000   | 12.6                     |

查看源码

1. using TDengineDriver;
2. using TDengineDriver.Impl;
3. using System.Runtime.InteropServices;

5. namespace TDengineExample
6. {
7. internal class QueryExample
8. {
9. static void Main()
10. {
11. IntPtr conn = GetConnection();
12. try
13. {
14. // run query
15. IntPtr res = TDengine.Query(conn, "SELECT * FROM meters LIMIT 2");
16. if (TDengine.ErrorNo(res) != 0)
17. {
18. throw new Exception("Failed to query since: " + TDengine.Error(res));
19. }

21. // get filed count
22. int fieldCount = TDengine.FieldCount(res);
23. Console.WriteLine("fieldCount=" + fieldCount);

25. // print column names
26. List<TDengineMeta> metas = LibTaos.GetMeta(res);
27. for (int i = 0; i < metas.Count; i++)
28. {
29. Console.Write(metas[i].name + "\t");
30. }
31. Console.WriteLine();

33. // print values
34. List<Object> resData = LibTaos.GetData(res);
35. for (int i = 0; i < resData.Count; i++)
36. {
37. Console.Write($"|{resData[i].ToString()} \t");
38. if (((i + 1) % metas.Count == 0))
39. {
40. Console.WriteLine("");
41. }
42. }
43. Console.WriteLine();

45. // Free result after use
46. TDengine.FreeResult(res);
47. }
48. finally
49. {
50. TDengine.Close(conn);
51. }

53. }
54. static IntPtr GetConnection()
55. {
56. string host = "localhost";
57. short port = 6030;
58. string username = "root";
59. string password = "taosdata";
60. string dbname = "power";
61. var conn = TDengine.Connect(host, username, password, dbname, port);
62. if (conn == IntPtr.Zero)
63. {
64. throw new Exception("Connect to TDengine failed");
65. }
66. else
67. {
68. Console.WriteLine("Connect to TDengine success");
69. }
70. return conn;
71. }
72. }
73. }

75. // output:
76. // Connect to TDengine success
77. // fieldCount=6
78. // ts      current voltage phase   location        groupid
79. // 1648432611249   10.3    219     0.31    California.SanFrancisco        2
80. // 1648432611749   12.6    218     0.33    California.SanFrancisco        2

查看源码

1. // compile with:
2. // gcc -o query_example query_example.c -ltaos
3. #include <inttypes.h>
4. #include <stdio.h>
5. #include <stdlib.h>
6. #include <string.h>
7. #include <taos.h>

9. typedef int16_t VarDataLenT;

11. #define TSDB_NCHAR_SIZE sizeof(int32_t)
12. #define VARSTR_HEADER_SIZE sizeof(VarDataLenT)

14. #define GET_FLOAT_VAL(x) (*(float *)(x))
15. #define GET_DOUBLE_VAL(x) (*(double *)(x))

17. #define varDataLen(v) ((VarDataLenT *)(v))[0]

19. int printRow(char *str, TAOS_ROW row, TAOS_FIELD *fields, int numFields) {
20. int  len = 0;
21. char split = ' ';

23. for (int i = 0; i < numFields; ++i) {
24. if (i > 0) {
25. str[len++] = split;
26. }

28. if (row[i] == NULL) {
29. len += sprintf(str + len, "%s", "NULL");
30. continue;
31. }

33. switch (fields[i].type) {
34. case TSDB_DATA_TYPE_TINYINT:
35. len += sprintf(str + len, "%d", *((int8_t *)row[i]));
36. break;

38. case TSDB_DATA_TYPE_UTINYINT:
39. len += sprintf(str + len, "%u", *((uint8_t *)row[i]));
40. break;

42. case TSDB_DATA_TYPE_SMALLINT:
43. len += sprintf(str + len, "%d", *((int16_t *)row[i]));
44. break;

46. case TSDB_DATA_TYPE_USMALLINT:
47. len += sprintf(str + len, "%u", *((uint16_t *)row[i]));
48. break;

50. case TSDB_DATA_TYPE_INT:
51. len += sprintf(str + len, "%d", *((int32_t *)row[i]));
52. break;

54. case TSDB_DATA_TYPE_UINT:
55. len += sprintf(str + len, "%u", *((uint32_t *)row[i]));
56. break;

58. case TSDB_DATA_TYPE_BIGINT:
59. len += sprintf(str + len, "%" PRId64, *((int64_t *)row[i]));
60. break;

62. case TSDB_DATA_TYPE_UBIGINT:
63. len += sprintf(str + len, "%" PRIu64, *((uint64_t *)row[i]));
64. break;

66. case TSDB_DATA_TYPE_FLOAT: {
67. float fv = 0;
68. fv = GET_FLOAT_VAL(row[i]);
69. len += sprintf(str + len, "%f", fv);
70. } break;

72. case TSDB_DATA_TYPE_DOUBLE: {
73. double dv = 0;
74. dv = GET_DOUBLE_VAL(row[i]);
75. len += sprintf(str + len, "%lf", dv);
76. } break;

78. case TSDB_DATA_TYPE_BINARY:
79. case TSDB_DATA_TYPE_NCHAR: {
80. int32_t charLen = varDataLen((char *)row[i] - VARSTR_HEADER_SIZE);
81. memcpy(str + len, row[i], charLen);
82. len += charLen;
83. } break;

85. case TSDB_DATA_TYPE_TIMESTAMP:
86. len += sprintf(str + len, "%" PRId64, *((int64_t *)row[i]));
87. break;

89. case TSDB_DATA_TYPE_BOOL:
90. len += sprintf(str + len, "%d", *((int8_t *)row[i]));
91. default:
92. break;
93. }
94. }

96. return len;
97. }

99. /**
100. * @brief print column name and values of each row
101. *
102. * @param res
103. * @return int
104. */
105. static int printResult(TAOS_RES *res) {
106. int         numFields = taos_num_fields(res);
107. TAOS_FIELD *fields = taos_fetch_fields(res);
108. char        header[256] = {0};
109. int len = 0;
110. for (int i = 0; i < numFields; ++i) {
111. len += sprintf(header + len, "%s ", fields[i].name);
112. }
113. puts(header);

115. TAOS_ROW row = NULL;
116. while ((row = taos_fetch_row(res))) {
117. char temp[256] = {0};
118. printRow(temp, row, fields, numFields);
119. puts(temp);
120. }
121. }

123. int main() {
124. TAOS *taos = taos_connect("localhost", "root", "taosdata", "power", 6030);
125. if (taos == NULL) {
126. puts("failed to connect to server");
127. exit(EXIT_FAILURE);
128. }
129. TAOS_RES *res = taos_query(taos, "SELECT * FROM meters LIMIT 2");
130. if (taos_errno(res) != 0) {
131. printf("failed to execute taos_query. error: %s\n", taos_errstr(res));
132. exit(EXIT_FAILURE);
133. }
134. printResult(res);
135. taos_free_result(res);
136. taos_close(taos);
137. taos_cleanup();
138. }

140. // output:
141. // ts current voltage phase location groupid
142. // 1648432611249 10.300000 219 0.310000 California.SanFrancisco 2
143. // 1648432611749 12.600000 218 0.330000 California.SanFrancisco 2

查看源码

1. <?php

3. use TDengine\Connection;
4. use TDengine\Exception\TDengineException;

6. try {
7. // instantiate
8. $host = 'localhost';
9. $port = 6030;
10. $username = 'root';
11. $password = 'taosdata';
12. $dbname = 'power';
13. $connection = new Connection($host, $port, $username, $password, $dbname);

15. // connect
16. $connection->connect();

18. $resource = $connection->query('SELECT ts, current FROM meters LIMIT 2');
19. var_dump($resource->fetch());
20. } catch (TDengineException $e) {
21. // throw exception
22. throw $e;
23. }

查看源码

查询数据 - 图1note
  1. 无论是使用 REST 连接还是原生连接的连接器,以上示例代码都能正常工作。
  2. 唯一需要注意的是:由于 REST 接口无状态, 不能使用 use db 语句来切换数据库。

异步查询

除同步查询 API 之外,TDengine 还提供性能更高的异步调用 API 处理数据插入、查询操作。在软硬件环境相同的情况下,异步 API 处理数据插入的速度比同步 API 快 2-4 倍。异步 API 采用非阻塞式的调用方式,在系统真正完成某个具体数据库操作前,立即返回。调用的线程可以去处理其他工作,从而可以提升整个应用的性能。异步 API 在网络延迟严重的情况下,优点尤为突出。

需要注意的是,只有使用原生连接的连接器,才能使用异步查询功能。

  • Python
  • C#
  • C
1. import time
2. from ctypes import *

4. from taos import *

7. def fetch_callback(p_param, p_result, num_of_rows):
8. print("fetched ", num_of_rows, "rows")
9. p = cast(p_param, POINTER(Counter))
10. result = TaosResult(p_result)

12. if num_of_rows == 0:
13. print("fetching completed")
14. p.contents.done = True
15. result.close()
16. return
17. if num_of_rows < 0:
18. p.contents.done = True
19. result.check_error(num_of_rows)
20. result.close()
21. return None

23. for row in result.rows_iter(num_of_rows):
24. print(row)
25. p.contents.count += result.row_count
26. result.fetch_rows_a(fetch_callback, p_param)

29. def query_callback(p_param, p_result, code):
30. if p_result is None:
31. return
32. result = TaosResult(p_result)
33. if code == 0:
34. result.fetch_rows_a(fetch_callback, p_param)
35. result.check_error(code)

38. class Counter(Structure):
39. _fields_ = [("count", c_int), ("done", c_bool)]

41. def __str__(self):
42. return "{ count: %d, done: %s }" % (self.count, self.done)

45. def test_query(conn):
46. counter = Counter(count=0)
47. conn.query_a("select ts, current, voltage from power.meters", query_callback, byref(counter))

49. while not counter.done:
50. print(counter)
51. time.sleep(1)
52. print(counter)
53. conn.close()

56. if __name__ == "__main__":
57. test_query(connect())

59. # possible output:
60. # { count: 0, done: False }
61. # fetched  8 rows
62. # 1538548685000 10.300000 219
63. # 1538548695000 12.600000 218
64. # 1538548696800 12.300000 221
65. # 1538548696650 10.300000 218
66. # 1538548685500 11.800000 221
67. # 1538548696600 13.400000 223
68. # 1538548685500 10.800000 223
69. # 1538548686500 11.500000 221
70. # fetched  0 rows
71. # fetching completed
72. # { count: 8, done: True }

查看源码

查询数据 - 图2note

这个示例程序,目前在 Windows 系统上还无法运行

1. using System;
2. using System.Collections.Generic;
3. using TDengineDriver;
4. using TDengineDriver.Impl;
5. using System.Runtime.InteropServices;

7. namespace TDengineExample
8. {
9. public class AsyncQueryExample
10. {
11. static void Main()
12. {
13. IntPtr conn = GetConnection();
14. try
15. {
16. QueryAsyncCallback queryAsyncCallback = new QueryAsyncCallback(QueryCallback);
17. TDengine.QueryAsync(conn, "select * from meters", queryAsyncCallback, IntPtr.Zero);
18. Thread.Sleep(2000);
19. }
20. finally
21. {
22. TDengine.Close(conn);
23. }

25. }

27. static void QueryCallback(IntPtr param, IntPtr taosRes, int code)
28. {
29. if (code == 0 && taosRes != IntPtr.Zero)
30. {
31. FetchRawBlockAsyncCallback fetchRowAsyncCallback = new FetchRawBlockAsyncCallback(FetchRawBlockCallback);
32. TDengine.FetchRawBlockAsync(taosRes, fetchRowAsyncCallback, param);
33. }
34. else
35. {
36. throw new Exception($"async query data failed,code:{code},reason:{TDengine.Error(taosRes)}");
37. }
38. }

40. // Iteratively call this interface until "numOfRows" is no greater than 0.
41. static void FetchRawBlockCallback(IntPtr param, IntPtr taosRes, int numOfRows)
42. {
43. if (numOfRows > 0)
44. {
45. Console.WriteLine($"{numOfRows} rows async retrieved");
46. IntPtr pdata = TDengine.GetRawBlock(taosRes);
47. List<TDengineMeta> metaList = TDengine.FetchFields(taosRes);
48. List<object> dataList = LibTaos.ReadRawBlock(pdata, metaList, numOfRows);

50. for (int i = 0; i < dataList.Count; i++)
51. {
52. if (i != 0 && (i + 1) % metaList.Count == 0)
53. {
54. Console.WriteLine("{0}\t|", dataList[i]);
55. }
56. else
57. {
58. Console.Write("{0}\t|", dataList[i]);
59. }
60. }
61. Console.WriteLine("");
62. TDengine.FetchRawBlockAsync(taosRes, FetchRawBlockCallback, param);
63. }
64. else
65. {
66. if (numOfRows == 0)
67. {
68. Console.WriteLine("async retrieve complete.");
69. }
70. else
71. {
72. throw new Exception($"FetchRawBlockCallback callback error, error code {numOfRows}");
73. }
74. TDengine.FreeResult(taosRes);
75. }
76. }

78. static IntPtr GetConnection()
79. {
80. string host = "localhost";
81. short port = 6030;
82. string username = "root";
83. string password = "taosdata";
84. string dbname = "power";
85. var conn = TDengine.Connect(host, username, password, dbname, port);
86. if (conn == IntPtr.Zero)
87. {
88. throw new Exception("Connect to TDengine failed");
89. }
90. else
91. {
92. Console.WriteLine("Connect to TDengine success");
93. }
94. return conn;
95. }
96. }
97. }

99. // //output:
100. // // Connect to TDengine success
101. // // 8 rows async retrieved

103. // // 1538548685500   |       11.8    |       221     |       0.28    |       california.losangeles   |       2       |
104. // // 1538548696600   |       13.4    |       223     |       0.29    |       california.losangeles   |       2       |
105. // // 1538548685000   |       10.8    |       223     |       0.29    |       california.losangeles   |       3       |
106. // // 1538548686500   |       11.5    |       221     |       0.35    |       california.losangeles   |       3       |
107. // // 1538548685000   |       10.3    |       219     |       0.31    |       california.sanfrancisco         |       2       |
108. // // 1538548695000   |       12.6    |       218     |       0.33    |       california.sanfrancisco         |       2       |
109. // // 1538548696800   |       12.3    |       221     |       0.31    |       california.sanfrancisco         |       2       |
110. // // 1538548696650   |       10.3    |       218     |       0.25    |       california.sanfrancisco         |       3       |
111. // // async retrieve complete.

查看源码

2. /**
3. * @brief call back function of taos_fetch_row_a
4. *
5. * @param param : the third parameter you passed to taos_fetch_row_a
6. * @param res : pointer of TAOS_RES
7. * @param numOfRow : number of rows fetched in this batch. will be 0 if there is no more data.
8. * @return void*
9. */
10. void *fetch_row_callback(void *param, TAOS_RES *res, int numOfRow) {
11. printf("numOfRow = %d \n", numOfRow);
12. int         numFields = taos_num_fields(res);
13. TAOS_FIELD *fields = taos_fetch_fields(res);
14. TAOS       *_taos = (TAOS *)param;
15. if (numOfRow > 0) {
16. for (int i = 0; i < numOfRow; ++i) {
17. TAOS_ROW row = taos_fetch_row(res);
18. char     temp[256] = {0};
19. printRow(temp, row, fields, numFields);
20. puts(temp);
21. }
22. taos_fetch_rows_a(res, fetch_row_callback, _taos);
23. } else {
24. printf("no more data, close the connection.\n");
25. taos_free_result(res);
26. taos_close(_taos);
27. taos_cleanup();
28. }
29. }

31. /**
32. * @brief callback function of taos_query_a
33. *
34. * @param param: the fourth parameter you passed to taos_query_a
35. * @param res : the result set
36. * @param code : status code
37. * @return void*
38. */
39. void *select_callback(void *param, TAOS_RES *res, int code) {
40. printf("query callback ...\n");
41. TAOS *_taos = (TAOS *)param;
42. if (code == 0 && res) {
43. printHeader(res);
44. taos_fetch_rows_a(res, fetch_row_callback, _taos);
45. } else {
46. printf("failed to execute taos_query. error: %s\n", taos_errstr(res));
47. taos_free_result(res);
48. taos_close(_taos);
49. taos_cleanup();
50. exit(EXIT_FAILURE);
51. }
52. }

54. int main() {
55. TAOS *taos = taos_connect("localhost", "root", "taosdata", "power", 6030);
56. if (taos == NULL) {
57. puts("failed to connect to server");
58. exit(EXIT_FAILURE);
59. }
60. // param one is the connection returned by taos_connect.
61. // param two is the SQL to execute.
62. // param three is the callback function.
63. // param four can be any pointer. It will be passed to your callback function as the first parameter. we use taos
64. // here, because we want to close it after getting data.
65. taos_query_a(taos, "SELECT * FROM meters", select_callback, taos);
66. sleep(1);
67. }

69. // output:
70. // query callback ...
71. // ts current voltage phase location groupid
72. // numOfRow = 8
73. // 1538548685500 11.800000 221 0.280000 california.losangeles 2
74. // 1538548696600 13.400000 223 0.290000 california.losangeles 2
75. // 1538548685000 10.800000 223 0.290000 california.losangeles 3
76. // 1538548686500 11.500000 221 0.350000 california.losangeles 3
77. // 1538548685000 10.300000 219 0.310000 california.sanfrancisco 2
78. // 1538548695000 12.600000 218 0.330000 california.sanfrancisco 2
79. // 1538548696800 12.300000 221 0.310000 california.sanfrancisco 2
80. // 1538548696650 10.300000 218 0.250000 california.sanfrancisco 3
81. // numOfRow = 0
82. // no more data, close the connection.

查看源码