厦门大学的一个课件 备查
http://www.cs.xmu.edu.cn/education/fine_courses/database/%BE%AB%C6%B7%BF%CE%B3%CC%BD%A8%C9%E8%C4%DA%C8%DD/3_%CD%F8%C2%E7%B0%E6cai/content/index.htm
3. 不用游标的嵌入式SQL语句应用技术
所谓不用游标的SQL语句,是指一般不需要返回结果数据,也不需要使用主变量的语句。它们是嵌入式SQL中最简单的一类语句。有以下几种:
· 说明性语句
· 数据定义语句
· 数据控制语句
· 查询结果为单记录的SELECT语句
· 非CURRENT形式的UPDATE语句
· 非CURRENT形式的DELETE语句
· INSERT语句
其中:
*) 所有的说明性语句、数据定义与控制语句都不需要使用游标,在主语言中嵌入说明性语句、数据定义与控制语句,只要给语句加上前缀EXEC SQL和语句结束符即可。
*) INSERT语句也不需要使用游标,但通常需要使用主变量。
*) SELECT语句、UPDATE语句、DELETE语句则更复杂些。
以下分别讨论常见的几种使用方法:
一、说明性语句
交互式SQL中没有说明性语句,这里的说明性语句是专为在嵌入式SQL中说明主变量等而设置的,一对由两条语句组成:
EXEC SQL BEGIN DECLARE SECTION;
<变量定义语句>
EXEC SQL END DECLARE SECTION;
两条语句必须配对出现,相当于一个括号,两条语句中间是主变量、指示变量的说明。
二、数据定义语句
例1 建立一个“学生”表Student
EXEC SQL CREATE TABLE Student
(Sno CHAR(5) NOT NULL UNIQUE,
Sname CHAR(20),
Ssex CHAR(1),
Sage INT,
Sdept CHAR(15));
数据定义语句中不允许使用主变量。例如下列语句是错误的:
EXEC SQL DROP TABLE :table_name;
三、数据控制语句
例2 把查询Student表权限授给用户U1
EXEC SQL GRANT SELECT ON TABLE Student TO U1;
四、查询结果为单记录的SELECT语句
在嵌入式SQL中,查询结果为单记录的SELECT语句需要用INTO子句指定查询结果的存放地点。该语句的一般格式为:
EXEC SQL SELECT [ALL|DISTINCT] <目标列表达式>[,<目标列表达式>]...
INTO <主变量>[<指示变量>][,<主变量>[<指示变量>]]...
FROM <表名或视图名>[,<表名或视图名>] ...
[WHERE <条件表达式>]
[GROUP BY <列名1> [HAVING <条件表达式>]]
[ORDER BY <列名2> [ASC|DESC]];
说明:
该语句对交互式SELECT语句的扩充就是多了一个INTO子句,把从数据库中找到的符合条件的记录,放到INTO子句指出的主变量中去。其他子句的含义不变。使用该语句需要注意以下几点:
*) INTO子句、WHERE子句的条件表达式、HAVING短语的的条件表达式中均可以使用主变量,但这些主变量必须事先加以说明,并且引用时前面要加上冒号。
*) 查询返回的记录中,可能某些列值为空值NULL,则如下处理:如果INTO子句中主变量后面跟有指示变量,则当查询得出的某个数据项为空值时,系统会自动将相应主变量后面的指示变量置为负值,但不向该主变量执行赋值操作,即主变量值仍保持执行SQL语句之前的值。所以当发现指示变量值为负值时,不管主变量为何值,均应认为主变量值为NULL。指示变量只能用于INTO子句中,并且也必须事先加以说明,引用时前面要加上冒号。
*) 如果数据库中没有满足条件的记录,即查询结果为空,则DBMS将SQLCODE的值置为100。
*) 如果查询结果实际上并不是单条记录,而是多条记录,则程序出错,DBMS会在SQLCA中返回错误信息。
例3 根据学生号码查询学生信息。假设已将要查询的学生的学号赋给了主变量givensno
EXEC SQL SELECT Sno, Sname, Ssex, Sage, Sdept
INTO :Hsno, :Hname, :Hsex, :Hage, :Hdept
FROM Student
WHERE Sno=:givensno;
上面的SELECT语句中Hsno, Hname, Hsex, Hage, Hdept和givensno均是主变量,并均已在前面的程序中说明过了。
例4 查询某个学生选修某门课程的成绩。假设已将要查询的学生的学号赋给了主变量givensno,将课程号赋给了主变量givencno
EXEC SQL SELECT Sno, Cno, Grade
INTO :Hsno, :Hcno, :Hgrade:Gradeid
FROM SC
WHERE Sno=:givensno AND Cno=:givencno;
由于学生选修一门课后有可能没有参加考试,也就是说其成绩为空值,所以我们在该例INTO子句中加了指示变量Gradeid,用于指示主变量Hgrade是否为空值。指示变量也需要和所有主变量一起在前面程序中事先说明。执行此语句后,如果Gradeid小于0,则不论Hgrade为何值,均认为该学生成绩为空值。
虽然对于仅返回一行结果数据的SELECT语句可以不使用游标,但从应用程序独立性角度考虑,最好还是使用游标。因为如果以后数据库改变了,该SELECT语句可能会返回多行数据,这时不使用游标就会出错。
五、非CURRENT形式的UPDATE语句
非CURRENT形式是指特殊情况下的应用。在这种情况下的嵌入式UPDATE语句中,SET子句和WHERE子句都可以使用主变量,其中SET子句中还可以使用指示变量。以下分别用几个例子说明它们的应用技术:
例5 将全体学生1号课程的考试成绩增加若干分。假设增加的分数已赋给主变量Raise
EXEC SQL UPDATE SC
SET Grade=Grade+:Raise
WHERE Cno='1';
该操作实际上是一个集合操作,DBMS会修改所有学生的1号课程的Grade属性列。
例6 修改某个学生1号课程的成绩。假设该学生的学号已赋给主变量givensno,修改后的成绩已赋给主变量newgrade
EXEC SQL UPDATE SC
SET Grade=:newgrade
WHERE Sno=:givensno;
例7 将计算机系全体学生年龄置NULL值
Sageid=-1;
EXEC SQL UPDATE Student
SET Sage=:Raise:Sageid
WHERE Sdept='CS';
将指示变量Sageid赋一个负值后,无论主变量Raise为何值,DBMS都会将CS系所有记录的年龄属性置空值。它等价于:
EXEC SQL UPDATE Student
SET Sage=NULL
WHERE Sdept='CS';
六、非CURRENT形式的DELETE语句
与上同理,DELETE语句的WHERE子句中可以使用主变量指定删除条件。
例8 某个学生退学了,现要将有关他的所有选课记录删除掉。假设该学生的姓名已赋给主变量stdname
EXEC SQL DELETE
FROM SC
WHERE Sno=
(SELECT Sno
FROM Student
WHERE Sname=:stdname);
另一种等价实现方法为:
EXEC SQL DELETE
FROM SC
WHERE :stdname=
(SELECT Sname
FROM Student
WHERE Studnet.Sno=SC.sno);
显然第一种方法更直接,从而也更高效些。
如果该学生选修了多门课程,执行上面的语句时,DBMS会自动执行集合操作,即把他选修的所有课程都删除掉。
七、INSERT语句
INSERT语句的VALUES子句中可以使用主变量和指示变量。
例9 某个学生新选修了某门课程,将有关记录插入SC表中。假设学生的学号已赋给主变量stdno,课程号已赋给主变量couno。
gradeid=-1;
EXEC SQL INSERT
INTO SC(Sno, Cno, Grade)
VALUES(:stdno, :couno, :gr:gradeid);
由于该学生刚选修课程,尚未考试,因此成绩列为空。所以本例中用指示变量指示相应的主变量为空值。
厦门大学计算机科学系 薛永生