SQL入门(4): 嵌入式SQL语言
本节讲述内容:
1.嵌入式SQL 语言概述
2.变量声明与数据库连接
3.数据集与游标
4.可滚动游标与数据库的增删改
5.状态捕捉以及错误处理机制
(一)嵌入式SQL语言
之前我们所学的都是交互式SQL 语言: select .. from .. where..
嵌入式SQL语言 表示 将SQL语言嵌入到 某一种高级语言中使用, 比如C++ ,Java, powerbuilder等
它们也称为宿主语言(host language).
复杂的检索不能用一条SQL语句完成, 需要结合高级语言中的顺序\分支\循环结构帮助处理.
if [conditon] then SQL_query else SQL_query end if
do while [condition] SQL_query end do
还有在SQL语句的检索结果基础上,再进行处理的
SQL_query1
for ... do
process the record
next
SQL_query 2
if .. then
else
end if
交互式SQL: select sname, sage from student where sname='xy';
嵌入式SQL: 以宿主语言C语言为例,
exec sql select sname, sage into :vsname, :vsage from student where sname='xy';
主要区别:
(1) exex sql 是一个引导词, 它引导sql 语句, 将SQL语句预编译成C编译器可识别的语句.
(2) 增加 into 子句, 用于把SQL 语句的检索结果赋给高级语言的程序变量
(3) 用冒号开头 表示高级语言的程序变量 :vsname , :vsage
冒号很重要, 用于区分是程序变量 还是 表的字段!! .... 还有很多特点之后在详细介绍
为啥要学嵌入式SQL , 用来解决啥问题?
下面逐个解决上述8个问题
(一) 数据库的连接(问题1)
在嵌入式SQL 操作之前, 首先需要与数据库进行连接
不同的DMBS 的语句是有差别的,
在嵌入式SQL程序执行之后, 需要断开数据库
SQL 执行的提交与撤销
SQL语句在执行过程中, 必须要有提交, 撤销语句
提交: exec sql commit work;
撤销: exec sql rollback work;
很多DBMS 都设计了捆绑 提交\撤销 与断开连接在一起的语句, 以保证在断开连接之前
使用户确认提交或 撤销先前的工作, Oracle 中就是这样:
exec sql commit release;
exec sql rollback release;
为什么需要提交和撤销呢? 这个设计到数据库中的'' 事务 ''处理
什么是事务? 从应用程序员角度来看, 事物是一个存取或者改变数据库内容的程序的一次执行,
或者说是一条或者多条SQL 语句的一次执行被看做是一个事务
事务 一般由应用程序员提出, 因此有开始和结束, 结束前需要提交或者撤销
begin transaction
exec sql...
exec sql...
exec sql commit work | exec sql rollback work --提交或者撤销
end transaction
注意: 提交表示这一系列操作对数据库的更新是有效的, 撤销则表示无效
其实从 任何一个SQL语句执行 就表示了一个事务的开始, 到了 commit 或 rollback 则结束一个事务,
因此上述的 begin end 可以省略.
事务的ACID 特性
A : atomicity 原子性, DBMS保证表示事务中的一组操作是不可分的,要么全做,要么一条也不做
C : consistency 一致性,例如两个人同时在买车票,会不会买到同一张车票
I: isolation 隔离性 两个事务操作互不干扰
D: durability 已提交事务的影响是持久的, 被撤销的事务影响可以恢复
事务处理技术是DBMS的核心处理技术!!
(二) 变量声明(问题2)
exec sql select sname, sage into :vsname, :vsage from student where sname=:specname;
加了冒号表示高级语言的程序变量, 这些变量需要声明
exec sql begin declare section; --开始声明
char vsname[], specname[] ='xy' ;
int vsage;
exec sql end declare section; -- 结束声明
注: 宿主程序的字符串变量长度要比字符型字段多1, 因为宿主程序的字符串尾部多一个终止符'\0' .
-- 变量的声明与使用
exec sql begin declare section;
char vsname[], specname[] ='xy' ;
int vsage;
exec sql end declare section;
-- 用户在此处 可以基于键盘输入给specname 赋值
exec sql select sname, sage into :vsname, :vsage from student where sname=:specname;
实例: 数据库连接+变量定义
#include<stdio.h>
#include"prompt.h"
exec sql include sqlca; --sqlca 表示SQL的通信区, communication area char cid_prompt[]="please enter customer id:";
int main()
{
exec sql begin declare section; --下面声明变量
char cust_id[], cust_name[];
float cust_discnt;
exec sql end declare section; exec sql whenever sqlerror goto report_error;-- 错误捕获
exec sql whenever not found goto notfound; -- 记录没有找到 strcpy(user_name,"poneilsql");-- 字符串赋值
strcpy(user_pwd,"123456"); exec sql connect :user_name identified by :user_pwd; -- 连接数据库
while((prompt(cid_prompt,1,cust_id,4))>=0){
exec sql select cname,discnt into :cust_name,:cust_discnt
from customers where cid=:cust_id; -- 根据输入的客户id 找到名字和折扣 exec sql commit work;-- 提交
printf("customer's name is %s and discount
is %.1f\n",cust_name, cust_discnt);
continue; -- 接着循环,再输入客户id
notfound:printf("can't find customer %s, continuing\n", cust_id);}
exec sql commit release; -- 断开数据库的连接
return 0;
report_error: -- 前面报错的执行
print_dberror();
exec sql rollback release; -- 断开连接
return 1;
}
(三) 数据集与游标(问题3 4 5)
问题3: SQL 语句如何执行?
问题4: 如何将SQL 检索到的结果传递回宿主程序进行处理?
问题5: 如何将静态SQL , SQL语句中的常量更换为变量?
如何读取单行数据和多行数据, 单行结果处理与多行结果处理的差异: into 子句 和 游标 cursor
1. 检索单行结果, 可以将结果直接传送到宿主主程序的变量中, select ... into ...
exec sql select sname, sage into :vsname, :vsage from student
where sname=:specname;
2. 如果是多行结果, 则需要使用游标cursor
游标是指向某个检索记录的指针, 通过这个指针, 每次读一行, 处理一行,
接着再读一行...,直到全部处理完毕 fetch..into... (一次一行)
需要先定义一个cursor-->再打开-->接着一条一条处理-->最后关闭
exec sql delcare cur_student cursor for --游标名
select sno, sname, sclass from student
where sclass=''; -- 定义游标
exec sql open cur_student; --打开游标
exec sql fetch cur_student into :vsno, :vsname, :vsclass; --取数据
...
exec sql close cur_student; --关闭游标
具体实例:
已知表orders(cid, aid, product, dollars) 客户id, 代理人id, 产品, 金额
游标: 给定一个客户id, 选出该客户下的所有代理商 和 金额(多行数据)
#define True 1
#include<stdio.h>
#include"prompt.h"
exec sql include sqlca; --sqlca 表示SQL的通信区, communication area exec sql begin declare section; --声明变量
char cust_id[], agent_id[];
double dollar_sum;
exec sql end declare section; int main()
{
char cid_prompt[]="please enter customer id:"; -- 定义提示字符串
exec sql declare agent_dollars cursor for -- 定义游标
select aid,sum(dollars) from orders
where cid=:cust_id group by aid; exec sql whenever sqlerror goto report_error;-- 错误捕获
exec sql connect to testdbl; --连接数据库
exec sql whenever not found goto finish; -- 记录没有找到 while((prompt(cid_prompt,1,cust_id,4))>=0){
exec sql open agent_dollars; -- 打开游标
while(True){ -- 打印每一条记录
exec sql fetch agent_dollars into :agent_id,:dollar_sum;
printf("%s %11.2f\n",agent_id, dollar_sum)
}; finish:
exec sql close agent_dollars; -- 关闭游标
exec sql commit work; -- 提交
exec sql disconnect current;--断开连接
return 0;
report_error: -- 前面报错的执行
print_dberror();
exec sql rollback;-- 撤销
exec sql disconnect current; --断开连接
return 1;
}
总结游标:
exec sql delcare cur_student cursor for --游标名
select sno, sname, sclass from student
where sclass=:vclass; -- 定义游标
order by sno
for read only; --只读, 不可更新
cursor 数据读取 fetch : exec sql fetch cursor_name into host_variable
exec sql delcare 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; -- 关闭
可滚动游标与数据库的增删改
标注的游标 始终是自开始到结束方向移动的, 每fetch 一次,向结束方向移动一次,
每一条记录只能被访问一次, 再次访问该记录只能关闭游标后重新打开
可不可以实现游标的向上移动呢? ODBC (open database connectivity) 是一种跨DBMS
的DB 操作平台, 它在应用程序与实际的DBMS之间提供了一种通用的接口,
很多DBMS不支持可滚动游标, 但是通过ODBC 可实现该功能
定义中增加了 scroll
使用如下:
可滚动游标移动时需要判断 是否到了结束位置, 或者到了起始位置,
EOF表示最后一条记录的后面位置
BOF表示起始位置的前面
如果不需要区分最上 最下, 则可以用whenever not found 进行检测
用游标进行数据库的增删改
1. 查找删除(与交互式delete 语句相同)
exec sql delete from customers c where c.city='harbin' and
not exists (select * from orders o where o.cid=c.cid)
-- 删除 城市是哈尔滨 且在订单 orders表里面没有记录的.
2. 定位删除
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 delcust
while(True){
exec sql fetch delcust into :cust_id;
exec sql delete from customers where current of delcust;}
1. 查找更新
exec sql update student s
set scalss='' where s.sclass='';
2.定位更新
exec sql declare stud cursor for
select * from student s where s.sclass='' and
for update of sclass;
exec sql open stud
while(True){
exec sql fetch stud into :vsno, :vsname,:vsclass;
exec sql update student
set sclass='' where current of stud;}
插入语句
exec sql insert into student(sno,sname,sclass)
values ('','xy',''); exec sql insert into master_stud(sno,sname,sclass)
select sno,sname,sclass from student;
综合实例: 求数据库中某一列位于中值的那一行
--已知表 orders(cid,aid,product,dollars)
-- 寻找数据库中某一列位于中值的那一行
#include<stdio.h>
#include"prompt.h"
exec sql include sqlca; --sqlca 表示SQL的通信区, communication area
char cid_prompt[]="please enter customer id:"; -- 定义提示字符串 int main()
{
exec sql begin declare section; --声明变量
char cid[], user_name[], user_pwd[];
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 null order by dollars; exec sql whenever sqlerror goto report_error;-- 错误捕获
strcpy(user_name,"poneilsql");-- 字符串赋值
strcpy(user_pwd,"123456");
exec sql connect :user_name identified by :user_pwd; -- 连接数据库
--exec sql whenever not found goto finish; -- 记录没有找到 while((prompt(cid_prompt,1,cust_id,4))>=0){
exec sql select count(dollars) into :ocount from orders
where cid=:cid;
if(ocount==0)
{printf("no record reviewed for cid value %s\n",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=%f\n",dollars); }
SQL入门(4): 嵌入式SQL语言的更多相关文章
- C语言中嵌入式SQL语句
原文:[转载]C语言中嵌入式SQL语句 http://blog.csdn.net/cnlht/archive/2007/12/12/1930960.aspx原文地址 实验内容: 掌握SQL Serve ...
- 第14讲:嵌入式SQL语言(基本技巧)
一.交互式SQL的局限 & 嵌入式SQL的必要性 专业人员(如DBA)可以熟练地运用交互式SQL语言,但普通用户却不是那么容易上手,所以需要通过数据库应用程序来使用数据库.编写一个可以与数据库 ...
- 数据库-第八章 数据库编程-8.1 嵌入式SQL
嵌入式SQL 一.嵌入式SQL的处理过程 1.嵌入式SQL语句的基本格式 2.嵌入式SQL的处理过程 3.主语言访问数据库的基本步骤 ⅰ建立数据库连接 ⅱ定义必要的主变量和数据通信区 ⅲ访问数据库并返 ...
- .Net程序员学用Oracle系列(28):PLSQL 之SQL分类和动态SQL
1.SQL 语句分类 1.1.分类方法及类型 1.2.数据定义语言 1.3.数据操纵语言 1.4.其它语句 2.动态 SQL 理论 2.1.动态 SQL 的用途 2.2.动态 SQL 的语法 2.3. ...
- 数据库原理及应用-SQL数据操纵语言(Data Manipulation Language)和嵌入式SQL&存储过程
2018-02-19 18:03:54 一.数据操纵语言(Data Manipulation Language) 数据操纵语言是指插入,删除和更新语言. 二.视图(View) 数据库三级模式,两级映射 ...
- 数据库系统学习(十)-嵌入式SQL语言之动态SQL
第十讲 嵌入式SQL语言之动态SQL 静态SQL 区别变量和属性:高级语言向嵌入式SQL传递变量的方法 动态SQL 动态构造SQL语句是应用程序员必须掌握的重要手段 SQL语句的动态构造示例 根据界面 ...
- 数据库系统学习(九)-嵌入式SQL语言之基本技巧
第九讲 嵌入式SQL语言之基本技巧 901 什么是嵌入式SQL语言 交互式SQL语言的局限性 嵌入式SQL语言 交互式和嵌入式语言的对比 高级语言中使用嵌入式语言需要解决的问题 902 程序与数据库连 ...
- SQL入门经典(一)之简介
今天是我第一天开通博客,也是我的第一篇博客.以后为大家带来第一篇关于学习技术性文章,这段时间会为大家带来是SQL入门学习.希望大家坚持读下去,因为学历有限.我也是初学者.语言表达能力不好和知识点不足, ...
- 3.7 嵌入式SQL
可以放入所有高级语言中去,如C 因为,SQL是过程性语句,需要高级语言的非过程性处理集合的分类处理 一.一般形式 所有的SQL语句都必须加前缀EXEC SQL SQL语句完成结束标志(:或END EX ...
随机推荐
- 【翻译】asp.net core中使用MediatR
这篇文章来自:https://ardalis.com/using-mediatr-in-aspnet-core-apps 本文作为翻译,有一些单词翻译成中文可能会有一些误解(对于读者)或者错误(对于作 ...
- Express使用art-template模板引擎
第一步:安装 npm install --save art-template npm install --save express-art-template 第二步:指定.html使用的解析引擎(官方 ...
- 定位z-index
1.z-index數值大的元素覆蓋數值小的元素,z-index需要在標明定位方式的元素有效: 3.父元素和子元素 ,如果父元素的index有效,子元素覆蓋父元素:但父元素的z-index失效(未設置定 ...
- Linux 学习 (三) 文件搜索命令
Linux达人养成计划 I 学习笔记 locate 文件名 搜索速度比较快 只能根据文件名搜索 搜索的是保存在 /var/lib/mlocate 的数据库(每天更新一次) 新建文件需要执行 updat ...
- java 的数据类型及其所占的字节数
1.char java中的一个char是2个字节.java采用unicode,2个字节来表示一个字符. 一个数字或英文或汉字都是一个字符,只不过数字和英文时,存储的2个字 节的第一个字节都为0,就是浪 ...
- jsp篇 之 jsp页面中的路径问题
jsp页面中的路径问题: 一般情况下,jsp中路径问题是和我们之前在servlet中讨论的html里面的路径问题是一 样的,但是在[jsp中可以动态获得该项目的url]. 如果在jsp页面的上面写了这 ...
- 【Android O】 Service AAA does not have a SELinux domain defined
在init.AAA.rc里面添加了一个脚本启动的服务: service AAA /vendor/bin/sh /vendor/etc/AAA_spec.sh user root group root ...
- git仓库构建小记
1.新建 .git 文件夹 约定的文件目录下,新建 .git 文件夹 mkdir test.git 2.初始化服务端仓库 git init --bare test.git 此时进入 test.git ...
- 小程序运行报错:errMsg: "request:fail url not in domain list"
错误原因: 报错提示说请求的url不在域名列表里,应该是还没有配置服务器域名 解决方法: 可点击开发者工具右上角 详情-项目设置-不校验合法域名.web-view(业务域名).TLS 版本以及 HTT ...
- 【bfs】最少转弯问题
题目描述 给出一张地图,这张地图被分为n×m(n,m<=100)个方块,任何一个方块不是平地就是高山.平地可以通过,高山则不能.现在你处在地图的(x1,y1)这块平地,问:你至少需要拐几个弯才能 ...