高级SQL(Chapter 5)
使用其他语言调用SQL
动态SQL
运行时以字符串形式构建SQL查询→提交查询→把结果存入程序变量中
JDBC(for Java)5.1.1
使用时,Java程序必须引用java.sql.*
驱动程序的加载
Class.forName(String driver);
driver:一个实现了java.sql.Driver接口的实体类
- 连接到数据库
Connection con=DriverManager.getConnection(String url, String userid, String passwd);
url:指明服务器所在的主机名称及端口等其他信息
- 向数据库中传递SQL语句
Statement stmt=conn.createStatement();//创建statement
stmt.excuteUpdate(String expression);//实现非查询语句(更新,删除,插入等),以字符串形式作为参数。返回整数表达被操作的元组数
ResultSet rset=stmt.excuteQuery(String expression);//实现查询,返回结果集,存在ResultSet类型的对象rset中
- 对结果集的操作
while(rset.next()){
System.out.println(rset.getString("dept_name")+" "+rset.getFloat(2));
}
rset.next()查看集合中是否还剩下未取出的元组,有的话就取出,没有就返回false
getString和getFloat是把结果集中的东西转化成String或Float
参数“dept_name”表示提取属性名为dept_name的值
参数“2”表示提取第二个属性的值
- 完成操作之后记得关闭
stmt.close();
conn.close();
- 预备语句
感觉有点像模板函数一样,某些地方可以到时候再替换
除此以外,出于安全和规范考虑(防sql注入),预备语句是首选
- 可更新结果集
对结果集中元组的更新将引起数据库中的更新
- 事务
默认情况下每一句sql语句都被当成一个自动提交的事务,可以使用
conn.setAutoCommit(false/true);
打开或关闭这种自动提交,关闭之后通过以下方式进行显式提交或回滚
conn.commit();
conn.rollbacck();
- 其他
getBlob();//返回的不是大对象本身,而是指针一样的东西
getClob();
setBlob();
ODBC(for C, C++)5.1.2
嵌入式SQL5.1.3
将SQL查询嵌入到其他语言(称为宿主语言)中,使用宿主语言写出的程序可以通过嵌入式sql的语法访问数据库
一个使用嵌入式sql的程序在编译前必须用特殊的预处理器进行处理
为了使预处理器识别嵌入式sql请求,使用如下语句
EXEC SQL <嵌入式sql语句>
- 连接到数据库
EXEC SQL connect to <server> user <user_name> using <password>;
- 使用宿主语言变量
变量声明要这样放
EXEC SQL BEGIN DECLARE SECTION;
int credit_amount;
EXEC SQL END DECLARE SECTION;
使用的时候要在前面加上冒号以区分sql变量和宿主变量
- 声明游标
EXEC SQL
declare c cursor for
select Id,name
from student
where tot_credit>:credit_amount;//:credit_amount是宿主语言变量,所以前面加了个冒号
用open语句来执行查询,并把结果存放在临时关系中
EXEC SQL open c;
使用fetch语句把结果元组赋值给宿主语言的变量,要求一个变量对应一个属性
EXEC SQL fetch c into :si,:sn;
fetch语句每次只会取出一条结果,并将游标后移一个,所以可以通过循环取出所有结果
当结果已经被全部取出,SQLSTATE被置为“02000”,意味不再有数据
使用如下close语句删除临时关系
EXEC SQL close c;
函数和过程
声明和调用SQL函数
- 格式
eg.给定一个系名,返回该系中的教师数目
create function dept_count (dept_name varchar(20))
returns integer #声明返回的类型
begin
declare d_count integer;
select count(*) into d_count
from instructor
where instructor.dept_name=dept_name#这里为什么不需要用dept_count.dept_name
return d_count;
end
- 支持以关系为返回结果的函数,称为表函数(table functions)
eg.
create function instructor_of(dept_name varchar(20))
returns table(
ID varchar(5),
name varchar(20),
dept_name varchar(20),
salary numeric(8,2))
return table
(select ID,name,dept_name,salary
from instructor
where instructor.dept_name=instructor_of.dept_name);#使用函数的参数时要用函数名instructor_of作为前缀
- 调用的时候直接用
声明和调用过程(procedure)
create proocedure dept_count(in dept_name varchar(20),out d_count integer)
begin
select count(*) into d_count
from instructor
where instructor.dept_name=dept_count.dept_name
end
- 调用的时候用call
declare d_count integer;
call dept_count('Physics',d_count);
其他语句
- while语句
while 布尔条件 do
语句序列;
end while
- repeat语句
repeat
语句序列;
until 布尔表达式
end repeat
- for循环
declare n integer default 0;//默认值为0
for r as
select budget from department
where dept_name='music'
do
set n=n-r.budget
end for
//leave相当于break
//iterate相当于continue
- if语句
if ...
then ...
elseif ...
then ...
else ...
end if
- 异常条件(Exception)
declare out_of_classroom_seats condition
declare exit handler for out_of_classroom_seats
begin
......//这里的语句可以执行signal out_of_classroom_seats来引发异常
end
SQL中用其他语言定义函数
效率高,可跨数据库
- Function
create fuction dept_count(dept_name varchar(20))
returns integer
language C
external name '/user/avi/bin/dept_count'
- Procedure
create procedure dept_count_proc(in dept_name varchar(20),out count integer)
language C
external name '/user/avi/bin/dept_count_proc'
触发器(Trigger)
格式
delimiter @ #声明分隔符@
create trigger timeslot_check1 after insert on section
for each row #在插入的每一行上进行迭代
begin
if(NEW.time_slot_id #可以用OLD和NEW来表示操作发生前后的表
NOT IN(
SELECT
time_slot_id
FROM
time_slot))
then
rollback;
end if;
end @ #结束以@为分隔符的时光
delimiter ; #恢复以;作为分隔符的时光
设为无效
alter trigger ... disable;
高级聚集特性
排序
select ID, rank() over (order by(GPA) desc) as s_rank # rank函数对所有在order by属性上相等的元组赋予相同的名次
from student_grades
order by s_rank;
空值null的存在可能会影响排序,可以通过设定nulls first或nulls last指定
select ID, rank() over (order by GPA desc nulls first) as s_rank