标签(空格分隔): 数据库
示例(来自课后习题)
public class ResultSetTable {
private ResultSet resultSet;
private ResultSetMetaData reslutSetMetaDate;
private int cols_num;
public void resultSetTable (ResultSet resultSet) throws SQLException {
this.resultSet = resultSet;
reslutSetMetaDate = resultSet.getMetaData();
cols_num = reslutSetMetaDate.getColumnCount();
for (int i = 1; i <= cols_num; i++) {
System.out.println(reslutSetMetaDate.getColumnName(i) + ' ');
}
while ( resultSet.next()) {
for (int i = 1; i <= cols_num; i++) {
system.out.println(reslutSet.getString(reslutSetMetaDate.getColumnName(i)) + ' ');}
}
}
}
示例二
函数和过程允许“业务逻辑”作为存储过程记录在数据库中,并在数据库内执行。尽管这样的“业务逻辑”能被写成程序设计语言过程并完全存储在数据库之外,但把它们定义成数据库的存储过程有以下的优点
- 允许多个应用访问
- 当业务规则发生变化时,进行单个节点的改变,而不必更改应用程序的其他部分
- 应用代码可以调用存储过程,而不是直接更新数据库关系
SQL标准不被很多数据库所支持,由此,即便是最基本的特性在不同的数据库产品中,都会有不同的语法与语义。在这种情况下,使用一种命令式程序设计语言,从SQL查询和触发器的定义中调用,可以免去程序员学习多种非标准数据库语言的烦恼。
--声明函数
--给定系名,返回该系的教师数木
create function dept_count (dept_name varchar(20))
returns integer
beign
declare d_count integer
select d_count integer
from instructor
where instructor.dept_name = dept_name;
return d_count;
end
--调用函数
--返回教师数大于12的所有系的名称和预算
select dept_name, budget
from department
where dept_count(dept_name) > 12;
--声明函数
--返回包含某特定系的所有教师的表
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 = instrutor_of.dept_name);
--调用
--返回金融系的所有教师
select *
from table(instructor_of('Finance'));
--改写示例一
create procedure dept_count_proc(in dept_name varchar(20), out d_count integer)
begin
select count(*) into d_count
from instructor
where instructor.dept_name = dept_count_proc.dept_name;
end
- declare :声明变量,可以是任意合法的SQL类型
- set :赋值变量
- begin...end:复合语句
- begin atomic...end:作为一个单一事务执行
- while语句:
while 布尔表达式 do
语句序列;
end while
- repeat语句:
repeat
语句序列;
until 布尔表达式
end repeat
- for循环
declare n integer default 0;
for r as
select budget from department where dept_name = 'Music'
do
set n = n + r.budget
end for
- leave:跳出循环
- iterate:跳过剩余语句从循环的开始进入下一个元祖
- if-then-else:
if 布尔表达式
then 语句或复合语句
elseif 布尔表达式
then 语句或复合语句
else 语句或复合语句
end if
- case:
- exception condition & handler:
declare out_of_classroom_seats condition
declare exit handler for out_of_classroom_seats
begin
sequence of statements
end
举例:
--确认选课的学生数未超过该课所在教室的容量
--完成学生对该课的注册
--返回错误代码(>=0成功,<0失败)
--以out参数的形式返回失败原因
create function registerStudent(
in s_id varchar(5),
in s_courseid varchar(8),
in s_secid varchar(8),
in s_semester varchar(6),
in s_year numeric(4, 0),
out errorMsg varchar(100))
returns integer
begin
--选课的学生数
declare currEnrol int;
select count(*) into currEnrol
from takes
where courseid = s_courseid and
sec_id =s_secid and
semester = s_semester and
year = s_year;
--该课所在教室的容量
declare limit int;
select capacity into limit
from classroom natural join section
where courseid = s_courseid and
sec_id = s_secid and
semester = s_semester and
year = s_year;
if (currEnrol < limit)
begin
insert into takes values
(s_id, s_courseid, s_secid, s_semester, s_year, null);
return (0);
end
--否则,已经达到课程容量上线
set errorMsg = 'Enrollment limit reached for course' ||
s_courseid || 'section' || s_secid;
return (-1);
end;
1.执行条件:触发事件 + 执行条件
2.执行动作
1.用触发器实现复杂的完整性约束
2.满足特定条件自动执行某项任务
3.满足特定条件对用户发出警报
--在插入时启动触发器
create trigger timeslot_check after insert on section
--过渡变量:插入完成后存储所插入行的值
referencing new row as nrow
--对每一个插入行迭代
for each row
/* time_slot_id不存在该id*/
when (nrow.time_slot_id not in
(select time_slot_id from time_slot))
begin
rollback
end;
--在删除时启动触发器
create trigger timeslot_check2 after delete on time_slot
--过渡变量:存储已经更新或者删除行的旧值
referencing old row as orow
for each row
when( orow.time_slot_id not in
(select time_slot_id from time_slot)
/* 旧id应该在time_slot中*/
and
orow.time_slot_id in
(select time_slot_id from section))
/* 旧id不应该在section*/
begin
rollback
end;
create trigger credits_earned after update of takes on (grade)
referencing new row as nrow
referencing old row as orow
for each row
/*只有当课程从‘F’或者空值被更新到代表课程成功完成的具体分数时,触发器才被激发*/
when nrow.grade <> 'F' and nrow.grade is not null
and (orow.grade = 'F' or orow.grade is null)
begin
update student
set tot_cred = tot_cred +
(select credits
from course
where course.id = nrow.courseid)
where student.id = nrow.id;
end;
/*若所插入分数的值为空白,则用null替代*/
create trigger setnull before update of takes
referencing new row as nrow
for each row
when (nrow.grade = ' ')
begin atomic
set nrow.grade = null;
end;
alter trigger trigger_name disable;//禁用触发器
drop trigger trigger_name;//永久移除触发器
create trigger reorder after update of level on inventory
referencing old row as orow, new row as nrow
for each row
when nrow.level <= (select level from minlevel where minlevel.item = nrow.item)
and
orow.level > (select level from minlevel where minlevel.item = orow.item))
begin atomic
insert into orders
(select item, amount
from reorder
where reorder.item = orow.item)
end
触发器虽好,但不要滥用!
1)触发器可以替代级联特性来实现外码的on delete cascsde特性
但这样工作量更大,且这种约束难以理解。
2)可以使用触发器来物化视图。
然而,现在很多数据库系统都支持自动视图维护。
3)触发器也被用来复制或备份数据库
现代数据库内置了数据库复制工具
4)
--例题5.7
/*
define/create:
on/of:
table:
statement:
new table:
*/
define trigger insert_into_branch_cust_via_depositor
after insert on branch_cust
referencing new table as inserted
for each statement
insert into branch_cust
select branch_name, customer_name
from inserted, account
where inserted.account_name = account.account_name
define trigger insert_into_branch_cust_via_account
after insert on branch_cust
referencing new table as inserted
for each statement
insert into branch_cust
select branch_name, customer_name
from inserted, depositor
where depositor.account_name = inserted.account_name
define trigger delete_from_branch_cust_via_depositor
after delete on depositor
referencing old table as deleted
for each statement
select branch_name, customer_name
from deleted, account
where deleted.account_name = account.account_name
define trigger delete from branch cust via account
after delete on account
referencing old table as deleted
for each statement
delete from branch cust
select branch name, customer name
from depositor, deleted
where depositor.account number = deleted.account number
define trigger delete_from_account
after delete on account
referencing old row as orow
for each row
delete from depositor
where depositor.customer_name not in (
select customer_name
from depositor
where account_number <> orow.account_number)