
# 处理结果集
- 返回单行结果的SELECT语句可以直接使用EXEC SQL执行，请参见[执行SQL语句](https://support.huaweicloud.com/distributed-devg-v10-gaussdb/gaussdb-12-0275.html)章节。
  示例：
  ```
  /* 首先建立一个表并插入数据 */
  EXEC SQL CREATE TABLE test_table (number1 integer, number2 integer);
  EXEC SQL INSERT INTO test_table (number1, number2) VALUES (2, 1);
  /* 查询结果为单行,:num 为宿主变量 */
  EXEC SQL SELECT number1 INTO :num FROM test_table WHERE number2 = 1;
  ```
  
- 若要处理多行结果集，则必须使用游标，如何使用游标请参考[使用游标]。
  示例：
  ```
  /* 首先建立一个表并插入数据 */
  EXEC SQL CREATE TABLE test_table (number1 integer, number2 integer);
  EXEC SQL INSERT INTO test_table (number1, number2) VALUES (2, 1);
  EXEC SQL INSERT INTO test_table (number1, number2) VALUES (3, 1);
  EXEC SQL INSERT INTO test_table (number1, number2) VALUES (4, 1);
  EXEC SQL INSERT INTO test_table (number1, number2) VALUES (5, 1);
  /* 定义宿主变量 */
  EXEC SQL BEGIN DECLARE SECTION;
  int v1;
  int v2;
  EXEC SQL END DECLARE SECTION;
  /* 声明游标 */
  EXEC SQL DECLARE test_bar CURSOR FOR SELECT number1, number2 FROM test_table ORDER BY number1;
  /* 打开游标 */
  EXEC SQL OPEN test_bar;
  /* 当游标到达结果集末尾时跳出循环 */
  EXEC SQL WHENEVER NOT FOUND DO BREAK;
  /* 获取查询结果集 */
  while(1)
  {
      EXEC SQL FETCH NEXT FROM test_bar INTO :v1, :v2;
      printf("number1 = %d, number2 = %d\n",v1,v2);
  }
  /* 关闭游标 */
  EXEC SQL CLOSE test_bar;
  ```
  
 #### 使用游标
使用游标可以检索出多行的结果集，应用程序必须声明一个游标并且从游标中抓取每一行数据。
1. 声明一个游标： 
   ```
   EXEC SQL DECLARE c CURSOR FOR SELECT * FROM tb1;
   ```
   
   
2. 打开游标： 
   ```
   EXEC SQL OPEN c;
   ```
   
   
3. 从游标中抓取一行数据： 
   ```
   EXEC SQL FETCH 1 IN c INTO :a, :str;
   ```
   
   
4. 关闭游标： 
   ```
   EXEC SQL CLOSE c;
   ```
   
   
![](https://support.huaweicloud.com/distributed-devg-v10-gaussdb/public_sys-resources/note_3.0-zh-cn.png)
在开启GUC参数enable_ecpg_cursor_duplicate_operation（默认开启）的情况下，使用ecpg连接ORA兼容数据库时，允许通过如下方式重复打开/关闭游标：
```
EXEC SQL OPEN c;
EXEC SQL OPEN c;
EXEC SQL CLOSE c;
EXEC SQL CLOSE c;
```
更多游标的使用细节请参见[DECLARE](https://support.huaweicloud.com/distributed-devg-v10-gaussdb/gaussdb-12-0282.html)，关于FETCH命令的细节请参见《参考》中"SQL参考 \> SQL语法 \> F \> FETCH"章节。
完整使用示例：
前提条件：需要提前创建testdb数据库。
```
#include <string.h>
#include <stdlib.h>
int main(void)
{
    EXEC SQL BEGIN DECLARE SECTION;
    int *a = NULL;
    char *str = NULL;
    EXEC SQL END DECLARE SECTION;
    int count = 0;
    /* 提前创建testdb */ 
    EXEC SQL CONNECT TO testdb ;
    EXEC SQL SET AUTOCOMMIT TO OFF;
    EXEC SQL BEGIN;
    EXEC SQL DROP TABLE IF EXISTS tb1;
    EXEC SQL CREATE TABLE tb1(id int, info text);
    EXEC SQL INSERT INTO tb1 (id, info) SELECT generate_series(1, 100000), 'test';
    EXEC SQL SELECT COUNT(*) INTO :a FROM tb1;
    printf ("a is %d\n", *a);
    EXEC SQL COMMIT;
    /* 定义游标 */
    EXEC SQL DECLARE c CURSOR FOR SELECT * FROM tb1;
    /* 打开游标 */
    EXEC SQL OPEN c;
    EXEC SQL WHENEVER NOT FOUND DO BREAK;
    while(1) {
        /* 抓取数据 */
        EXEC SQL FETCH 1 IN c INTO :a, :str;
        count++;
        if (count == 100000) {
            printf("Fetch res: a is %d, str is %s", *a, str);
        }
    }
    /* 关闭游标 */
    EXEC SQL CLOSE c;
    EXEC SQL SET AUTOCOMMIT TO ON;
    EXEC SQL DROP TABLE tb1;
    EXEC SQL DISCONNECT;
    ECPGfree_auto_mem();
    return 0;
}
```
运行结果如下：
```
a is 100000
Fetch res: a is 100000, str is test
```
当cursor指向表的某一行时，可以使用**WHERE CURRENT OF cursor_name**语法更新或删除cursor当前指向的行。使用限制及约束请参见《参考》中"SQL参考 \> SQL语法 \> U \> UPDATE"章节对此语法介绍。
完整使用示例：
```
#include <string.h>
#include <stdlib.h>
int main(void)
{
    EXEC SQL BEGIN DECLARE SECTION;
    int va;
    int vb;
    EXEC SQL END DECLARE SECTION;
    int count = 0;
    /* 提前创建testdb */
    EXEC SQL CONNECT TO testdb;
    EXEC SQL SET AUTOCOMMIT TO OFF;
    EXEC SQL BEGIN;
    EXEC SQL DROP TABLE IF EXISTS t1;
    EXEC SQL CREATE TABLE t1(c1 INT, c2 INT);
    EXEC SQL INSERT INTO t1 VALUES(generate_series(1, 10000), generate_series(1, 10000));
    EXEC SQL COMMIT;
    /* 定义游标 */
    EXEC SQL DECLARE cur1 CURSOR FOR SELECT * FROM t1 WHERE c1 < 100 FOR UPDATE;
    /* 打开游标 */
    EXEC SQL OPEN cur1;
    /* 抓取数据 */
    EXEC SQL FETCH 1 IN cur1 INTO :va, :vb;
    printf("c1: %d, c2: %d\n", va, vb);
    /* 使用 WHERE CURRENT OF 删除当前行 */
    EXEC SQL DELETE FROM t1 WHERE CURRENT OF cur1;
    /* 继续抓取数据 */
    EXEC SQL FETCH 1 IN cur1 INTO :va, :vb;
    EXEC SQL FETCH 1 IN cur1 INTO :va, :vb;
    printf("c1: %d, c2: %d\n", va, vb);
    /* 使用 WHERE CURRENT OF 更新当前行 */
    EXEC SQL UPDATE t1 SET c2 = 21 WHERE CURRENT OF cur1;
    /* 查询更新后的数据 */
    EXEC SQL SELECT c2 INTO :vb FROM t1 WHERE c1 = :va;
    printf("c1: %d, c2: %d\n", va, vb);
    /* 关闭游标 */
    EXEC SQL CLOSE cur1;
    /* 恢复自动提交并清理 */
    EXEC SQL SET AUTOCOMMIT TO ON;
    EXEC SQL DROP TABLE t1;
    EXEC SQL DISCONNECT;
    ECPGfree_auto_mem();
    return 0;
}
```
运行结果如下：
```
c1: 1, c2: 1
c1: 3, c2: 3
c1: 3, c2: 21
```
