第15章 嵌入式SQL的应用

第15章 嵌入式SQL的应用

SQL在如今的数据库领域虽然应用的非常的广泛,但是,与一些高级语言相比,在某些功能上还有一定的限制。也就是说,在有些功能上,纯粹使用SQL语句还无法实现。数据库访问只是其中一个部件。有些如与用户交互、图形化显示数据等动作只能通过应用高级语言来实现。

15.1 嵌入式SQL介绍
在关系数据库中,可以将SQL语句嵌入到宿主语言中,既实现嵌入式SQL,从而完成在单独使用SQL语句时难以实现的功能。

15.1.1 直接调用SQL
直接调用SQL也称为交互式SQL。通常是指用户在数据库产品提供的客户端应用软件中直接运行SQL语句,同时通过该软件返回SQL语句的执行结果。前面所讲解的SQL Server数据库及其相关的示例,其交互式SQL的实现都是通过在查询分析器中实现的。在SQL Server的查询分析器中直接运行SQL语句,同时返回语句的执行结果,如图15.1所示。
第15章 嵌入式SQL的应用_第1张图片
图15.1 SQL Server2005的查询分析器界面

说明:本书中所使用的SQL Server数据库是SQL Server2005的SQL Server Management
Studio版本,该版本将SQL Server2000中的企业管理器和查询分析器的功能都集合在一起,图19.1就是该版本的查询分析器界面。

在不同的数据库管理系统当中,实现交互式SQL的方法是不同的。在Oracle数据库当中,通过SQL*Plus软件实现交互式SQL。但是,无论通过什么方式实现交互式SQL,SQL中其基本的SELECT、INSERT、UPDATE和DELETE语句以及与存储过程、触发器、事务和连接等有关的语句,几乎都可以在交互式SQL环境中实现,即实现直接调用操作。

交互式SQL是一个纯SQL环境,因此,通过交互式SQL很难与应用程序建立起连接,这就使得交互式SQL的应用受到了很大的限制。在实际应用中,大多数的访问都是通过嵌入式SQL和SQL调用层接口(CLI)完成的,很少依靠交互式SQL来实现。

15.1.2 SQL调用层接口(CLI)
通常情况下,应用程序要想与SQL数据库之间进行交流,需要SQL调用层接口来实现。SQL调用层接口是一种支持预定义例程的应用程序接口。应用程序调用例程,然后连接到数据库。通过例程可以访问数据库中的数据信息,同时将访问到的数据信息返回给应用程序。
应用程序与SQL数据库之间通过SQL调用层接口(CLI)进行交流的过程如图15.2所示。
第15章 嵌入式SQL的应用_第2张图片
图15.2 通过SQL调用层接口(CLI)访问数据库的流程

通常情况下,应用程序与CLI例程之间是通过函数来实现的。
程序通过使用函数来调用CLI例程,函数通过设定参数把值传递给例程,由函数作为应用程序和SQL数据库之间的接口。目前应用最广泛的的CLI模块工具是Microsoft公司的ODBC(Open Database Conectivity)和Microsoft公司的OLE-DB/ADO(ActiveX Data Object)。
1.ODBC
ODBC技术是对数据库进行访问的标准应用程序接口(API)和Windows开放式服务体系结构OSA的一个重要组成部分,已被得到了广泛的应用。
ODBC为开发应用数据库程序提供了非常强大的功能和灵活性。ODBC通过驱动程序管理器与数据库进行交换信息。驱动程序管理器负责将应用程序对ODBC的调用,传递给正确的驱动程序,而驱动程序在执行完相应的操作后,将结果通过驱动程序管理器返回给应用程序。
ODBC所包含的部件及其关系如图15.3所示。
第15章 嵌入式SQL的应用_第3张图片
图15.3 ODBC包含的各部件及其关系图

说明:应用程序要访问一个数据库,首先必须用ODBC管理器注册一个数据源,管理器根据数据源提供的数据库位置、数据库类型及ODBC驱动程序等信息,建立起ODBC与具体数据库的联系。

2.OLE-DB/ADO
OLE DB是系统级的编程接口,可在C/C++语言中直接使用。OLE DB提供了一组标准的服务组件,用于提供查询、缓存、数据更新和事务处理等操作。OLE DB还通过定义的COM接口将各种数据系统的访问操作进行封装,为数据使用方和数据提供方建立了标准。
微软公司的ADO是最新的对象层次上的数据操作技术,ADO技术为操作OLE DB数据源提供了一套高层次自动化接口。虽然OLE DB已经是一个强大的数据操作接口,但是很多的数据库应用程序开发人员并不需要OLE DB提供的操作数据的底层控制接口。

注意:通过CLI访问SQL数据库的核心并不在于SQL本身,而在于访问SQL数据库的高级语言开发工具(如C语言)以及CLI实现的本身。

ADO同OLE DB、数据库应用以及数据源之间的关系如图15.4所示。
第15章 嵌入式SQL的应用_第4张图片
图15.4 ADO同OLE DB、数据库应用以及数据源之间的关系

15.2 嵌入式SQL的使用
15.2.1 嵌入式SQL
嵌入式SQL是指将SQL语言嵌入到某种高级语言当中,如在FORTRAN、COBOL和C语言中都可以嵌入SQL语言,来弥补SQL语言在实现复杂应用方面的不足。
通常使用预处理的方式来实现嵌入式SQL。通过扩充宿主语言(高级编程语言)的编译程序,使其能够处理SQL语句和预处理的方式。预处理方式的处理过程主要可以表示为以下几个方面:

  • 由DBMS的预处理程序扫描源程序,从源程序中识别出SQL语句使其能够被编译执行。
  • 把识别出的SQL语句转换成主语言调用语句,使高级语言编译程序能识别该调用语句。
  • 由高级语言的编译程序将整个源程序编译成目标代码。

其具体实现的流程如图15.5所示。
在这里插入图片描述
图15.5 嵌入式SQL预处理方式的实现

从图15.5中可以看出,预处理方式首先从含有高级语言和SQL语句的程序开始。在编译程序之前,首先把程序提交给一个预编辑器,通过预编译器将SQL语句从高级语言中分离出来,并且实现对SQL语句的调用。然后通过高级语言编译器按照自己的方式进行编译,最后得到目标代码,实现连接到数据库的例程当中。

15.2.2 SQL通信区
SQL通信区(SQL Communication Area)简称SQLCA。在SQL语句运行时,DBMS返回描述系统当前工作状态以及运行环境状态等信息。应用程序根据从SQLCA中取出的信息来决定下一步要执行的操作。
在使用SQLCA时,首先需要在高级语言中定义,其实现定义的语句结构如下所示:
EXEC SQL INCLUDE SQLCA
SQLCA中包含的主要字段及其字段的含义如下所示:

  • SQLCAID:该字段含有8字节字符,其作用是在查看内存内容时帮助进行调试。
  • SQLCABC:该字段是包含SQLCA结构长度的长整型数。
  • SQLCODE:数据库在请求上检测到错误时,指定错误代码的长整数。成功操作的错误代码是0,正数表示警告,负数表示错误。
  • SQLERRML:字段中信息的长度。
  • SQLERRMC:要插入到错误消息中的零个或多个字符串。
  • SQLERRD:长整数的实用程序数组。

下面通过一个示例来说明如何在嵌入式SQL语句中应用SQLCA。
【上机实战】
在C语言中嵌入SQL语句中SQLCA。

#include
/* 定义SQLCA变量,用于进行错误检测 */
EXEC SQL INCLUDE SQLCA;
main()
{
  /* 连接数据库 */
  EXEC DQL CONNECT TO MyDataBase USER SA;
  if(sqlca.sqlcode)
    {
       printf(Printer,"连接数据库服务器错误!");
       exit();
    }
}

示例中的代码表示通过SQLCA检测在连接数据库时是否有错误产生。如果sqlca.sqlcode的值为0,则连接数据库的SQL语句执行失败,说明连接数据库不成功,程序将提示“连接数据库服务器错误!”的提示信息。

15.2.3 主变量
在SQL语句中使用的高级语言程序的变量简称为主变量。使用主变量可以输入或输出数据。
1.主变量的分类
主变量可以分为输入主变量和输出主变量两种。输入主变量通过SQL语句进行引用,然后由应用程序对其赋值;输出主变量由SQL语句对该变量进行赋值或设置状态信息,然后将该信息返回给应用程序。
利用输入主变量,可以指定向数据库中插入的数据,将数据库中的数据修改为指定值的功能。利用输出主变量,可以得到SQL语句的结果数据和状态。
2.主变量的定义和使用
在SQL语句中,输入主变量前面要加冒号,以便于区别数据库对象名。输入主变量可以被应用在SQL的数据操纵语句当中的任何位置。定义输出变量的方法是在SQL语句的BEGIN DECLARE SECTION与END DECLARE SECTION之间进行说明。
下面通过一个示例来讲解如何定义输入主变量。
【上机实战】
定义输入主变量。

/* 定义输入主变量 */
EXEC SQL SELECT sName,sSex,sPhone,sAddress
    /* 下面的变量tName,tSex,tPhone,tAddress,In_No是在高级语言中定义的 */
    INTO :tName,:tSex,:tPhone,:tAddress
    FROM employee
    WHERE No=:In_No;

下面通过一个示例来讲解如何定义输出主变量。

/* 定义输出主变量 */
EXEC SQL BEGIN DECLARE SECTION
   INT out_No;
   CHAR out_name[10];
   CHAR out_sex[2];
   INT out_age;
   CHAR out_phone[11];
   CHAR out_address[50];
   CHAR SQLSTATE[6]
EXEC SQL END DECLARE SECTION
EXEC SQL SELECT sName,sSex,sAge,sPhone,sAddress
    INTO :tName,:tSex,:tAge,:tPhone,:tAddress
    FROM employee
    WHERE No=:In_No;

15.2.4 在嵌入式SQL中使用SQL语句
本节中讲解的是在嵌入式SQL中如何使用SELECT语句、UPDATE语句、DELETE语句和INSERT语句。

1.在嵌入式SQL中使用SELECT语句
在嵌入式SQL中使用SELECT语句是对交互式SELECT语句的补充。嵌入式SQL中使用了INTO语句,并且其返回的结果只有一条记录。
下面通过一个示例来说明如何在嵌入式SQL中使用查询结果为单记录的SELECT语句。
【上机实战】
从员工信息表(employee)中查询员工编号(No)为1001的员工姓名和性别信息,并且将其值赋予主变量

tName和tSex。
EXEC SQL SELECT sName,Sex
INTO :tName,:tSex
FROM employee
WHERE No=1001

代码中的tName和tSex都是前面示例中定义过的主变量。语句返回员工信息表(employee)中员工编号为1001的单行记录信息。

2.在嵌入式SQL中使用UPDATE语句
在嵌入式SQL中使用UPDATE语句的语法形式与使用交互式UPDATE语句的语法形式基本相似。只不过在嵌入式SQL中使用的UPDATE语句中的SET子句和WHERE子句中可以使用主变量而以。
下面通过一个示例来说明如何在嵌入式SQL中使用UPDATE语句。
【上机实战】
通过主变量将员工工资表(EmPays)中所有女员工的工资提高。假设增加的工资已经赋给主变量

AddPays。
EXEC SQL UPDATE EmPays
SET EmPays=EmPays + :AddPays
WHERE EmSex='女'

该代码执行以后,员工工资表(EmPays)中所有女员工的工资提都被更改提高。
3.在嵌入式SQL中使用DELETE语句
在嵌入式SQL中使用DELETE的语法结构中,除了在其WHERE子句中可以使用主变量之外,其他部分都与交互式DELETE语句相同。
下面通过一个示例来说明如何在嵌入式SQL中使用DELETE语句。
【上机实战】
通过主变量将学生信息表(student)中所有年龄大于某值的员工信息删除。假设该值已经赋予了主变量

del_age。
EXEC SQL DELETE 
FROM student
WHERE SAge>:del_age;

该代码执行以后,学生信息表(student)中所有年龄大于主变量del_age中值的员工信息都被删除。
4.在嵌入式SQL中使用INSERT语句
在嵌入式SQL中使用INSERT的语法结构中,除了在其VALUES子句中可以使用主变量之外,其他部分都与交互式INSERT语句相同。
下面通过一个示例来说明如何在嵌入式SQL中使用INSERT语句。
【上机实战】
通过主变量向学生信息表(student)中插入数据信息,并且假定表中的各字段信息都存储在主变量stud_no、stud_spno、stud_name和stud_age当中。

EXEC SQL INSERT INTO student
VALUES(:stud_no,:stud_spno,:stud_name,:stud_age);

该代码执行以后,主变量中的数据信息被插入到学生信息表(student)当中。

15.2.5 在嵌入式SQL中使用游标
嵌入式SQL中的一组主变量一次只能存放一条记录。因此,只是使用主变量,并不能完全满足SQL语句向应用程序输出数据的要求。为此,嵌入式SQL引入了游标的概念,用游标来解决上述出现的问题。
在嵌入式SQL中,游标是系统为用户开设的一个数据缓冲区,其用于存放SQL语句的执行结果。用户可以用SQL语句逐一从游标中获取记录,并赋给主变量,然后再通过高级语言程序进行处理,完成相应的操作。
在嵌入式SQL中使用游标主要有以下几个步骤:
(1)定义一个游标,使之对应一个SELECT语句。实现过程可用下面的语句进行表示:

EXEC SQL DECLARE <游标名称> CURSOR FOR 

(2)打开游标,在定义了游标之后,可以执行游标对应的查询,其结果集合为该游标的活动集。实现过程可用下面的语句进行表示:

EXEC SQL OPEN <游标名称>

此时游标指针定位于结果集中第一行的前一行。
(3)在活动集中将游标移到特定的行,并取出该行数据放到相应的主变量中,其实现的过程可以用下面的语句进行表示:

EXEC SQL FETCH FROM <游标名称> INTO <主变量名称>

(4)关闭游标,游标在使用完成以后,需要释放活动集及其所占用的资源,使它不再和查询结果相联系。其实现的过程可以通过下面的语句进行表示:

EXEC SQL CLOSE <游标名称>

下面通过一个具体的示例来说明如何在嵌入式SQL中使用游标。
【上机实战】
在C语言中使用嵌入式SQL,并且使用了游标。

EXEC SQL INCLUDE SQLCA;
EXEC SQL BEGIN DECLARE SECTION;
CHAR employee_name[10];
CHAR employee_phone[11];
CHAR emoloyee_address[50];
EXEC SQL END DECLARE SECTION;
main()
{
  EXEC SQL DECLARE employee_Cursor CURSOR FOR
  SELECT sName,sPhone,sAddress;
   /* 打开游标*/
  EXEC SQL OPEN employee_Cursor;
  for(;;)
  {
   /* 将当前值当道主变量当中*/
   EXEC SQL FETCH employee_Cursor INTO :employee_name,
   :employee_phone,:emoloyee_address;
   if(sqlca.sqlcode<>0)
   break;
   /* 输出结果*/
   printf("姓名:%s,联系电话:%s,联系地址:%s",employee_name,
   employee_phone,emoloyee_address);
  }
   /* 关闭游标*/
EXEC SQL CLOSE employee_Cursor  
}

上面示例演示的是在嵌入式SQL中游标最基本的使用方法。下面讲解如何在查询结果为多条记录的SELECT语句中使用游标。
下面的代码演示的是,通过主变量从员工工资表(EmPays)中检索员工姓名(EmName)、员工性别(EmSex)和员工的基本工资(EmBasicPays)信息,其中员工姓名由主变量InName给出。

Void Pays()
{
  EXEC SQL INCLUDE SQLCA;
  EXEC SQL BEGIN DECLARE SECTION;
  CHAR emname[10];
  CHAR emsex[2];
  INT empays;
EXEC SQL END DECLARE SECTION;
gets(emname);
EXEC SQL DECLARE emppay_cursor CURSOR FOR
SELECT EmName,EmSex,EmBasicPays 
FOR EmPays 
WHERE EmName=:emname;
EXEC SQL OPEN emppay_cursor;
WHILE(1)
{
  EXEC SQL FETCH FROM emppay_cursor INTO :emname,:emsex,:empays;
  if(sqlca.sqlcode<>0)
  break;
   printf("姓名:%s,性别:%s,基本工资:%d",emname,emsex,empays);
}
EXEC SQL CLOSE emppay_cursor;
}

你可能感兴趣的:(SQL)