嵌入式SQL语言

Posted 计算机小白的爬坑之路

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了嵌入式SQL语言相关的知识,希望对你有一定的参考价值。

嵌入式SQL语言

一、概述

高级语言+SQL语言
既继承高级语言的过程控制性又结合SQL语言的复杂结果集操作的非过程性;同时又为数据库操作者提供安全可靠的操作方式,通过应用程序进行操作。
嵌入式SQL语言
将SQL语言嵌入到某一种高级语言中使用,如C/C++, Java, PowerBuilder等,又称宿主语言(HostLanguage)。

示例交互式SQL语言
select Sname, Sage from Student where Sname =‘张三’;

示例嵌入式SQL语言
以宿主语言C语言为例
exec sql select Sname, Sage into :vSname, :vSage from Student where Sname=‘张三’;

典型特点

  1. exec sql 引导SQL语句:提供给C编译器,以便对SQL语句预编译成C编译器可识别的语句。
  2. 增加 into子句:该子句用于指出接收SQL语句检索结果的程序变量,由冒号引导的程序变量,如:‘:vSname’, ‘:vSage’

二、变量声明与数据库连接

1、变量的声明与使用

在嵌入式SQL语句中可以出现宿主语言语句所使用的变量:
exec sql select Sname, Sage into :vSname, :vSage from Student where Sname= :specName;

变量声明:
exec sql begin declare section; char vSname[10], specName[10]=“张三”; int vSage; exec sql end declare section;

变量声明和赋值中,要注意:

  1. 宿主程序的字符串变量长度应比字符型字段的长度多1个。因宿主程序的字符串尾部多一个终止符为\\0 ‘,而程序中用双引号来描述。
  2. 宿主程序变量类型与数据库字段类型之间有些是有差异的,有些DBMS可支持自动转换,有些不能。

声明的变量,可以在宿主程序中赋值,然后传递给SQL语句的where等子句中,以使SQL语句能够按照指定的要求(可变化的)进行检索。
exec sql begin declare section; char vSname[10], specName[10]=“张三”;int vSage; exec sql end declare section;
exec sql select Sname,Sage into :vSname, :vSage from Student where Sname = :specName ;

相应的交互式SQL语句:
select Sname, Sage from Student where Sname =张三’;

嵌入式比交互式SQL语句灵活了一些:只需改一下变量值,SQL语句便可反复使用,以检索出不同结果。

(1) 数据库与DBMS连接

SQL标准连接语法为:
exec sql connect to target-server as connect-name user user-name;

exec sql connect to default;
Oracle中数据库连接:
exec sql connect :user_name identified by :user_pwd;
DB2 UDB中数据库连接:
exec sql connect to mydb user :user_name using :user_pwd;

(2) 与数据库断开连接

SQL断开连接的语法
exec sql disconnect connect-name;

exec sql disconnect current;
Oracle中断开连接:
exec sql commit release;

exec sql rollback release;
DB2 UDB中断开连接:
exec sql connect reset; exec sql disconnect current;

(3) SQL执行的提交与撤消

SQL语句在执行过程中,必须有提交和撤消语句才能确认其操作结果

SQL执行的提交:
exec sql commit work;
SQL执行的撤消:
exec sql rollback work;

很多DBMS都设计了捆绑提交/撤消与断开连接在一起的语句,以保证在断开连接之前使用户确认提交或撤消先前的工作
例如Oracle中:
exec sql commit release;

exec sql rollback release;

(4) 事务的概念与特性

事务:(从应用程序员角度)是一个存取或改变数据库内容的程序的一次执行或者说一条或多条SQL语句的一次执行被看作一个事务

事务一般是由应用程序员提出,因此有开始和结束,结束前需要提交或撤消。

Begin Transaction
exec sql …
exec sql …
exec sql commit work | exec sql rollback workEnd Transaction

在嵌入式SQL程序中,任何一条数据库操纵语句(如exec sql select等)都会引发一个新事务的开始,只要该程序当前没有正在处理的事务。而事务的结束是需要应用程序员通过commit或rollback确认的。因此Begin Transaction和End Transaction两行语句是不需要的。

事务∶(从微观角度,或者从DBMS角度)是数据库管理系统提供的控制数据操作的一种手段,通过这一手段,应用程序员将一系列的数据库操作组合在一起作为一个整体进行操作和控制,以便数据库管理系统能够提供一致性状态转换的保证。

事务的特性: ACID

  1. 原子性Atomicity : DBMS能够保证事务的一组更新操作是原子不可分的,即对DB而言,要么全做,要么全不做
  2. 一致性Consistency: DBMS保证事务的操作状态是正确的,符合一致性的操作规则,它是进一步由隔离性来保证的
  3. 隔离性lsolation: DBMS保证并发执行的多个事务之间互相不受影响。例如两个事务T1和T2,即使并发执行,也相当于或者先执行了T1,再执行T2;或者先执行了T2,再执行T1。
  4. 持久性Durability: DBMS保证已提交事务的影响是持久的,被撤销事务的影响是可恢复的。

换句话说:具有ACID特性的若干数据库基本操作的组合体被称为事务。

事务处理是DBMS的核心技术。



步骤:

  1. 引入SQLCA
  2. 声明变量
  3. 设置SQL错误捕获语句
  4. 连接数据库
  5. 设置SQL语句,并提交
  6. 断开连接

三、数据集与游标

1、检索单行结果

可将结果直接传送到宿主程序的变量中

EXEC SQL SELECT[ALL | DISTINCT]expression [, expression…]
INTO host-variable , [host-variable,…]
FROM tableref [corr_name] [ , tableref [corr_name] …]WHEREsearch_condition;

示例
exec sql select Sname, Sage into :vSname,:vSage from Student where Sname = :specName ;

2、检索多行结果

检索多行结果,则需使用游标(Cursor)
游标是指向某检索记录集的指针。通过这个指针的移动,每次读一行,处理一行,再读一行….,直至处理完毕。

读一行操作是通过Fetch…into语句实现的:每一次Fetch,都是先向下移动指针,然后再读取。
记录集有结束标识EOF,用来标记后面已没有记录了

3、游标(Cursor)的使用

游标(Cursor)的使用需要先定义、再打开(执行)、接着一条接一条处理,最后再关闭

exec sql declare cur_student cursor for
select Sno, Sname,Sclass from Student where Sclass=035101’;
exec sql open cur_student;
exec sql fetch cur_student into :vSno, :vSname, :vSclass;
exec sql close cur_student;

游标可以定义一次,多次打开(多次执行),多次关闭

Cursor的定义:declare cursor

EXEC sQL DECLAREcursor_name CURSOR FOR
Subquery
[ORDER BY result_column [ASC | DESC][, result_column …]
[FOR [ READ ONLY | UPDATE [OF columnname [, columnname…]]l];

示例
exec sql declare cur_student cursor for select Sno, Sname, Sclass from Student where Sclass= :vClass order by Sno for read only ;

Cursor的打开和关闭open cursor //close cursor
EXEC SQL OPEN cursor_name;
EXEC SQL CLOSE cursor_name;

Cursor的数据读取Fetch
EXEC SQL FETCH cursor_name INTOhost-variable , [host-variable,...];

示例
exec sql declare cur_student cursor for select Sno, Sname, Sclass from Student where Sclass= :vClass order by Sno for read only ;
exec sql open cur_student;

exec sql fetch cur_student into :vSno, :vSname, :vSage…
exec sql close cur_student;

四、可滚动游标及数据库的增删改

1、可滚动游标的概念、定义和使用

标准的游标始终是自开始向结束方向移动的,每fetch一次,向结束方向移动一次;一条记录只能被访问一次;再次访问该记录只能关闭游标后重新打开。
可滚动游标是可使游标指针在记录集之间灵活移动、使每条记录可以反复被访问的一种游标。

EXEC SQL DECLAREcursor_name [INSENSITIVE] [SCROLL] CURSOR
[WITH HOLD] FOR Subquery
[ORDER BY result_column [ASC | DESC][, result_column …][FOR READ ONLY | FOR UPDATE OF columnname [,
columnname ]…];
EXEC SQL FETCH
[NEXT |PRIOR | FIRST | LAST
I [ABSOLUTE | RELATIVE] value_spec ]
FROM cursor_name INTO host-variable [, host-variable …];

NEXT向结束方向移动一条;
PRIOR向开始方向移动一条;
FIRST回到第一条;
LAST移动到最后一条;
ABSOLUT value_spec定向检索指定位置的行,
value_spec由1至当前记录集最大值;
RELATIVE value_spec相对当前记录向前或向后移动,
value_spec为正数向结束方向移动,为负数向开始方向移动

可滚动游标移动时需判断是否到结束位置,或到起始位置。可通过判断是否到EOF位置(最后一条记录的后面),或BOF位置(起始记录的前面)。如果不需区分,可通过whenever not found语句设置来检测。

2、数据的删除与更新

一种是查找删除(与交互式DELETE语句相同),一种是定位删除
EXEC sQL DELETE FROM tablename [corr_name]
WHERE search_condition | WHERE CURRENT OF cursor_name;

示例:查找删除
exec sql delete from customers c where c.city =‘Harbin' and not exists ( select * from orders o where o.cid = c.cid);

示例:定位删除
exec sql declare delcust cursor for
select cid from customers c where c.city =‘harbin' and not exists ( select * from orders o where o.cid = c.cid)for update of cid;
exec sql open delcustWhile (TRUE)
exec sql fetch delcust into :cust_id;
exec sql delete from customers where current of delcust ;

3、数据库记录的更新

一种是查找更新(与交互式Update语句相同),一种是定位更新
EXEC sQL UPDATEtablename [corr_name]
SET columnname = expr [, columnname = expr …]
[ WHEREsearch_condition ] | WHERE CURRENT OF cursor_name;

示例:查找更新
execsql update student s set sclass ='035102’ where s.sclass = ‘034101’

示例:定位更新
exec sql declare stud cursor for
select * from student s where s.sclass =‘034101’for update of sclass;
exec sql open stud

While (TRUE)
exec sql fetch stud into :vSno, :vSname, :vSclass;
exec sql update student set sclass = '035102’where current ofstud ;

4、数据库记录的插入

只有一种类型的插入语句
EXEC SQL INSERT INTOtablename [(columnname [,columnname, …] )]
[ VALUES (expr [ , expr , …] ) | subqurey ];

示例:插入语句
exec sql insert into student ( sno, sname, sclass) values ('03510128',‘张三',‘035101');

示例:插入语句
exec sql insert into masterstudent ( sno, sname,sclass)
select sno, sname, sclass from student;

5、示例:宿主语言与SQL结合的过程性控制

求数据库中某一列位于中值的那一行

#include <stdio.h>
#include "prompt.h”
exec sql include sqlca;
char custprompt[ ] ="Please enter a customer ID:int main()

exec sql begin declare section;
char cid[5],user_name[20], user_pwd[10];
double dollars; 
int ocount;
exec sql end declare section;
exec sql declare dollars_cursor cursor for
select dollars from orders where cid = :cid and dollars is not nullorder by dollars;

int i;
exec sql whenever sqlerror goto report_error;
strcpy(user_name, "poneilsql");
strcpy(user_pwd, "xxXx”);
exec sql connect :user_name identified by :user_pwd;
While ( prompt(custprompt, 1, cid ,4)>=0 
exec sql select count(dollars) into :ocount from orders where cid =:cid ;
if (ocount ==0 )
printf("No record reviewed for cid value %sln", cid);
continue; 
exec sql open dollars _cursor;
for (i =0; i< (ocount+1)/2; i++)
exec sql fetch dollars_cursor into :dollars;
exec sql close dollars_cursor;
exec sql commit work;
printf("Median dollar amount =%fln”, dollars); 

五、状态捕获及错误处理机制

状态捕获及其处理
状态,是嵌入式SQL语句的执行状态,尤其指一些出错状态;有时程序需要知道这些状态并对这些状态进行处理

嵌入式SQL程序中,状态捕获及处理有三部分构成

  1. 设置SQL通信区:一般在嵌入式SQL程序的开始处便设置。
    exec sql include sqlca;
  2. 设置状态捕获语句:在嵌入式SQL程序的任何位置都可设置;可多次设置;但有作用域。
    exec sql whenever sqlerror goto report_error;
  3. 状态处理语句:某一段程序以应对SQL操作的某种状态
    report_error: exec sql rollback;

SQL通信区:SQLCA
SQLCA是一个已被声明过的具C语言的结构形式的内存信息区,其中的成员变量用来记录SQL语句执行的状态,便于宿主程序读取与处理
SQLCA是DBMS(执行SQL语句)与宿主程序之间交流的桥梁之一

状态捕获语句
exec sql whenever condition action;

Whenever语句的作用是设置一个“条件陷阱”,该条语句会对其后面的所有由Exec SQL语句所引起的对数据库系统的调用自动检查它是否满足条件(由condition指出).

  1. SQLERROR:检测是否有SQL语句出错。其具体意义依赖于特定的
  2. DBMSONOT FOUND:执行某一SQL语句后,没有相应的结果记录出现
  3. SQLWARNING:不是错误,但应引起注意的条件

如果满足condition,则要采取一些动作(由action指出)

  1. CONTINUE:忽略条件或错误,继续执行
  2. GOTO标号:转移到标号所指示的语句,去进行相应的处理STOP:终止程序运行、撤消当前的工作、断开数据库的连接
  3. DO函数或CALL函数:调用宿主程序的函数进行处理,函数返回后从引发该condition的Exec SQL语句之后的语句继续进行。

状态捕获语句Whenever的作用范围是其后的所有Exec SQL语句,一直到程序中出现另一条相同条件的Whenever语句为止,后面的将覆盖前面的。

int main()
exec sql whenever sqlerror goto handle_error;
exec sql create table customers(cid char(4) not null,
cname varchar(13), ... ...);
handle_error:
exec sql whenever sqlerror continue;
//控制是否无限循环:无,则可能:有,则不会
exec sql drop customers;exec sql disconnect;
fprintf(stderr,"could not create customers tableln");return -1;

典型DBMS系统记录状态信息的三种方法状态记录

  1. sqlcode:典型DBMS都提供一个sqlcode变量来记录其执行sql语句的状态,但不同DBMS定义的sqlcode值所代表的状态意义可能是不同的,需要查阅相关的DBMS资料来获取其含义
  2. sqlcode== 0, successful call;
  3. sqIcode<0, error, e.g., from connect, database does not exist , -16;
  4. sqlcode > 0, warning, e.g., no rows retrieved from fetch
  5. sqlca.sqlcode:支持SQLCA的产品一般要在SQLCA中填写sqlcode来记录上述信息;除此而外,sqlca还有其他状态信息的记录
  6. sqlstate:有些DBMS提供的记录状态信息的变量是sqlstate或sqlca.sqlstate

当我们不需明确知道错误类型,而只需知道发生错误与否,则我们只要使用前述的状态捕获语句即可,而无需关心状态记录变量(隐式状态处理)
但我们程序中如要自行处理不同状态信息时,则需要知道以上信息,但也需知道正确的操作方法(显式状态处理)

显式状态处理示例

exec sql begin declar section;
char sQLSTATE[6];
exec sql end declare section;

exec sql whenever sqlerror goto handle_error;

exec sql whenever sqlerror continue;exec sql create table custs
(cid char(4) not null, cname varchar(13),... .…. );

if (strcmp(SQLSTATE, "82100")==0)
<处理82100错误的程序>

以上是关于嵌入式SQL语言的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Go 语言开发的宿主程序中嵌入 WebAssembly

Lua与其他宿主语言交互原理剖析

Lua入门

SQL 四大功能DDL/DML/DCL/TCL

如何通过SQL语句来修改FireBird用户sysdba的密码

嵌入式SQL语言之动态SQL