SEX CHAR(1), ECITY CHAR(20), PRIMARY KEY(E#)); CREATE TABLE COMP
( C# CHAR(4) NOT NULL,
CNAME CHAR(20) NOT NULL, CITY CHAR(20), PRIMARY KEY(C#));
CREATE TABLE WORKS
( E# CHAR(4) NOT NULL, C# CHAR(4) NOT NULL, SALARY SMALLINT, PRIMARY KEY(E#, C#),
FOREIGN KEY(E#) REFERENCES EMP(E#), FOREIGN KEY(C#) REFERENCES COMP(C#));
② SELECT E#, ENAME
FROM EMP
WHERE AGE>50 AND SEX='M';
③ SELECT EMP.E#, ENAME
FROM EMP, WORKS
WHERE EMP.E#=WORKS.E# AND SALARY>1000; ④ SELECT A.E#, A.ENAME
FROM EMP A, WORKS B, WORKS C WHERE A.E#=B.E# AND B.E#=C.E#
AND B.C#='C4' AND C.C#='C8';
⑤ SELECT A.E#, A.ENAME
FROM EMP A, WORKS B, COMP C WHERE A.E#=B.E# AND B.C#=C.C#
AND CNAME='联华公司' AND SALARY>1000 AND SEX='M';
⑥ SELECT E#, COUNT(C#) AS NUM, SUM(SALARY) AS SUM_SALARY
FROM WORKS GROUP BY E#; ⑦ SELECT X.E#
FROM WORKS X
WHERE NOT EXISTS
(SELECT *
FROM WORKS Y
WHERE E#='E6' AND NOT EXISTS
(SELECT *
FROM WORKS Z WHERE Z.E#=X.E# AND Z.C#=Y.C#));
⑧ SELECT A.E#, A.ENAME
FROM EMP A, WORKS B, COMP C WHERE A.E#=B.E# AND B.C#=C.C#
AND CNAME='联华公司'
AND SALARY<(SELECT AVG(SALARY)
FROM WORKS, COMP
WHERE WORKS.C#=COMP.C#
AND CNAME='联华公司');
⑨ UPDATE WORKS
SET SALARY=SALARY+100
WHERE E# IN (SELECT E# FROM EMP WHERE AGE>50); ⑩ DELETE FROM WORKS WHERE E# IN (SELECT E# FROM EMP WHERE AGE>60); DELETE FROM EMP WHERE AGE>60;
3.14 对第3.13题中的关系建立一个有关女职工信息的视图EMP_WOMAN,属性包括(E#,ENAME,
C#,CNAME,SALARY)。
然后对视图EMP_WOMAN操作,检索每一位女职工的工资总数。(假设每个职工可在多个公司兼职)
解: CREATE VIEW EMP_WOMAN
AS SELECT A.E#, A.ENAME, C.C#, CNAME, SALARY
FROM EMP A, WORKS B, COMP C WHERE A.E#=B.E# AND B.C#=C.C#
AND SEX='F';
SELECT E#,SUM(SALARY) FROM EMP_WOMAN
GROUP BY E#;
3.15 在第1章中提到的仓库管理数据库中有五个基本表: 零件 PART(P#,PNAME,COLOR,WEIGHT) 项目 PROJECT(J#,JNAME,DATE) 供应商 SUPPLIER(S#,SNAME,SADDR) 供应 P_P(J#,P#,TOTAL) 采购 P_S(P#,S#,QUANTITY)
① 试用SQL DDL语句定义上述五个基本表,需说明主键和外键。
② 试将PROJECT、P_P、PART三个基本表的联接定义为一个视图VIEW1,将PART、P_S、SUPPLIER三个基本表的联接定义为一个视图VIEW2。
③ 试在上述两个视图的基础上进行查询操作: a)检索上海的供应商所供应的零件的编号和名称。 b)检索项目J4所用零件的供应商的编号和名称。 解:① CREATE TABLE PART
(P# CHAR(6),
PNAME CHAR(10) NOT NULL, COLOR CHAR(6), WEIGHT FLOAT(6), PRIMARY KEY(P#));
CREATE TABLE PROJECT
(J# CHAR(6),
JNAME CHAR(12) NOT NULL, DATE DATE,
PRIMARY KEY(J#)); CREATE TABLE SUPPLIER
(S# CHAR(8),
SNAME CHAR(12) NOT NULL, SADDR VARCHAR(30), PRIMARY KEY(S#));
CREATE TABLE P_P
(J# CHAR(6), P# CHAR(6), TOTAL INTEGER,
PRIMARY KEY (J#, P#)
FOREIGN KEY(J#) REFERENCES PROJECT(J#), FOREIGN KEY(P#) REFERENCES PART(P#)); CREATE TABLE P_S
(P# CHAR(6), S# CHAR(8), QUANTITY INTEGER, PRIMARY KEY (P#, S#)
FOREIGN KEY(P#) REFERENCES PART(P#),
FOREIGN KEY(S#) REFERENCES SUPPLIER(S#));
② CREATE VIEW VIEW1
AS SELECT A.J#, JNAME, DATE, C.P#, PNAME, COLOR,
WEIGHT, TOTAL
FROM PROJECT A, P_P B, PART C WHERE A.J#=B.J# AND B.P#=C.P#;
CREATE VIEW VIEW2
AS SELECT A.P#, PNAME, COLOR, WEIGHT, C.S#, SNAME,
SADDR, QUANTITY
FROM PART A, P_S B, SUPPLIER C WHERE A.P#=B.P# AND B.S#=C.S#;
③ a) SELECT P#, PNAME
FROM VIEW2
WHERE SADDR LIKE ’上海%’; b) SELECT S#, SNAME FROM VIEW1, VIEW2
WHERE VIEW1.P#=VIEW2.P# AND J#=’J4’;
3.16 对于3.2题的教学数据库中基本表SC,建立一个视图: CREATE VIEW S_GRADE(S#,C_NUM,AVG_GRADE) AS SELECT S#,COUNT(C#),AVG(GRADE) FROM SC
GROUP BY S#;
试判断下列查询和更新操作是否允许执行。如允许,写出转换到基本表SC上的相应操作。 ① SELECT *
FROM S_GRADE;
② SELECT S#,C_NUM FROM S_GRADE
WHERE AVG_GRADE>80; ③ SELECT S#,AVG_GRADE FROM S_GRADE
WHERE C_NUM >(SELECT C_NUM
FROM S_GRADE WHERE S#='S4');
④ UPDATE S_GRADE SET S#='S3' WHERE S#='S4';
⑤ DELETE FROM S_GRADE
WHERE C_NUM>4;
答:① 允许查询。相应的操作如下:
SELECT S#,COUNT(C#) AS C_NUM,AVG(GRADE) AS AVG_GRADE FROM SC
GROUP BY S#;
② 允许查询。相应的操作如下:
SELECT S#,COUNT(C#) AS C_NUM FROM SC GROUP BY S#
HAVING AVG(GRADE)> 80;
③ 允许查询。相应的操作如下:
SELECT S#,AVG(GRADE) AS AVG_GRADE FROM SC GROUP BY S#
HAVING COUNT(C#)> (SELECT COUNT(C#)
FROM SC GROUP BY S#
HAVING S#='S4');
④ 不允许。C_NUM是对SC中的学生选修门数进行统计,在未更改SC表时,要在视图S_GRADE中更改门数,是不可能的。
⑤ 不允许。在视图S_GRADE中删除选修门数在4门以上的学生元组,势必造成SC中这些学生学习元组的删除,这不一定是用户的原意,因此使用分组和聚合操作的视图,不允许用户执行更新操作。
3.17 预处理方式对于嵌入式SQL的实现有什么重要意义?
答:此时宿主语言的编译程序不必改动,只要提供一个SQL函数定义库,供编译时使用。预处理方式只是把源程序中的SQL语句处理成宿主语言的函数调用形式。
3.18 在宿主语言的程序中使用SQL语句有哪些规定? 答:有三条规定:
① 在程序中要区分SQL语句与宿主语言语句,所有SQL语句必须加前缀标识“EXEC SQL”以及结束标志“END_EXEC”;
② 允许嵌入的SQL语句引用宿主语言的程序变量,而主语句不能引用数据库中的字段变量;
③ SQL的集合处理方式与宿主语言的单记录处理方式之间要用游标机制协调。 3.19 SQL的集合处理方式与宿主语言单记录处理方式之间如何协调?
答:用游标机制协调。把SELECT语句查询结果定义成游标关系,以使用文件的方式来使用游标关系。与游标有关的SQL语句有四个:游标定义,游标打开,游标推进,游标关闭。 3.20 嵌入式SQL的DML语句何时不必涉及到游标?何时必须涉及到游标? 答:不涉及游标的DML语句有下面两种情况: ① INSERT、DELETE、UPDATE语句,只要加上前缀和结束标志,就能嵌入在宿主语言程序中使用;
② 对于SELECT语句,如果已知查询结果肯定是单元值,也可不必涉及游标操作。 涉及游标的DML语句有下面两种情况: ① 当SELECT语句查询结果是多个元组时,必须用游标机制把多个元组一次一个地传递给主程序处理;
② 对游标指向元组进行修改或删除操作时,也涉及到游标。 3.21 在教学数据库中检索成绩不及格的学生信息,要求显示(S#,SNAME,C#,CNAME,TEACHER),
试编写实现此功能的嵌有SQL语句的C语言程序段。 解: #define NO_MORE_TUPLES !(strcmp(SQLSTATE,〞02000〞))
void sel()
{ EXEC SQL BEGIN DECLARE SECTION;
char sno[5],cno[5],sname[9],cname[11],teacher[9]; char SQLSTATE[6];
EXEC SQL END DECLARE SECTION; EXEC SQL DECLARE x CURSOR FOR
SELECT s.s#,sname,c.c#,cname,teacher FROM s,sc,c
WHERE s.s#=sc.s# and sc.c#=c.c# and grade<60; EXEC SQL OPEN scx; while(1)
{ EXEC SQL FETCH FROM x
INTO :sno,:sname,:cno,:cname,:teacher;
if(NO_MORE_TUPLES)break;
printf(〞%s,%s,%s,%s,%s\\n〞,sno,sname,cno,cname,teacher);
}
EXEC SQL CLOSE x; }
3.3 练习题
3.3.1 填空题
1.在SQL中,关系模式称为__________,子模式称为__________,元组称为__________,
属性称为__________。
2.SQL中,表有两种:__________和__________,也称为__________和__________。 3.SQL中,用户有两种:__________和__________。