【课堂笔记】《数据库系统概论(第5版)》-第8章:数据库编程

第8章:数据库编程

SQL缺少流程控制能力,难以实现业务应用中的逻辑控制;SQL编程技术可以有效地克服SQL语言实现复杂应用方面的不足,提高应用系统和数据库管理系统之间的互操作性。

使用SQL编程来访问和管理数据库中数据的方式主要有:嵌入式SQL(ESQL),过程化SQL(PL/SQL),储存过程和自定义函数,开放数据库连接(ODBC)等。。。

8.1 嵌入式SQL

SQL的特点之一就是可以在交互式和嵌入式两种不同的使用方式下工作。

8.1.1 嵌入式SQL的处理过程

被嵌入的语言,如Java,被称为宿主语言

嵌入式SQL的基本处理过程:

在这里插入图片描述

在嵌入式SQL中,为了能够快速区分SQL语言与主语言,所有SQL语句都必须加前缀,对于C语言,格式为:

EXEC SQL </*SQL语句*/>;

对于Java,格式为:

# SQL {</*SQL语句*/>};

8.1.2 嵌入式SQL与主语言之间的通信

数据库工作单元与源程序工作单元之间的通信主要包括:

  1. 向主语言传递SQL语句的执行状态信息,给主语言提供控制流程的依据,这部分主要由SQL通信区(SQLCA)来实现
  2. 主语言向SQL语句提供参数,主要用主变量(host variable)实现
  3. 将SQL语句的查询结果提交给主语言处理,主要用主变量和游标实现(cursor)
  • SQL通信区

    SQL语句执行过后,需要返回主程序若干信息,包括当前的工作状态和各种运行环境的数据等,这些信息将被送到SQL通信区中,应用程序将从SQL通信区中读取这些信息作为流程控制的依据。

    SQL通信区使用exec sql include sqlca加以定义,其中有一个变量sqlcode,用来存放每次执行SQL之后返回的代码。

    应用程序每执行一次SQL就应检查一下sqlcode的值(success,其他)

  • 主变量

    嵌入式SQL中可以使用主语言程序中的变量来输入或者输入数据;

    SQL语句中使用的主语言程序变量称为主变量

    根据作用不同分为输入主变量(主程序赋值,SQL引用)和输出主变量(同理);

    一个主变量可以附带一个任选的指示变量(indicator variable),为一个整数变量,用来指示其所属的主变量的值或者条件,例如只是或者检测主变量是否为空;

    所有主变量必须在begin decalre sectionend declare section之间进行说明,说明之后,主变量就可以在SQL语句中任何可以使用表达式的地方出现,为了与数据库对象名(表名,列名等)区分,嵌入式SQL语句中的主变量和指示变量都要在前面加上冒号;

  • 游标

    SQL语言面向集合,一条SQL语句可以返回多条记录;
    主语言一般是面向记录的,一次只能处理一条记录;

    为了协调,ESQL引入了游标的概念;

    游标是系统为用户开设的一个数据缓冲区,存放SQL的执行结果,每一个游标区都有自己的名字,用户可以通过游标逐一获得记录并进行处理。

  • 建立和关闭数据库连接

    • 建立数据库连接

      exec sql connect to target[AS connection-name][USER user-name]
      

      target:要连接的数据库服务器,可以是像<dbname>@<hostname>:<port>一样的服务器表示串,还可以是DEFAULT,还可以是包含服务器标识的SQL串常量。

      connection-name:可选的连接名,用来识别程序内建立的多个数据库连接,如果程序内只有一个数据库连接,也可以不指定。

    • 关闭数据库连接

      exec sql disconnect[connection];
      
  • 程序实例

    EXEC SQL BEGIN DECLARE SECTION; /*主变量说明开始*/
    char Deptname[20];
    char Hsno[9];
    char Hsname[20];
    char Hssex[2];
    int HSage;
    int NEWAGE;
    EXEC SQL END DECLARE SECTION; /*主变量说明结束*/
    long SQLCODE;
    EXEC SQL INCLUDE SQLCA; /*定义SQL通信区*/
    
    int main(void) /*C语言主程序开始*/
    {
        int count = 0;
        char yn; /*变量yn代表yes或no*/
    
        printf("Please choose the department name(CS/MA/IS): ");
        scanf("%s", deptname); /*为主变量deptname赋值*/
    
        EXEC SQL CONNECT TO TEST @localhost : 54321 USER "SYSTEM" / "MANAGER"; /*连接数据库TEST*/
        EXEC SQL DECLARE SX CURSOR FOR /*定义游标SX*/
            SELECT Sno,
            Sname, Ssex, Sage /*SX对应的语句*/
            FROM Student 
            WHERE SDept = :deptname;
    
        EXEC SQL OPEN SX; /*打开游标SX,指向查询结果的第一行*/
    
        for (;;)          /*用循环结构逐条处理结果集中的记录*/
        {
            EXEC SQL FETCH SX INTO :HSno, :Hsname, :HSsex, :HSage;
    
            /*推进游标,将当前数据放入主变量*/
            if (SQLCA.SQLCODE != 0) /*SQLCODE != 0,表示操作不成功*/
                break;              /*利用SQLCA中的状态信息决定何时退出循环*/
    
            if (count++ == 0)       /*如果是第一行的话,先打出行头*/
                printf("\n%-10s %-20s %-10s %-10s\n", "Sno", "Sname", "Ssex", "Sage");
    
            printf("%-10s %-20s %-10s %-10d\n", "HSno", "Hsname", "Hssex", "HSage"); /*打印查询结果*/
    
            printf("UPDATE AGE(y/n)?"); /*询问用户是否要更新该学生的年龄*/
            do
            {
                scanf("%c", &yn);
            } while (yn != 'N' && yn != 'n' && yn != 'Y' && yn != 'y');
            if (yn == 'y' || yn == 'Y') /*如果选择更新操作*/
            {
                printf("INPUT NEW AGE:");
                scanf("%d", &NEWAGE);   /*用户输入新年龄到主变量中*/
                EXEC SQL UPDATE Student /*嵌入式SQL更新语句*/
                    SET Sage = :NEWAGE
                    WHERE CURRENT OF SX;
            } /*对当前游标指向的学生年龄进行更新*/
        }
        EXEC SQL CLOSE SX;        /*关闭游标SX,不再和查询结果对应*/
        EXEC SQL COMMIT WORK;     /*提交更新*/
        EXEC SQL DISCONNECT TEST; /*断开数据库连接*/
    }
    

8.1.3 不用游标的SQL语句

以下ESQL语句不需要使用游标:

  • 说明性语句
  • 数据定义语句
  • 数据控制语句
  • 查询结果为单条记录的SELECT语句
  • CURRENT形式的增删改语句
  1. 查询结果为单条记录的SELECT语句

    因为查询结果只有一个,只需要一个into子句指定存放查询结果的主变量,无需游标。

    注意事项

    1. into,where,having中的条件表达式均可以使用主变量;
    2. 为了应对查询结果为空值的情况,会使用到指示变量,当出现空值的时候,指示变量会被赋值负值。
    3. 如果实际结果不为单条记录,将导致错误
  2. CURRENT形式的增删改语句

    (啥是current形式自行百度解决吧。。。)
    如果是非current形式的增删改语句,无需使用游标,在updateset子句和where子句中均可以使用主变量,set子句还可以使用指示变量。

8.1.4 使用游标的SQL语句

必须使用游标的SQL语句包括:

  1. 查询结果为多条记录的select语句;

    使用游标机制将查询结果一条一条的送给主程序处理;

    1. 说明游标

      exec sql declare <游标名> cursor for <select 语句>;
      

      此时并不会执行SQL语句;

    2. 打开游标

      exec sql open <游标名>;
      

      执行相应的select语句,并将结果放置到缓冲区。

    3. 推进游标指针并获取当前的记录

      exec sql fetch <游标名>
          into <主变量>[<指示变量>][,<指示变量>]...;
      
    4. 关闭游标

      exec sql close <游标名>;
      

      游标被关闭后就不再与原来的查询结果相关联;

      被关闭的游标可以被再次打开;

  2. current形式的updatedelete语句;

    updatedelete中使用如下的子句:

    where current of <游标名>;
    

8.1.5 动态SQL

前文使用的嵌入式SQL中,主变量、查询目标列等都是固定的,属于静态SQL

如果某些应用需要等到执行时才能够确定需要提交的SQL语句,需要用到动态SQL

动态SQL支持动态组装SQL和动态参数两种形式。

  1. 使用SQL语句主变量

    程序主变量包含的内容是SQL语句的内容,称为SQL语句主变量。

  2. 动态参数

    使用(?)表示SQL语句中的可变元素。

    需要通过prepare语句来准备主变量或者execute语句来绑定数据。

    (具体用法见教材)

过程化SQL

8.2.1 过程化SQL的快结构

基本的SQL是高度非过程化的语言;

嵌入式SQL借助高级语言实现了过程化;

过程化SQL是对SQL的扩展,使其增加了过程化语句的功能;

过程化SQL程序的基本结构是块,所有的过程化SQL程序都是由块组成的;

块之间可以相互嵌套,每个块完成一个逻辑操作;

8.2.2 变量和常量的定义

  1. 变量定义

    变量名 数据类型 [[not null] := 初值表达式];
    变量名 数据类型 [[not null] 初值表达式];
    
  2. 常量的定义

    常量名 数据类型 constant := 常量表达式;
    

    必须要赋初值。

  3. 赋值语句

    变量名 := 表达式;
    

8.2.3 流程控制

  1. 条件控制语句

    if condition then
        statement1;
    else
        statement2;
    end if;
    

    if语句之间可以嵌套

  2. 循环控制语句

    1. 最简单的loop语句

      loop
          some_statement;
      end loop;
      
    2. while-loop语句

      while condition loop
          some_statement
      end loop;
      
    3. for-loop语句

      for count in [reverse] bound1 .. bound2 loop
          some_statement
      end loop;
      
  3. 错误处理

    教材:请读者根据具体情况处理

8.3 存储过程和函数

过程化SQL主要有匿名块和命名块两种类型;

前面介绍的是匿名块,每次执行时都需要编译,不会被保存、调用;

过程和函数是命名块,它们被编译和保存在数据库中,称为持久性储存模块,可以被反复调用;

8.3.1 存储过程

存储过程由过程化SQL书写,被编译和优化后储存在数据库中,使用时只需要调用;

  1. 存储过程的优点

    1. 运行效率高
    2. 降低了客户端和服务器端之间的通信量(只需要发送存储过程的名字和参数)
    3. 方便实施企业规则
  2. 存储过程的用户接口

    1. 创建存储过程

      create or replace procedure 过程名 ([参数1, 参数2,...])
      as <过程化SQL>;
      
    2. 执行存储过程

      call / perform procedure 过程名 ([参数列表])
      
    3. 重命名一个存储过程

      alter procedure name_1 rename to name_2;
      
    4. 重新编译一个存储过程

      alter procedure 过程名 compile;
      
    5. 删除存储过程

      drop procedure 过程名;
      

8.3.2 函数

也称为自定义函数;

函数的定义与存储过程类似,但是函数必须指定返回类型;

  1. 函数的定义语句格式

    create or replace function 函数名 ([param_1, param_2, ...]) returns <data_type>
    as <过程化SQL>;
    
  2. 函数的执行语句格式

    call / select 函数名 ([param_1, param_2, ...]);
    

    这么久了,还没提过这些方括号、尖括号在代码里啥意思,这里放个链接,以防有人不知道

  3. 修改函数

    可以重命名和重编译,和上面的存储过程一样;

8.4 ODBC编程

ODBC是啥自行百度

优点:

  • 程序可移植性好
  • 能同时访问不同的数据库
  • 共享多个数据资源

8.4.1 ODBC概述

ODBC有两重功效或者说约束力:

  1. 规范应用程序开发
  2. 规范关系数据库管理系统应用接口

8.4.2 ODBC工作原理概述

在这里插入图片描述

  1. 用户应用程序

    提供用户界面、应用逻辑、事务逻辑;

    ODBC应用程序包含的内容有:

    • 请求连接数据库
    • 向数据源发送SQL语句
    • 为SQL语句执行结果分配存储空间,定义所读取的数据格式
    • 获取数据库操作结果或处理错误
    • 进行数据处理并向用户提交处理结果
    • 请求事务的提交和回滚操作
    • 断开与数据源的连接
  2. ODBC驱动程序管理器

    • 包含在ODBC32.DLL中
    • 管理应用程序和驱动程序之间的通信
    • 建立、配置或删除数据源,并查看系统当前所安装的数据库ODBC驱动程序
  3. 数据库驱动程序

    提供应用系统与数据库平台的独立性

  4. ODBC数据源管理

    数据源是是最终用户需要访问的数据,包含了数据库位置和数据库类型等信息,是一种数据连接的抽象;

8.4.3 ODBC API基础

各个数据库厂商的ODBC应用程序编程接口都要符合两方面的一致性:

  • API一致性
  • 语法一致性
  1. 函数概述

    • 分配和释放环境句柄、连接句柄、语句句柄
    • 连接函数(SQLDriverconnect等)
    • 与信息相关的函数(SQLGetinfo、SQLGetFuction等)
    • 事务处理函数(如SQLEndTran)
    • 执行相关函数(SQLExecdirect、SQLExecute等)
    • 编目函数,ODBC 3.0提供了11个编目函数,如SQLTables、SQLColumn等。应用程序可以通过对编目函数的调用来获取数据字典的信息,如权限、表结构等
  2. 句柄及其属性

    句柄是32位整数值,代表一个指针;

    分为:

    • 环境句柄
    • 连接句柄
    • 语句句柄
    • 描述符句柄
    1. 每个ODBC应用程序需要建立一个ODBC环境,分配一个环境句柄,存取数据的全局性背景,如环境状态、当前环境状态诊断、当前在环境上分配的连接句柄等;

    2. 一个环境句柄可以建立多个连接句柄,每一个连接句柄实现与一个数据源之间的连接;

    3. 在一个连接中可以建立多个语句句柄,它不只是一个SQL语句,还包括SQL语句产生的结果集以及相关的信息等;

    4. 在ODBC 3.0中又提出了描述符句柄的概念,它是描述SQL语句的参数、结果集列的元数据集合;

在这里插入图片描述

  1. 数据类型

ODBC定义了两套数据类型,一套是SQL数据类型,一套是C数据类型,两者之间可以相互转换。

8.4.4 ODBC工作流程

在这里插入图片描述

  • 1
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
第二 关系数据库 1 .试述关系模型的三个组成部分。 答:关系模型由关系数据结构、关系操作集合和关系完整性约束三部分组成。 2 .试述关系数据语言的特点和分类。 答:关系数据语言可以分为三类: 关系代数语言。 关系演算语言:元组关系演算语言和域关系演算语言。 SQL:具有关系代数和关系演算双重特点的语言。 这些关系数据语言的共同特点是,语言具有完备的表达能力,是非过程化的集合操作语言,功能强,能够嵌入高级语言中使用。 3 (略) 4 . 5 . 述关系模型的完整性规则。在参照完整性中,为什么外部码属性的值也可以为空?什么情况下才可以为空? 答:实体完整性规则是指若属性A是基本关系R的主属性,则属性A不能取空值。 若属性(或属性组)F是基本关系R的外码,它与基本关系S的主码Ks相对应(基本关系R和S不一定是不同的关系),则对于R中每个元组在F上的值必须为:或者取空值(F的每个属性值均为空值);或者等于S中某个元组的主码值。即属性F本身不是主属性,则可以取空值,否则不能取空值。 6.设有一个SPJ数据库,包括S,P,J,SPJ四个关系模式: 1)求供应工程J1零件的供应商号码SNO: πSno(σJno=‘J1’(SPJ)) 2)求供应工程J1零件P1的供应商号码SNO: πSno(σJno=‘J1’∧Pno=‘P1‘(SPJ)) 3)求供应工程J1零件为红色的供应商号码SNO: πSno(πSno,,Pno(σJno=‘J1‘ (SPJ))∞πPno(σCOLOR=’红‘ (P))) 4)求没有使用天津供应商生产的红色零件的工程号JNO: πJno(SPJ)- πJNO(σcity=‘天津’∧Color=‘红‘ (S∞SPJ∞P) 5)求至少用了供应商S1所供应的全部零件的工程号JNO: πJno,Pno(SPJ)÷ πPno(σSno=‘S1‘ (SPJ)) 7. 试述等值连接与自然连接的区别和联系。 答:连接运算符是“=”的连接运算称为等值连接。它是从关系R与S的广义笛卡尔积中选取A,B属性值相等的那些元组 自然连接是一种特殊的等值连接,它要求两个关系中进行比较的分量必须是相同的属性组,并且在结果中把重复的属性列去掉。 8.关系代数的基本运算有哪些 ? 如何用这些基本运算来表示其他运算? 答:并、差、笛卡尔积、投影和选择5种运算为基本的运算。其他3种运算,即交、连接和除,均可以用这5种基本运算来表达。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值