• proc程序中使用PLSQL、Exception 、 动态SQL(day08)


    1. proc中如何使用plsql
      1.1 使用plsql的语法
        exec sql execute
            begin
                /* 相当于plsql的匿名块 */
            end;
        end-exec;
    
        在预编译时,需要加如下两个选项:
        sqlcheck = semantics
        userid = 用户名/密码:在预编译时时,检查调用的过程、函数等子程序是否存在及合法
       
    
      
        1.2 在proc中调用存储过程
          1) 创建一个存储过程,传入两个参数,把两数之和存入第二个参数
           create or replace procedure getsum_zsm_00(
               var_a number,var_b in out number)
           is
           begin
                var_b:=var_a + var_b;
           end;   
    
         2) 在proc中调用存储过程
          
          案例:callproc.pc
    #include <stdio.h>
    exec sql include sqlca;
    int main(void)
    {
        exec sql begin declare section;
            char userpasswd[30]="openlab/open123";
            int x = 1;
            int y = 9526;
        exec sql end declare section;
        exec sql connect:userpasswd;
        exec sql execute
            begin
                getsum_zsm_00(:x,:y);
            end;
        end-exec;
        exec sql commit work release;
        printf("%d
    ",y);
        return 0;
    }
    
    
    
    
    
    1.3 在proc中使用函数
         1) 创建一个函数,传入两个数字,返回最大值
             create or replace function getmax_zsm_00(
                var_a number,var_b number) return number
             is
             begin
                if var_a > var_b then
                   return var_a;
                end if;
                return var_b;
             end;
             
         2) 编写一个proc程序,调用该函数
           
            案例:callfunc.pc
    #include <stdio.h>
    exec sql include sqlca;
    int main(void)
    {
        exec sql begin declare section;
            char userpasswd[30]="openlab/open123";
            int x = 1;
            int y = 9526;
            int max=0;
        exec sql end declare section;
        exec sql connect:userpasswd;
        exec sql execute
            begin
                :max:=getmax_zsm_00(:x,:y);
            end;
        end-exec;
        exec sql commit work release;
        printf("%d
    ",max);
        return 0;
    }
    
    
    
    2. 连接数据库
      2.1 本地数据库连接
        exec sql connect:用户名/密码;
        exec sql connect:用户名 identified by :密码;
      2.2 远程连接数据库
        需要提供一个远程连接的描述字符串,包括:ip地址、端口号、oracle数据库的服务ID(服务器名)
       这个字符串有固定格式,程序员可以根据格式拼接字符串
       a文件中,一般有远程连接的$ORACLE_HOME/network/admin/tnsnames.or描述字符串的配置
       $ORACLE_HOME:环境变量,oracle的安装路径
        
        ip地址是要访问的数据库所在的服务器的ip地址
        端口号默认1521
    
        有了远程数据库的描述字符串,使用using引入描述:
        exec sql connect:用户名/密码 using :描述字符串;
        
        案例:rdbconn.pc
    #include <stdio.h>
    exec sql include sqlca;
    int main(void){
        exec sql begin declare section;
         char userpasswd[30]="openlab/open123";
    //     char rdbdesc[20] = "DB10";
         char rdbdesc[200] = "(DESCRIPTION ="
           "(ADDRESS = (PROTOCOL = TCP)(HOST = 172.60.5.80)(PORT = 1521))"
             "(CONNECT_DATA ="
              "(SERVER = DEDICATED)"
                "(SERVICE_NAME = orcl)"
             ")"
           ")";
         char name[25];
        exec sql end declare section;
        exec sql connect:userpasswd using :rdbdesc;
        if(sqlca.sqlcode)
            printf("%s
    ",sqlca.sqlerrm.sqlerrmc);
        exec sql select first_name into :name
            from s_emp where id=1;
        exec sql commit work release;
        printf("%s
    ",name);
        return 0;
    }
    
    
    
    
    
        
        如果面对的是多个数据库,可以他通过定义标签,然后使用标签区分访问的是哪个数据库。
        
        案例:mdbconn.pc
    #include <stdio.h>
    exec sql include sqlca;
    int main(void)
    {
        exec sql begin declare section;
           char userpasswd80[30]="openlab/open123";
           char userpasswd81[30]="openlab/open123";
           char rdbdesc[20]="DB10";
           char name80[25];
           char name81[25];
           char label80[10]="80";
           char label81[10]="81";
        exec sql end declare section;
        exec sql connect:userpasswd81 at :label81;
        exec sql connect:userpasswd80 at :label80 using :rdbdesc;
        exec sql at :label80 select first_name into :name80
            from s_emp where id=1;
        exec sql at :label81 select first_name into :name81
            from s_emp where id=1;
        exec sql at :label80 commit work release;
        exec sql at :label81 commit work release;
        printf("172.60.5.80:%s
    ",name80);
        printf("172.60.5.81:%s
    ",name81);
        return 0;
    }
    
    
    
    
    
    3. proc中的错误处理
      3.1 局部的错误处理方式
         sqlca.sqlcode   //错误码
         sqlca.sqlerrm.sqlerrmc    //错误信息
      3.2 全局的错误处理方式
         错误处理方案只写一次,出现匹配的类型的错误,自动查找错误处理方案并执行
         
         exec sql whenever 条件 动作;
         条件就是错误的方式,有三种:
            sqlerror:        sql语句错误
            notfound:     没有找到数据
            sqlwarning:  sql语句出现警告(不常用)
         动作就是错误处理方案,包括:
            do 错误处理函数():      条件发生后,调用错误处理函数
            do break:                     退出循环
            continue:                     继续
            stop:                             停止执行代码(不常用)
            goto 标签:                    跳转到标签处(不常用)     标签: < <标签名> >
    
        3.3 举例:删除一张不存在的表
          案例:sqlerror.pc
    #include <stdio.h>
    exec sql include sqlca;
    void sqlerror()
    {
        printf("sqlerror:%s
    ",sqlca.sqlerrm.sqlerrmc);
    }
    void notfound()
    {
        printf("notfound:%s
    ",sqlca.sqlerrm.sqlerrmc);
    }
    int main(void)
    {
        exec sql begin declare section;
            char userpasswd[30]="openlab/open123";
            char name[25];
            int id=100;
        exec sql end declare section;
        exec sql whenever sqlerror do sqlerror();
        exec sql whenever notfound do notfound();
        exec sql connect:userpasswd;
        exec sql drop table tablename;
        exec sql select first_name into :name from s_emp
            where id=:id;
        exec sql commit work release;
        return 0;
    }
    
    
    
    
        
          proc中默认对错误是忽略的(不提示、不中断)
          
          sql语句出现错误,会向上查找对应的全局处理语句,如果有,执行处理方案。如果没有,继续执行后面的代码。
    
     
    4. proc中的数据处理
      1) 单行单列的结果集     使用一个宿主变量解决
           ....
           char name[25];
           .....
           exec sql select first_name into :name from s_emp
                  where id=1;
           .....
      2) 单行多列的结果集     使用多个宿主变量 或 结构体变量 解决
          exec sql select id,first_name,salary into :id,:name,:sal 
               from  s_emp where id=1;
    
          案例:selecta.pc
    #include <stdio.h>
    exec sql include sqlca;
    struct emp{
        int id;
        char name[25];
        double sal;
    };
    int main(void)
    {
        exec sql begin declare section;
            char userpasswd[30]="openlab/open123";
            struct emp e;
        exec sql end declare section;
        exec sql connect:userpasswd;
        exec sql select id,first_name,salary into :e
            from s_emp where id=1;
        exec sql commit work release;
        printf("%d %s %g
    ",e.id,e.name,e.sal);
        return 0;
    }
    
    
    
    3) 多行单列的结果集   使用一个数组解决
          exec sql select first_name into :names from s_emp;
    
      4) 多行多列的结果集   使用多个数组、结构体数组、游标解决
          exec sql select id,name,region_id into :ids,:names,:rids 
               from  s_dept;
          练习:使用多个数组接收s_dept表中的全部信息,并循环输出。
               添加必要的错误处理
    
          案例:selectb.pc
    #include <stdio.h>
    exec sql include sqlca;
    struct emp{
        int id;
        char name[25];
        double sal;
    };
    int main(void)
    {
        exec sql begin declare section;
            char userpasswd[30]="openlab/open123";
            struct emp emps[50];
        exec sql end declare section;
        exec sql connect:userpasswd;
        exec sql select id,first_name,salary into :emps
            from s_emp;
        exec sql commit work release;
        int i=0;
        for(;i<sqlca.sqlerrd[2];i++)
        {
            printf("%d %s %g
    ",emps[i].id,emps[i].name,
                    emps[i].sal);
        }
        return 0;
    }
    
    
    
    
    
          在proc中使用游标的步骤:
          a.声明游标
             exec sql declare 游标名 cursor for select语句;
          b. 打开游标
             exec sql open 游标名;
          c. 提取数据
             exec sql fetch 游标名 into :宿主变量;
          d.关闭游标
             exec sql close 游标名;
    
          使用游标时,结束循环采用:
          exec sql whenever notfound do break;
    
          案例:selectc.pc
    #include <stdio.h>
    exec sql include sqlca;
    struct emp{
        int id;
        char name[25];
        double sal;
    };
    int main(void)
    {
        exec sql begin declare section;
            char userpasswd[30]="openlab/open123";
            struct emp e;
        exec sql end declare section;
        exec sql connect:userpasswd;
        exec sql declare empcursor cursor for
            select id,first_name,salary from s_emp;
        exec sql open empcursor;
        exec sql whenever notfound do break;
        while(1)
        {
            exec sql fetch empcursor into :e;
            printf("%d %s %g
    ",e.id,e.name,e.sal);
        }
        exec sql close empcursor;
        exec sql commit work release;
        return 0;
    }
    
    
    
    
    
          
          有一种特殊的游标,叫做滚动游标。滚动游标可以直接调到任何一行。在用法上和普通游标(顺序游标)的区别:
           a. 声明时,滚动游标关键字是scroll cursor
              exec sql declare 游标名 scroll cursor for select语句;
           b. 提取数据时,滚动游标有多种方式:
               fetch first              提取第一行
               fetch last              提取最后一行
               fetch next             提取下一行
               fetch prior            提取上一行
               fetch absolute n:    提取第n行
               fetch relative n    提取从当前位置开始的第n行
               fetch current                  提取当前行
    
             exec sql fetch first 游标名 into :宿主变量
    
             案例:cp selectc.pc scrollcursor.pc
    #include <stdio.h>
    exec sql include sqlca;
    struct emp{
        int id;
        char name[25];
        double sal;
    };
    int main(void)
    {
        exec sql begin declare section;
            char userpasswd[30]="openlab/open123";
            struct emp e;
        exec sql end declare section;
        exec sql connect:userpasswd;
        exec sql declare empcursor scroll cursor for
            select id,first_name,salary from s_emp;
        exec sql open empcursor;
        exec sql fetch absolute 10 empcursor into :e;
        printf("%d %s %g
    ",e.id,e.name,e.sal);
        exec sql fetch next empcursor into :e;
        printf("%d %s %g
    ",e.id,e.name,e.sal);
        exec sql fetch relative -5 empcursor into :e;
        printf("%d %s %g
    ",e.id,e.name,e.sal);
        exec sql fetch last empcursor into :e;
        printf("%d %s %g
    ",e.id,e.name,e.sal);
        exec sql close empcursor;
        exec sql commit work release;
        return 0;
    }
    
    
    
    5.动态sql
      sql在执行时,才由参数传入
      
      1) 非select语句,没有占位符
         char sqlstr[100]="create table....";
         exec sql execue immediate :sqlstr;
    
        案例:dsqla.pc
    
      2) 非select语句,有占位符
         char sqlstr[100]="insert into.....values(:b0,:b1...)";
         exec sql prepare stmt from :sqlstr;
         exec sql execute stmt using :宿主变量....;
    
        案例:dsqlb.pc
    #include <stdio.h>
    #include <string.h>
    exec sql include sqlca;
    int main(void)
    {
        exec sql begin declare section;
            char userpasswd[30]="openlab/open123";
            char sqlstr[100];
            int id=1001;
            char name[20]="Tarena";
        exec sql end declare section;
        exec sql connect:userpasswd;
        strcpy(sqlstr,
            "insert into testdsql_zsm_00 values(:b0,:b1)");
        exec sql prepare s from :sqlstr;
        exec sql execute s using :id,:name;
        exec sql commit work release;
        return 0;
    }
    
    
    
    3) select语句
         char sqlstr[100]="select .... from ... where id>:b0";
         exec sql prepare stmt from :sqlstr;
         exec sql delcare 游标名 cursor for stmt;
         ....
         
         案例:dsqlc.pc
    #include <stdio.h>
    #include <string.h>
    exec sql include sqlca;
    struct emp{
        int id;
        char name[25];
        double sal;
    };
    int main(void)
    {
        exec sql begin declare section;
            char userpasswd[30]="openlab/open123";
            char sqlstr[100];
            struct emp e;
            int id=10;
        exec sql end declare section;
        exec sql connect:userpasswd;
        strcpy(sqlstr,
          "select id,first_name,salary from s_emp where id>:b0");
        exec sql prepare s from :sqlstr;
        exec sql declare empcursor cursor for s;
        exec sql open empcursor using :id;
        exec sql whenever notfound do break;
        while(1)
        {
            exec sql fetch empcursor into :e;
            printf("%d %s %g
    ",e.id,e.name,e.sal);
        }
        exec sql close empcursor;
        exec sql commit work release;
        return 0;
    }
    
    
    
    ----------------------------------------------------------------------
    总结:
    1. sql
      select
        select..from
           表达式
           别名
           null值: nvl
        where子句
           比较运算符
           between  and
           in
           like     _   %      escape ''
           is null
           逻辑运算符:and   or   not
        order by 子句
           order by 排序标准 排序方式,排序标准 排序方式
        group by子句
           select后的字段必须是分组标准,或者是组函数
        having子句
           分组后的筛选
        单行函数
            to_date   to_char
        组函数
            
        表连接
           select 字段列表 
               from 表1,表2 where 关联条件 [and 筛选条件];
           (+):oracle中外连接
    
           select 字段列表
               from 表1 {{left|right|full} [outer] | [inner]} join 表2
                   on 关联条件 [where 筛选条件];
    
        子查询
           where
           select
           having
           from
    
    
      ddl:
        table
        sequence
        view
        index
            
      dml
        insert   delete  update
    
      tcl
        ACID:
        
      约束
      
      分页
    
    2. plsql
      变量
      数据类型:  record、table、 ref cursor
                         表名.字段%type
                         表名%rowtype
      流程控制
      动态sql
      游标
      异常
      有名块
         过程
         函数
         包
         触发器
    
    3.proc
      宿主变量
      指示变量
      数组变量
      通信区
      嵌入sql、plsql语句
      连接数据库
      错误处理
      select结果集的处理
      动态sql
    
    ---------------------------------------------------------------------
          
  • 相关阅读:
    SVN日常使用
    zabbix安装
    shell日常脚本(centos6)
    mysql故障记录
    PHP商品秒杀功能实现思路分析
    Redis
    PHP 实现实时通信一般有两种方式
    FTP DNS SMTP POP3 HTTP HTTPS DHCP DNS SNMP Telnet 端口号
    TCP/UDP/HTTP的区别和联系
    TCP 和 UDP 的区别
  • 原文地址:https://www.cnblogs.com/Kernel001/p/7714469.html
Copyright © 2020-2023  润新知