Proc*C/C++入门之动态SQL

2017-01-13 19:06:48来源:作者:人点击

Proc*C/C++入门之动态SQL基本概念

在有些情况下, 在编码时 SQL 语句还不能完整地写出来, 而是在程序执行时才能
构造出来,这种在程序执行临时生成的 SQL 语句叫动态 SQL 语句. 利用动态 SQL 来
编写 Pro*C 程序的方法叫动态 SQL 技术!

目的:加强应用程序的功能和灵活 静态SQL —- 在编写应用程序时,使用EXEC SQL关键字直接嵌入的SQL语句;在proc编译应用程序生成c语言的时,都已经确定 动态SQL —- 在运行应用程序时,由用户动态输入的SQL语句。

在下列情况之一不知道时, 使用动态 SQL 技术:

SQL 语句的文本. 宿主变量的个数。 宿主变量的数据类型 引用的数据库对象, 如列, 索引, 序列, 表, 用户名和视图.

Oracle 中动态 SQL 可用以下两种方法实现:一个是 Oracle 自己的方法, 一个是 ANSI 的方法. 一般建议使用 Oracle 的方法,
但对于较复杂的应用, 可以使用 ANSI 的方法, 因为这样可以使自己的程序简化。

动态SQL1

语法:
EXEC SQL EXECUTE IMMEDIATE :host_string

host_string 字符串

限制
不能执行select语言,仅适用于非select语句 在sqlplus上运行的命令,都可以拿过来来执行 语句中不包含输入宿主变量–一个宿主指针变量指向一块内存空间(存有用户输入的SQL语句) 常用于仅执行一次的动态语句 对重复执行多次的动态SQL语句,降低执行效率
nt main01(){    int     ret = 0;        int     i = 0;    char    choosechar;    memset(mySql, 0, sizeof(mySql));    pSql = NULL;    EXEC SQL WHENEVER SQLERROR DO sqlerr02();    connet();    pSql = mySql;    //循环处理sql语言    for(;;)    {        printf("/nplease enter sql(not select ): ");        gets(mySql);        //scanf("%s", mySql); --空格截断        printf("mysql:%s/n", mySql);        printf("任意键继续..../n");        getchar();        EXEC SQL EXECUTE IMMEDIATE :pSql;        EXEC SQL COMMIT;        printf("继续执行吗?/n");        scanf("%c", &choosechar);        fflush(stdin);        if (choosechar=='n' || choosechar=='N')        {            break;        }    }    EXEC SQL COMMIT WORK RELEASE;    printf("return ok.../n");    return ret ;}

动态SQL2

使用PREPARE命令准备SQL语句

EXEC SQL PREPARE statement_name FROM :host_string;

statement_name: 标识符,
host_string:含SQL语句的字符串

使用EXECUTE命令执行SQL语句
EXEC SQL EXECUTE statement_name [USING :host_variable]

如果SQL语句要通过宿主变量赋值,输入SQL语句时要用占位符

仅适用于非select语句 可包含虚拟输入宿主变量和指示器变量,其个数和类型在预编译时已知
int main02(){    int     ret = 0;        int     i = 0;    char    choosechar;    memset(mySql, 0, sizeof(mySql));    pSql = NULL;    EXEC SQL WHENEVER SQLERROR DO sqlerr02();    connet();    pSql = mySql;    //循环处理sql语言    for(;;)    {        printf("/n请输入要更新部门编号 ");        scanf("%d", &deptno);        printf("/n请输入要新loc值 ");        scanf("%s", loc);        //准备动态sql        EXEC SQL PREPARE my_pre_sql FROM 'update dept set loc = :a where deptno = :b';        //执行动态sql        EXEC SQL EXECUTE my_pre_sql USING :loc, :deptno;        EXEC SQL COMMIT;        printf("/n 按任意键继续? ");        getchar();        printf("/n退出键入n, 其他继续? ");        scanf("%c", &choosechar);        fflush(stdin);        if (choosechar=='n' || choosechar=='N')        {            break;        }    }    EXEC SQL COMMIT WORK RELEASE;    printf("return ok.../n");    return ret ;}

动态SQL3

使用PREPARE命令准备SQL语句

EXEC SQL PREPARE statement_name FROM :host_string;

statement_name: 标识符,
host_string:含SQL语句的字符串

使用DECLARE命令定义游标,可以结合游标一块使用
 EXEC SQL DECLARE cursor_name CURSOR FOR statement_name;  EXEC SQL OPEN cursor_name [using host_variable_list] EXEC SQL FETCH cursor_name INTO host_variable_list EXEC SQL CLOSE cursor_name 
查询部门号大于10的所有部门信息 动态sql3 处理选择列表项(select查询出来的结果列数固定) 和 输入宿主变量个数一定 本质:
输入宿主变量个数固定 查询条件固定 输出宿主变量个数固定 返回结果固定
//可以结合游标一块使用int main(){    int     ret = 0;        int     i = 0;    char    choosechar;    memset(mySql, 0, sizeof(mySql));    pSql = NULL;    EXEC SQL WHENEVER SQLERROR DO sqlerr02();    connet();    //EXEC SQL WHENEVER NOT FOUND DO nodata();    //循环处理sql语言    for(;;)    {        printf("/n请输入部门编号 ");        scanf("%d", &deptno);        //准备动态sql        EXEC SQL PREPARE my_pre_sql3 FROM 'select deptno, dname, loc from dept where deptno > :a';        //定义游标        EXEC SQL DECLARE c1 CURSOR FOR my_pre_sql3;        //打开游标        EXEC SQL OPEN c1 USING :deptno;        //提取数据        EXEC SQL WHENEVER NOT FOUND DO break;        for (;;)        {            EXEC SQL FETCH c1 INTO :deptno, :dname,:loc:loc_ind;            printf("%d/t %s/t %s /n", deptno, dname, loc);         }        EXEC SQL CLOSE c1;        EXEC SQL COMMIT;        printf("/n 按任意键继续? ");        getchar();        printf("/n键入 n 退出, 其他继续? ");        scanf("%c", &choosechar);        fflush(stdin);        if (choosechar=='n' || choosechar=='N')        {            break;        }    }    EXEC SQL COMMIT WORK RELEASE;    printf("return ok.../n");    return ret ;}   

动态SQL4

既适用于SELECT语句,也适用于非SELECT语句、 工程中主要使用该模式

与前面的方法相比有两个突出的不同点:

不但包含选择表项或虚拟输入宿主变量,而且它们的个数或数据类型在编译时还不知道 在其它方法中,ORACLE和C之间的数据类型转换是自动实现的。而在方法4中,由于动态语句中的宿主变量个数和类型在编译时还不知道,因此不能实现自动转换,必须由程序来控制数据类型之间的转换

主要信息:

选择表项和实输入宿主变量的个数 每一个选择表项和实输入宿主变量的成年高度 每一个选择表项和实输入宿主变量的数据类型 每一个输出宿主变量和实输入宿主变量的内存单元地址

ANSI模式

/* 包含C头文件 */  #include   #include   #include   #include   #include   /* 包含SQLDA和SQLCA结构 */  #include   #include   /* 定义绑定变量和选择列表项的最大个数 */  #define MAX_ITEMS       40  /* 定义绑定变量和选择列表项名称的最大长度 */  #define MAX_VNAME_LEN   30  /* 定义指示变量名称的最大长度 */  #define MAX_INAME_LEN   30  void connect();  void sql_error();  void alloc_descriptors(int , int , int);  void dealloc_descriptors();  void set_bind_variables();  void process_select_list();  /* 定义绑定描述区和选择描述区 */  SQLDA* bind_dp;  SQLDA* select_dp;  /* 定义输入宿主变量:存放动态SQL语句 */  char sql_stat[100];   char current_date[20];     int main()  {      /* 安装错误处理句柄 */      exec sql whenever sqlerror do sql_error();      /* 连接到数据库 */      connect2();      /* 分配绑定描述区和选择描述区 */      alloc_descriptors(MAX_ITEMS , MAX_VNAME_LEN , MAX_INAME_LEN);      for( ; ; )      {          printf("请输入动态SQL语句(exit:退出):");          gets(sql_stat);          /* EXIT(exit):退出 */          if(0 == strncmp(sql_stat , "exit" , 4) || 0 == strncmp(sql_stat , "EXIT" , 4))              break;          /* 准备动态SQL语句 */          exec sql prepare s from :sql_stat;          /* 定义游标 */          exec sql declare c cursor for s;          /* 出错,继续下一循环 */          if(0 != sqlca.sqlcode)              continue;          /* 设置绑定变量 */          set_bind_variables();          /*          * 打开游标          * select语句:生成结果集          * 其他SQL语句:执行语句          */          exec sql open c using descriptor bind_dp;          /*          * select语句          */          if(0 == strncmp(sql_stat , "select" , 6) || 0 == strncmp(sql_stat , "SELECT" , 6))         {              process_select_list();           }          /* 关闭游标 */          exec sql close c;      }      /* 释放选择描述区和选择描述区 */      dealloc_descriptors();      /* 提交事务,断开连接 */      exec sql commit work release;      puts("谢谢使用Oracle动态SQL方法四!/n");      return 0;  }  void connect2()  {      /* 定义宿主变量 */      char username[20] , password[20] , server[20];      /* 输入用户名、口令和网络服务名 */      printf("输入用户名:");      gets(username);      printf("输入口令:");      gets(password);      printf("输入网络服务名:");      gets(server);      /* 连接到数据库 */      EXEC SQL CONNECT :username identified by :password using :server;  }  void sql_error()  {      /* 显示SQL错误信息 */      printf("%.*s/n" , sqlca.sqlerrm.sqlerrml , sqlca.sqlerrm.sqlerrmc);  }  void alloc_descriptors(int size , int max_vname_len , int max_iname_len)  {      int i;      /* 分配绑定描述区和选择描述区 */      bind_dp = SQLSQLDAAlloc(0 , size , MAX_VNAME_LEN , MAX_INAME_LEN);      select_dp = SQLSQLDAAlloc(0 , size , MAX_VNAME_LEN , MAX_INAME_LEN);      /* 为指示变量、绑定变量和选择列表项分配内存 */      for(i = 0 ; i != MAX_ITEMS ; ++i)      {          bind_dp->I[i] = (short*)malloc(sizeof(short));          select_dp->I[i] = (short*)malloc(sizeof(short));          bind_dp->V[i] = (char*)malloc(1);          select_dp->V[i] = (char*)malloc(1);      }  }  void dealloc_descriptors()  {      int i;      /* 释放指示变量、绑定变量和选择列表项占用的内存 */      for(i = 0 ; i != MAX_ITEMS ; ++i)      {          if(bind_dp->V[i] != (char*)0)              free(bind_dp->V[i]);          free(bind_dp->I[i]);          if(select_dp->V[i] != (char*)0)              free(select_dp->V[i]);          free(select_dp->I[i]);      }      /* 释放绑定描述区和选择描述区 */      SQLSQLDAFree(0 , bind_dp);      SQLSQLDAFree(0 , select_dp);  }  void set_bind_variables()  {      int i;      char bind_var[64];      /* 设置绑定变量最大个数 */      bind_dp->N = MAX_ITEMS;      /* 绑定变量名称: 绑定描述区 */      exec sql describe bind variables for s into bind_dp;      /* 设置绑定变量实际个数 */      bind_dp->N = bind_dp->F;      /* 循环处理绑定变量 */      for(i = 0 ; i != bind_dp->F ; ++i)      {          /* 显示绑定变量名 */          printf("请输入绑定变量%.*s的值:" , (int)bind_dp->C[i] , bind_dp->S[i]);          /* 输入绑定变量的值 */          gets(bind_var);          /* 设置绑定变量的长度成员 */          bind_dp->L[i] = strlen(bind_var);          /* 为绑定变量数据缓冲区重新分配内存(多一位,留给'/0') */          bind_dp->V[i] = (char*)realloc(bind_dp->V[i] , bind_dp->L[i] + 1);          /* 绑定变量数据: 数据缓冲区 */          strcpy(bind_dp->V[i] , bind_var);          /* 设置指示变量,处理NULL */          if(0 == strncmp(bind_var , "NULL" , 4) || 0 == strncmp(bind_var , "null" , 4))              *bind_dp->I[i] = -1;          else              *bind_dp->I[i] = 0;          /* 设置数据缓冲区数据类型代码->char */          bind_dp->T[i] = 1;      }  }  void process_select_list()  {      int i , null_ok , precision , scale;      char title[MAX_VNAME_LEN];      /* 设置选择列表项的最大个数 */      select_dp->N = MAX_ITEMS;      /* 选择列表项: 选择描述区 */      exec sql describe select list for s into select_dp;      /* 设置选择列表项的实际个数 */      select_dp->N = select_dp->F;      /* 循环处理选择列表项 */      for(i = 0 ; i != select_dp->F ; ++i)      {          /* 清除select_dp->T[i]的高位->null */          SQLColumnNullCheck(0 , (unsigned short*)&select_dp->T[i]              , (unsigned short*)&select_dp->T[i] , &null_ok);          /* 根据内部数据类型确定外部类型数据长度(显示长度) */          switch(select_dp->T[i])          {          case 2:              /* number类型,取得精度与标度 */              //SQLNumberPrecV6(0 , (unsigned short*)&select_dp->T[i] , &precision , &scale);             SQLNumberPrecV6(0 , (unsigned long *)&select_dp->L[i] , &precision , &scale);  //wangbaoming modify 201409            if(scale > 0)                  /* 实数: 显示长度:float  */                  select_dp->L[i] = sizeof(float);              else                  /* 整数: 显示长度 int */                  select_dp->L[i] = sizeof(int);              break;          case 12:              /* DATA数据类型(DD-MON-YY) */              select_dp->L[i] = 9;              break;          }          /* 根据变量长度,重新为选择列表项数据缓冲区分配内存 */          if(2 != select_dp->T[i])              /* 其他类型 */              select_dp->V[i] = (char*)realloc(select_dp->V[i] , select_dp->L[i] + 1);          else              /* number类型 */              select_dp->V[i] = (char*)realloc(select_dp->V[i] , select_dp->L[i]);          /* 初始化title */          memset(title , ' ' , MAX_VNAME_LEN);          /* 选择列表项名称: title */          strncpy(title , select_dp->S[i] , select_dp->C[i]);          /* 显示列名 */          if(2 == select_dp->T[i])              if(scale > 0)                  printf("/t%.*s" , select_dp->L[i] + 3, title);              else                  printf("/t%.*s" , select_dp->L[i] , title);          else              printf("/t%-.*s" , select_dp->L[i] , title);          /* 根据Oracle内部类型确定外部数据类型(显示类型) */          if( 2 == select_dp->T[i])          {              /* number 类型*/              if(scale > 0)                  /* float */                  select_dp->T[i] = 4;              else                  /* int */                  select_dp->T[i] = 3;          }          else              /* char */              select_dp->T[i] = 1;      }      printf("/n");      /* 提取数据完毕->结束循环 */      exec sql whenever not found do break;      /* 循环处理选择列表数据 */      for( ; ; )      {          /* 数据->选择描述区 */          exec sql fetch c using descriptor select_dp;          /* 显示数据 */          for( i = 0 ; i != select_dp->F ; ++i)          {              if(*select_dp->I[i] < 0){                  /* 处理NULL */                  printf("/tNULL");              }else{                  if(3 == select_dp->T[i]){                      /* int */                      printf("/t%d" , *(int*)select_dp->V[i]);                  }else if(4 == select_dp->T[i]){                      /* float */                      printf("/t%8.2f" , *(float*)select_dp->V[i]);                  }else{                      /* char */                      printf("/t%.*s" , select_dp->L[i] , select_dp->V[i]);                  }                  }          }          printf("/n");      }  }  

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台