zoukankan      html  css  js  c++  java
  • 【SQL】宿主语言接口

    一般情况下,SQL语句是嵌套在宿主语言(如C语言)中的。有两种嵌套方式:

    1.调用层接口(CLI):提供一些库,库中的函数和方法实现SQL的调用

    2.直接嵌套SQL:在代码中嵌套SQL语句,提交给预处理器,将SQL语句转换成对宿主语言有意义的内容,如调用库中的函数和方法代替SQL语句

    阻抗不匹配问题:连接SQL语句与常规编程语言的基本问题。SQL核心使用关系数据模型,而C语言等常规语言则使用整型、实数型、算数型、字符型、指针等类型。

     

    一、SQL与宿主语言连接

    EXEC SQL关键字提示预处理将由SQL代码进入。

    共享变量:实现数据库和宿主语言之间的信息交换。

    SQL中共享变量要加冒号,宿主语言中不需要。

    SQLSTATE:特殊变量,由5个字符的数组组成(在C中分配空间要分配6个,后面有''),存放表示调用过程出现的问题的代码。'00000'表示没有错误。

    1.1 DECLARE节

    声明共享变量要在声明节中。

    EXEC SQL BEGIN DECLARE SECTION;

    ...

    EXEC SQL END DECLARE SECTION;

    EXEC SQL BEGIN DECLARE SECTION;
        char studioName[50], studioAddr[256];
        char SQLSTATE[6];
    EXEC SQL END DECLARE SECTION;

    1.2 使用共享变量

    任何不含返回结果的SQL语句,都可以用EXEC SQL为前缀嵌入宿主语言。

    void getStudio(){
        EXEC SQL BEGIN DECLARE SECTION;
            char studioName[50], studioAddr[256];
            char SQLSTATE[6];
        EXEC SQL END DECLARE SECTION;
    
        printf("please input studio name:
    ");
        scanf("%s", &studioName);
        printf("please input studio address:
    ");
        scanf("%s", &studioAddr);
    
        EXEC SQL INSERT INTO Studio(name, address)
                        VALUES (:studioName, :studioAddr);

    1.3 连接SQL返回结果到宿主语言

    因为阻抗不匹配,使得返回结果无法直接返回到宿主语言中,必须使用下面两种机制中的一个。

    单元组选择语句:只有一个结果的查询语句,将该元组存储到共享变量中。

    游标:为查询声明一个游标,游标范围覆盖结果关系中的所有元组,每个元组一次被提取到共享变量,由宿主语言处理。

    1.4单元组选择语句

    类似于普通的select-from-where语句,只是SELECT子句后面紧跟着关键字INTO和一连串的共享变量。如果结果少于或多于一个元组,则共享变量中不会有值,且SQLSTATE中存入一个错误码。

    void printNetWorth(){
        EXEC SQL BEGIN DECLARE SECTION;
            char studioName[50];
            int presNetWorth;
            char SQLSTATE[6];
        EXEC SQL END DECLARE SECTION;
    
        /*输入studioName的代码*/
    
        EXEC SQL SELECT netWorth
                        INTO :presNetWorth
                        FROM Studio, MovieExec
                        WHERE presC# = cert# AND
                                    Studio.name = :studioName;
    
        /*检查SQLSTATE中的代码是否为'00000'*/
    }

    1.5 游标

    游标声明:

    EXEC SQL DECLARE 游标名称 CURSOR FOR 查询

    初始化游标的位置:使之指向第一个元组

    EXEC SQL OPEN 游标名称

    得到下一个元组:

    EXEC SQL FETCH FROM 游标名称 INTO 变量列表

    变量列表中存放获取的结果,如果已经遍历结束则SQLSTATE中返回'02000'

    关闭游标:

    EXEC SQL CLOSE 游标名称

    void worthRanges(){
        int i, digits, counts[15];
        EXEC SQL BEGIN DECLARE SECTION;
            int worth;
            char SQLSTATE[6];
        EXEC SQL END DECLARE SECTION;
        EXEC SQL DECLARE execCursor CURSOR FOR
                SELECT netWorth FROM MovieExec;
    
        EXEC SQL OPEN execCursor;
        for(i = 1; i < 15; i++)
            counts[i] = 0;
        while(1){
            EXEC SQL FETCH FROM execCursor INTO :worth;
            if(NO_MORE_TUPLES) 
                break;
            digits = 1;
            while((worth /= 10) > 0) digits++;
            if(digits <= 14) counts[digits]++;
        }
        EXEC SQL CLOSE execCursor;
        for(i = 1; i < 15; i++)
            printf("digits = %d: number of execs = %d
    ",i, counts[i]);
    }

    1.6 游标更新

    可以通过游标删除或修改当前的元组。

    WHERE后只能是 WHERE CURRENT OF

    下面的例子将资产少于1000的删除,多余1000的翻倍。

    #define NO_MORE_TUPLES !(strcmp(SQLSTATE,"02000"))
    
    void changeWorth(){
        EXEC SQL BEGIN DECLARE SECTION;
            int certNo, worth;
            char execName[31], execAddr[256], SQLSTATE[6];
        EXEC SQL END DECLARE SECTION;
        EXEC SQL DECLARE execCursor CURSOR FOR MovieExec;
    
        EXEC SQL OPEN execCursor;
        while(1){
            EXEC SQL FETCH FROM execCursor INTO :execName, :execAddr, :certNo, :worth;
            if(NO_MORE_TUPLES) break;
            if(worth < 1000)
                EXEC SQL DELETE FROM MovieExec
                                             WHERE CURRENT OF execCursor;
            else
                EXEC SQL UPDATE MovieExec
                                SET netWorth = 2 * netWorth
                                WHERE CURRENT OF execCursor;
        }
        EXEC SQL CLOSE execCursor;
    }

    1.7 避免并发修改

    如果在游标获取到元组到游标关闭前,不希望元组发生变化:

    EXEC SQL DECLARE 游标名 INSENSITIVE CURSOR FOR 查询;

    不希望通过游标修改元组

    EXEC SQL DECLARE 游标名  CURSOR FOR 查询 FOR READ ONLY

    1.8动态SQL

    在运行时,通过输入SQL语句实现查询需要动态SQL语句支持。

    EXEC SQL PREPARE V FROM 表达式;

    EXEC SQL EXECUTE V; //这句可以多次执行 表明表达式V执行了多次

    上面两句合并后可以写成:

    EXEC SQL EXECUTE IMMEDIATE 表达式;

    void readQuery(){
        EXEC SQL BEGIN DECLARE SECTION;
            char * query;
        EXEC SQL END DECLARE SECTION;
    
        /*输入SQL语句,放入query中*/
    
        EXEC SQL PREPARE SQLquery FROM :query;
        EXEC SQL EXECUTE SQLquery;
    }
  • 相关阅读:
    search支持多种标签
    二级导航样式
    内容页与首页列表页调用点击数量
    常用标签
    20随机验证码
    19.请输入整数
    18.自定义过滤器表头排序
    17.js实现金山打字
    16.简单的自定义指令
    OC学习笔记 面向对象 继承与组合
  • 原文地址:https://www.cnblogs.com/dplearning/p/4898089.html
Copyright © 2011-2022 走看看