Proc *C/C++入门之游标访问数据库

本文介绍Oracle中如何将宿主变量转换为外部数据类型,并详细讲解了普通游标与滚动游标的定义、打开、提取数据及关闭等操作步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

数据类型转换

  • Oracle外部数据类型中的string是以零结尾的字符串,类似于varchar2类型!
  • char在数据不满的时候,后面部分会被填充为空格
  • 在SQL语句中的宿主数据类型可以人为的转换为Oracle的外部数据类型,所以我们可以把char [20]转换为string类型,避免产生多余的空格虽然varchar也可以避免空格,但是varchar还要引用里卖弄具体的成员,所以不是很方便,最方便的方法就是转换为string。

转换语法如下:

  • 将定义好的宿主变量进行类型转换–操作同一个变量,只不过变量的类型变成了外部数据类型
EXEC SQL VAR host_variable IS type_name[(length)];
char  emp_name[11];
EXEC SQL VAR emp_name IS STRING(11);

以后Oracle操作emp_name的时候就当做STRING(11)来操作!类似于强制类型转换!

  • 直接将宿主类型转换为外部数据类型–用新的类型定义变量,和之前定义的类型等价,但是可以避免空格
EXEC SQL TYPE user_type IS type_name[(length)];
        typedef struct {
            short  len;
            char   buff[4000];
        } graphics;
        EXEC SQL TYPE graphics IS VARRAW(4000);

以后graphics就等价于 VARRAW(4000)类型,可以用它定义其他变量!类似于typedef定义类型别名!只不过是真的产生了新类型(由宿主类型变成了外部数据类型)!

游标

游标是为了操作多行多列时,逐行或随机处理数据而设计的。数组是一次性获取多条数据,但是对于数据条目很多时,使用数组一次性接收所有数据是不合理的!用游标有目的性的获取数据才是明智之举!

普通游标:只能单方向一行一行的检索数据。

滚动游标:可以随机指向数据库表里的数据,可以指向任意一行!

操作步骤:

  1. 定义游标
EXEC SQL DECLARE emp_cursor CURSOR FOR
       select empno,ename,sal from emp where deptno=10;
  1. 打开游标
EXEC SQL  OPEN emp_cursor ;

(Open cursor: put the select results into a memory place,and the cursor pointer points to the first row data.)

  1. 提取数据 fetch into
/** 在此处理数据处理**/
EXEC SQL FETCH emp_cursor INTO :empnum,:name:salary;

INTO 后面变量的顺序要和所查询的表的条目里的列名的顺序一致,一般是宿主变量

(After fetch, cursor pointer moves down one line. Use loop for multiple rows)

  1. EXEC SQL CLOSE emp_cursor;

普通游标综合示例


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "sqlca.h"

extern sqlgls(char * , size_t *, size_t * );
extern sqlglmt(void *,char *,size_t *,size_t *);

void sqlerr02()
{
    char    stm[120];
    size_t  sqlfc, stmlen=120;
    unsigned int ret = 0;

    //出错时,可以把错误SQL语言给打印出来
    EXEC SQL WHENEVER SQLERROR CONTINUE;

    ret = sqlgls(stm, &stmlen, &sqlfc); 
    printf("出错的SQL:%.*s\n", stmlen, stm);
    printf("出错原因:%.*s\n", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc);
    //printf("出错原因:%.70s\n", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc);
    EXEC SQL ROLLBACK WORK RELEASE;
    exit(1);
}

void nodata()
{
    int ret = 0;
    printf("没有发现数据\n");
    if (sqlca.sqlcode != 0)
    {
        ret = sqlca.sqlcode;
        printf("sqlca.sqlcode: err:%d \n", sqlca.sqlcode);
        return ;
    }
}


typedef char dnameType[20];
typedef char locType[20];

EXEC SQL BEGIN DECLARE SECTION;
    EXEC SQL TYPE dnameType is string(20);
    EXEC SQL TYPE locType is string(20);
    char    *usrname = "scott";
    char    *passwd = "lzj123529";
    char    *serverid = "orcl";

    int             deptno;
    dnameType       dname; //string 数据类型  //varchar类型 和 char 类型的区别. 与编译选项有关系
    short           dname_ind;
    locType         loc;
    short           loc_ind;    
EXEC SQL END DECLARE SECTION;

void connet()
{
    int ret = 0;
    //连接数据库
    EXEC SQL CONNECT:usrname IDENTIFIED BY:passwd USING:serverid ;
    if (sqlca.sqlcode != 0)
    {
        ret = sqlca.sqlcode;
        printf("sqlca.sqlcode: err:%d \n", sqlca.sqlcode);
        return ;
    }
    else
    {
        printf("connect ok...\n");
    }

}

int main()
{
    int ret = 0;    
    int i = 0;

    EXEC SQL WHENEVER SQLERROR DO sqlerr02();
    connet();


    //1   定义游标 为某一次查询定义一个游标
    EXEC SQL DECLARE c CURSOR FOR
        select deptno, dname, loc from dept ;

    //2.  打开游标
    EXEC SQL  OPEN c ;


    //3.  提取数据 fetch into
    EXEC SQL WHENEVER NOT FOUND DO BREAK;
    while(1)
    {
            EXEC SQL FETCH c INTO :deptno, :dname:dname_ind, :loc:loc_ind;
            if (loc_ind == -1)
            {
                strcpy(loc, "NULL");
            }
            if (dname_ind == -1)
            {
                printf("dname is null \t");
            }

            printf("%d, %s, %s\n", deptno, dname,loc );

    }

    //4.  EXEC SQL CLOSE c;
    EXEC SQL CLOSE c;


    EXEC SQL COMMIT WORK RELEASE;
    printf("return ok...\n");

    return ret ;
}

注意EXEC SQL WHENEVER NOT FOUND DO BREAK;的利用技巧

  • 演示效果
oracle@lzj:~$ ./array 
connect ok...
50, 20name, 中国
10, ACCOUNTING, NEW YORK
20, RESEARCH, DALLAS
30, SALES, NULL
40, OPERATIONS, BOSTON
61, 中国2, 中国
return ok...

滚动游标

定义的时候多了一个SCROLL关键字

在游标变量的前面多了一些表示偏移量的关键字:

关键字说明
LAST最后一行数据
FIRST第一行数据
ABSOLUTE n绝对位置的数据:第n条数据
RELATIVE n相对位置:相对当前游标位置的第n条数据
NEXT下一条数据
PRIOR前一条数据
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "sqlca.h"

//演示滚动游标查询数据

extern sqlgls(char * , size_t *, size_t * );
extern sqlglmt(void *,char *,size_t *,size_t *);
void connet();

void sqlerr02();
void sqlerr02()
{
    char    stm[120];
    size_t  sqlfc, stmlen=120;
    unsigned int ret = 0;

    //出错时,可以把错误SQL语言给打印出来
    EXEC SQL WHENEVER SQLERROR CONTINUE;

    ret = sqlgls(stm, &stmlen, &sqlfc); 
    printf("出错的SQL:%.*s\n", stmlen, stm);
    printf("出错原因:%.*s\n", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc);
    //printf("出错原因:%.70s\n", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc);
    EXEC SQL ROLLBACK WORK RELEASE;
    exit(1);
}

void nodata()
{
    int ret = 0;
    printf("没有发现数据\n");
    if (sqlca.sqlcode != 0)
    {
        ret = sqlca.sqlcode;
        printf("sqlca.sqlcode: err:%d \n", sqlca.sqlcode);
        return ;
    }
}


typedef char dnameType[20];
typedef char locType[20];

EXEC SQL BEGIN DECLARE SECTION;
    EXEC SQL TYPE dnameType is string(20);
    EXEC SQL TYPE locType is string(20);
    char    *usrname = "myscott";
    char    *passwd = "22";
    char    *serverid = "orcl";

    int             deptno;
    dnameType       dname; //string 数据类型  
    short           dname_ind;
    locType         loc;
    short           loc_ind;    
EXEC SQL END DECLARE SECTION;

int main()
{
    int ret = 0;    
    int i = 0;

    EXEC SQL WHENEVER SQLERROR DO sqlerr02();
    connet();
    //EXEC SQL WHENEVER NOT FOUND DO nodata();


    //1 定义游标  declare cursor  在为某一次查询
    EXEC SQL DECLARE dept_cursor SCROLL  CURSOR FOR 
        select deptno, dname, loc from dept;
    //2 打开游标 open cursor 
    EXEC SQL OPEN dept_cursor;

    //3 获取数据 fetch data
    //while (1)
    {
        //EXEC SQL WHENEVER NOT FOUND DO break;

        //查询最后一条数据
        EXEC SQL FETCH LAST dept_cursor INTO :deptno, :dname:dname_ind, :loc:loc_ind;
        //printf("条目数:%d\t", sqlca.sqlerrd[2]);
        printf("%d\t %s\t %s \n", deptno, dname, loc );

        //查询第一条数据
        EXEC SQL FETCH FIRST dept_cursor INTO :deptno, :dname:dname_ind, :loc:loc_ind;
        //printf("条目数:%d\t", sqlca.sqlerrd[2]);
        printf("%d\t %s\t %s \n", deptno, dname, loc );

        //查询第3条数据
        EXEC SQL FETCH ABSOLUTE 3 dept_cursor INTO :deptno, :dname:dname_ind, :loc:loc_ind;
        //printf("条目数:%d\t", sqlca.sqlerrd[2]);
        printf("%d\t %s\t %s \n", deptno, dname, loc );

        //查询相对第3条数据 也就是第6条
        EXEC SQL FETCH RELATIVE 3 dept_cursor INTO :deptno, :dname:dname_ind, :loc:loc_ind;
        //printf("条目数:%d\t", sqlca.sqlerrd[2]);
        printf("%d\t %s\t %s \n", deptno, dname, loc );

        //查询下一条
        EXEC SQL FETCH NEXT dept_cursor INTO :deptno, :dname:dname_ind, :loc:loc_ind;
        //printf("条目数:%d\t", sqlca.sqlerrd[2]);
        printf("%d\t %s\t %s \n", deptno, dname, loc );

        //查询前一条
        EXEC SQL FETCH PRIOR  dept_cursor INTO :deptno, :dname:dname_ind, :loc:loc_ind;
        //printf("条目数:%d\t", sqlca.sqlerrd[2]);
        printf("%d\t %s\t %s \n", deptno, dname, loc );

    }

    //4 关闭游标 close data
    EXEC SQL CLOSE dept_cursor; 
    EXEC SQL COMMIT WORK RELEASE;
    printf("return ok...\n");

    return ret ;
}

void connet()
{
    int ret = 0;
    //连接数据库
    EXEC SQL CONNECT:usrname IDENTIFIED BY:passwd USING:serverid ;
    if (sqlca.sqlcode != 0)
    {
        ret = sqlca.sqlcode;
        printf("sqlca.sqlcode: err:%d \n", sqlca.sqlcode);
        return ;
    }
    else
    {
        printf("connect ok...\n");
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值