select S1.sid,S1.sname from sailors S1 join reserves R1 on S1.sid=R1.sid join boats B1 on R1.bid=B1.bid where B1.color='red'
intersect
select S1.sid,S1.sname from sailors S1 join reserves R1 on S1.sid=R1.sid join boats B1 on R1.bid=B1.bid where B1.color='green';
如果有的DBMS不能用intersect,那么可以嵌套查询
select s.sid, s1.sname from sailors s, boats b, reserves r
where s.sid=r.sid and r.bid=b.bid and b.color='red' and s.sid in
(select s2.sid, s2.sname from sailors s2,boats b2,reserves r2 where s2.sid=r2.sid and r2.bid=b2.bid and b2.color='green');
- 其他的运算符
in 在…范围,not in 不在…范围 exists 存在,not exists 不存在 unique 某个值在表里面是否唯一,not unique 不唯一 op any,op all,op in。op是<,>,=,<=,>=,!=。意思就是(如< any就是小于任意一个值就行,也就是说选出不是最小值的那个值。< all就是小于所有的值,也就是选出最小值)。但是这样操作有的DBMS支持 如选出级别大于Horatio的水手的信息
select * from sailors s where s.rating >any (select s2.rating from sailors s2 where s2.sname='horatio');
就是说s中的级别大于任意一个子表中的级别即可,因为子表中的姓名为horatio的水手不止一个,所以只需要大于任意一样就行
- 预定了所有船的选手,选修了所有计算机课的学生。这个“所有”使用的就是除法
如查找预定了所有船的选手的姓名:
select s1.sname
from sailors s
where not exists
(select b.bid from boats b
except
select r.bid from reserves r where r.sid=s.sid);
3.1-2就是这个水手没有预定的船 4.前面加上not exists表明这个水手没有预定的船不存在,即预定了所有的船。
如果数据库不支持except
select s1.sname
from sailors
where not exists
(select b.bid from boats b
where not exists
(select r.bid from reserves r where r.bid=b.bid and r.sid=s.sid));
2.1前面加上not exists表示选出水手没有预定的船 3.2前面加上not exists表示不存在水手没有预定的船,即水手预定了所有的船
-
group by 语句在having语句的执行之前。并且having需要和group by同时出现,这就要求having语句中必须有分组的东西。即如果group by是以deptno进行分组的,那么having中必须出现deptno字段,没有deptno字段的全部放到where中去,否则会报错。 -
cast可以给null幅值或者赋属性 如 有两张表:student(name,school) soldiers(name,service) 现在想把这两张表合并到一起成这样的形式: | name | school | service | 则
create view prospects(name, school, service) as
select name,school,cast(NULL as varchar(20))
from students
union
select name,cast(NULL as varchar(20)), service from soldiers;
propects后面跟的是试图的三个字段 cast(NULL as varchar(20))指的是将null变成varchar类型
- when,then,case的一些应用
有一个表officers(name,status,rank,title) 在status字段中可以用1表示active duty状态 用2表示reserve状态 3表示special assignment状态 4表示retired状态 则查询的时候可以这样写
select name, (case status
when 1 then 'active duty'
when 2 then 'reserve'
when 3 then 'special assignment'
when 4 then 'retired'
else 'unknown' end) as status
from officers;
when,then,case类似于switch,case和if,所以sql中如果想用判断语句,一般选择when,then,case
- EXCEPT和EXCEPT ALL
都是做集合差,但EXCEPT ALL 不删重复元组,也就不用排序,效率比EXCEPT高 - 递归查询
有一张表FedEmp(name, salary, manager) 查找Hoover手下的所有薪资大于100000的人 可以知道,Hoover手下的手下也有可能有人,也就是形成了类似于树的结构,因此需要用到递归查询
WITH agents(name,salary) AS
((SELECT name,salary
FROM FedEmp
WHERE manager='Hoover')
UNION ALL
(SELECT f.name,f.salary
FROM agents AS a,FedEmp AS f
WHERE f.manager=a.name))
SELECT name from agents where agents.salary>10000;
再如飞机零件图(componments): 一个wing机翼需要5个struct,1个aileron… 1个struct需要10个rivet… 查询一个机翼需要多少rivet 因为wing直接间接都在用rivet,所以需要递归查询 递归查询先查出临时表:
with wingpart(subpart, qty) as
((select subpart, qty from componments where part='wing')
union all
(select c.subpart, w.qty,*c.qty from wingpart w, components c where w.subpart=c.part))
一定要注意的是w.qtyc.qty,比如一个wing机翼需要5个struct,1个struct需要10个rivet,则需要510=50个rivet 所以sql语句应该写成
with wingpart(subpart, qty) as
((select subpart, qty from componments where part='wing')
union all
(select c.subpart, w.qty,*c.qty from wingpart w, components c where w.subpart=c.part))
select sum(qty) as qty from wingpart where subpart='rivet';
定义数组变量
EXEC SQL BEGIN DECLARE SECTION;
char SNO[7];
char GIVENSNO[7];
char CNO[6];
char GIVENCNO[6];
float GRADE;
short GRADEi;
EXEC SQL END DECLARE SECTION;
执行命令的方式 连接数据库
EXEC SQL CONNECT :uid IDENTIFIED by:pwd: ;
执行DML语句
EXEC SQL INSERT INTO SC(SNO,CNO,GRADE)VALUES(:SNO,:CNO,:GRADE);
查询【简单查询,返回一个值】
EXEC SQL SELECT GRADE INTO :GRADE,:GRADE1
FROM SC
WHERE SNO=:GIVENSNO AND CNO=:GIVENCNO;
为了处理查询返回的集合,引入游标机制 因为关系型数据库查询结果是一个集合,而c中的变量仅仅是一个变量,所以需要使用游标 定义游标
Define a cursor
EXEC SQL DECLAR<cursor name> CURSOR FOR
select...
from ...
where...
打开游标
EXEC SQL OPEN<cursor name>
一旦open一个游标,就可以把游标理解成一个文件,这时候sql返回的就可以是一个集合了
取游标内每一条元组
EXEC SQL FETCH <cursor name>
INTO :hostvar1,:hostvar2;
使用fetch操作之后,就可以把游标(看成一个文件,文件里面有sql返回的数据集合)中的数据按顺序返回给c中的变量,因为文件中的数据是一个集合,很多,所以需要用到循环,在循环中进行fetch
判断查询结果是否取完
SQLCA.SQLCODE ==100 时取完
关闭CURSOR
CLOSE cursor
1.可以直接运行的动态SQL【非查询】 用字符数组动态拼接出一条sql语句
EXEC SQL BEGIN DECLARE SECTION;
char sqlstring[200];
EXEC SQL END DECLARE SECTION;
char cond[150];
strcpy(sqlstring, "delete from student where");
printf("Enter search condition:");
scanf("%s", cond);
strcat(sqlstring, cond);
EXEC SQL EXECUTE IMMEDIATE: sqlstring;
2.动态SQL的查询【带动态参数】
EXEC SQL BEGIN DECLARE SECTION;
char sqlstring[200];
int birth_year;
EXEC SQL END DECLARE SECTION;
strcpy(sqlstring, "delete from student where year(bdate)<=:y;");
printf("Enter birth year for delete:");
scanf("%d", &birth_year);
EXEC SQL PREPARE PURGE FROM:sqlstring;
EXEC SQL EXECUTE PURGE USING:birth_year;
- 存储过程机制
- 允许用户把一组常用的sql定义为一个存储过程,系统对其优化编译后可以被直接调用。
- 用户使用更加方便,应用需求发生变化时,只需要改变存储过程
- 改进性能
- 可以扩展DBMS的功能
创建一个存储过程
EXEC SQL
create procedure drop_student
(IN student_no char(7),
OOUT message char(30))
BEGIN ATOMIC
delete from student where SNO=student_no;
delete from SC where SNO=student_no;
SET message=student_no || 'droped';
END;
|