数据库系统概念(第六版)课后习题答案-第三章SQL(实践习题)

3.1 使用大学模式,用SQL写出如下查询。(建议在一个数据库上实际运行这些查询,使用我们在本书的Web网站db-book.com上提供的样本数据,上述网站还提供了如何建立一个数据库和加载样本数据的说明。)

Classroom(building, room_number, capacity)

Department(dept_name, building, budget)

Course(course_id, title, dept_name, credits学分)课程信息

Instructor(ID, name, dept_name, salary)教员信息登记

Section(course_id, sec_id, semester, year, building, room_number, time_slot_id)开课信息

Teaches(ID, course_id, sec_id, semester, year)授课信息

Student(ID, name, dept_name, tot_cred学分)

Takes(ID, course_id, sec_id, semester, year, grade)选课信息

Advisor(s_ID, i_ID)辅导员信息

Time_slot(time_slot_id, day, start_time, end_time)

Prereq(course_id, prereq_id)

 

A.    找出Comp.Sci. 系开设的具有3个学分的课程名称。

Selecttitle

Formcourse

Wheredept_name = ‘Comp.Sci.’ and credits = 3;

B.    找出名叫Einstein的教师所教的所有学生的标识,保证结果中没有重复。

原始答案:

Selects_ID

From(select name, s_ID

Forminstructor,  advisor

Whereinstructor.ID = advisor.i_ID)

       Where name = ‘Einstein’

       修改后的答案:

       修改原因:上述筛选的是名叫Einstein的教师作为辅导员名下的学生。题目应该理解为名叫Einstein的教师开设的课程中教授的学生,所以修改SQL查询语句如下:

       授课老师的关系:

              Section naturaljoin teaches natural join instructor

              (course_id, sec_id, semester, year,building, room_number, time_slot_id, ID, name, dept_name, salary)

       学生选课的关系

              Studentnatural join takes

              (ID,name, dept_name, tot_cred, course_id, sec_id,semester, year, grade)

       决定一门课程的主码是(course_id, sec_id, semester, year

       所以老师的关系要和学生的关系以课程的主码进行连接,然后筛选出特定老师教的学生。

       完整SQL语句如下:

       Select distinctstudent.ID

       From (Section naturaljoin teaches natural join instructor)

                     Join(Student natural join takes)

                            Using (course_id, sec_id, semester, year)

       Where section.name = ‘Einstein’;

 

C.    找出教师的最高工资

用集合的比较语句实现:

Selectsalary

Forminstructor

Wheresalary >= all (select salary

Frominstructor);

用聚集函数实现:

Select max(salary)

Frominstructor;

 

D.    找出工资最高的所有教师(可能有不止一位教师具有相同的工资)。

SelectID, name

Frominstructor

Wheresalary = (select max(salary)

Frominstructor);

E.     找出2009年秋季开设的每个课程段的选课人数。

原始答案:

Selectcourse_id, count(distinct ID)

Fromtakes natural join section

Wheresemester= ‘Fall’ and year = 2009

Group bycourse_id;

修改后的答案:

Selectcourse_id,sec_id, count(distinct ID)

Fromtakes natural join section

Wheresemester= ‘Fall’ and year = 2009

Group bycourse_id, sec_id;

添加了对于sec_id属性的筛选,因为在2009年秋季同一个课程可能开设两次,我们必须把课程段考虑在内。

F.     从2009年秋季开设的所有课程段中,找出最多的选课人数。

原始答案:

Withmax_student (course_id, sec_id,num) as

(Select course_id,sec_id, count (distinctID)

From takes natural join section

Where semester= ‘Fall’ and year =2009

Group by course_id, sec_id

)

              Select max(num)

              From max_student;

注意with……as……定义临时关系的用法

使用另一种写法

     Select max (enrollment)

  From (Select count (distinct ID) as enrollment

From takes natural join section

Where semester= ‘Fall’ and year =2009

Group by course_id, sec_id);

 

G. 找出2009年秋季拥有最多选课人数的课程段。

Withmax_student (course_id, sec_id,num) as

(Select course_id,sec_id, count (distinctID)

From takes natural join section

Where semester= ‘Fall’ and year =2009

Group by course_id, sec_id

)

              Selectcourse_id, sec_id

              Frommax_student

              Where num = (select max(num)

From max_student);

 

 

3.2 假设给你一个关系grade_points(grade, points),它提供从takes关系中用字母表示的成绩等级到数字表示的得分之间的转换。例如,“A”等级可指定为对应于4分,“A-”对应于3.7分,“B+”对应于3.3分,“B”对应于3分,等等。学生在某门课程(课程段)上所获得的等级分值被定义为该课程段的学分乘以该生得到的成绩等级所对应的数字表示的得分。给定上述关系和我们的大学模式,用SQL写出下面的每个查询。为简单起见,可以假设没有任何takes元组在grade上取null值。

A.根据ID为12345的学生所选修的所有课程,找出该生所获得的等级分值的总和。

Select sum(credits*points)

From takes natural joincourse natural join grade_points

Where ID = ‘12345’

为了防止该生什么课都没选,可以将上面答案改良成下面这种:

(Select sum(credits*points)

From takes natural join course natural join grade_points

Where ID = ‘12345’)

Union

(Select 0

From student

Where takes.ID = ‘12345’ and not exists (select*

From takes

Where takes.ID= ‘12345’));

注意并运算的使用以及检测存在性的使用

 

B. 找出上述学生等级分值的平均值(GPA),即用等级分值的总和除以相关课程学分的总和。

Select (sum (credits*points))/ (sum(credits))

From takes natural joincourse natural join grade_points

Where ID = ‘12345’;

C. 找出每个学生的ID和等级分值的平均值。

Select ID, (sum(credits*points)) / (sum(credits))

From takes natural joincourse natural join grade_points

Group by ID;

 

3.3 使用大学模式,用SQL写出如下插入、删除和更新语句。

A.给Comp.Sci.系的每位教师涨10%的工资。

Updateinstructor

Setsalary = salary*1.1

Wheredept_name = ‘Comp.Sci.’;

B. 删除所有未开设过(即没有出现在section关系中)的课程。

Deletefrom course

Wherecourse.course_id not in (select course_id

Form section);

C.把每个在tot_cred属性上取值超过100的学生作为同系的教师插入,工资为10000美元。

Insertinto instructor

SelectID, name, dept_name, 10000

Fromstudent

Wheretot_cred  > 10000;

3.4 考虑图3-18中的保险公司数据库,其中加下划线的是主码。为这个关系数据库构造出如下SQL查询:

A.找出2009年其车辆出过交通事故的人员总数。

原始答案:

Selectcount (distinct driver_id)

From participatednatural join accident

Wheredate = 2009;

修改答案:

注意时间(date)并不代表年份(year),所以修改答案如下

Selectcount (distinct driver_id)

Fromparticipated natural join accident

Wheredate between date ‘2009-00-00’ and date ‘’2009-12-31

B.向数据库中增加一个新的事故,对每个必须的属性可以设定任意值。

这个题目可以先假定一些参数,完成数据库增加操作后,所有的属性均可以修改。

Insertinto accident

       Values(4007, ‘2009-09-01’, ‘Berkeley’)

Insertinto Participated

       Select 4007,  c.license , P.driver_id, 3000

       From (person as p) natural join (owns aso) natural join (car as c)

       Where p.name =’Jones’;

C.删除“John Smith”拥有的马自达车(Mazda)。

Deletefrom car

Wheremodel = ‘Mazda’ and license in (select license

From owns natural join person

Where name = ‘John Smith’);

Person(driver_id,name,address)投保人

Car(license,model,year)投保车

Accident(report_number,date,location)事故信息

Owns(driver_id,license)投保人与投保车关系

Participated(report_number,license,driver_id,damage_amount赔偿金)事故详情

 

 

3.5 假设有关系marks(ID, score),我们希望基于如下标准为学生评定等级:如果score<40得F;如果40≤score<60得C;如果60≤score<80得B;如果80≤score得A。写出SQL查询完成下列操作:

A.基于marks关系显示每个学生的等级。

SelectID,

              Case

                     When score<40 then ‘F’

                     When score<60 then ‘C’

                     When score<80 then ‘B’

                     Else ‘A’

              End

Frommarks;

 

B.找出各等级的学生数。

With grades as (Select ID,

              Case

                     When score<40 then ‘F’

                     When score<60 then ‘C’

                     When score<80 then ‘B’

                     Else‘A’

              End as grade

From marks)

Selectgrade count (distinct ID)

Fromgrades

Group bygrade;

3.6  SQL的like运算符是大小写敏感的,但字符串上的lower()函数可用来实现大小写不敏感的匹配。为了说明是怎么用的,写出这样一个查询:找出名称中包含了“sci ”子串的系,忽略大小写。

Selectdept_name

Fromdepartment

Where lower(dept_name) like ‘%sci%’;

3.7 考虑SQL查询

Selectdistinct p.a1

Fromp,r1,r2

Wherep.a1=r1.a1 or p.a1=r2.a1

在什么条件下这个查询选择的p.a1值要么在r1中,要么在r2中?仔细考察r1或r2可能为空的情况。

P, r1,r2均非空

3.8 考虑图3-19中的银行数据库,其中加下划线的是主码。为这个关系数据库构造出如下SQL查询:

A. 找出银行中所有有账户但无贷款的客户。

原始答案

Selectcustomer_name

From depositor

Wherecustomer_name not in (select customer name

From borrower);

换一种写法

(selectcustomer_name

Fromdepositor)

Except

(selectcustomer_name

Fromborrower)

注意Except差运算的使用方式

B. 找出与“Smith”居住在同一个城市、同一个街道的所有客户的名字。

原始答案:

Selectcustomer_name

Fromcustomer

Where(customer_street,customer_city) = (select customer_street,customer_city

From customer

Where customer_name = ‘Smith’);

另一种写法:

SelectF.customer_name

From(customer as F) join (customer as S) using(ustomer_street,customer_city)

WhereS.customer_name = ‘Smith’;

C. 找出所有支行的名称,在这些支行中都有居住在“Harrison”的客户所开设的账户。

Selectdistinct branch_name

Fromaccount natural join depositor natural join customer

Wherecustomer_city = ‘Harrison’;

Branch ( branch_name,  branch_city , assets 资产)分行信息

Customer (customer_name, customer_street, customer_city)客户信息

Loan (loan_number, branch_name, amount)贷款信息

Borrower (customer_name, loan_number)贷款人信息

Account(account_number, branch_name, balance)账户信息

Depositor(customer_name, account_number)账户人信息

图3-19

 

3.9 考虑图3-20的雇员数据库,其中加下划线的是主码。为下面每个查询写出SQL表达式:

Employee(employee_name,street,city)

Works(employee_name,company_name,salary)

Company(company_name,city)

Managers(employee_name,manager_name)

图3-20

A.找出所有为“First Bank Corporation”工作的雇员名字及其居住城市。

Select employee_name , city

From employee natural joinworks

Where company_name = ‘FirstBank Corporation’;

B. 找出所有为“First Bank Corporation”工作且薪金超过10000美元的雇员名字、居住街道和城市。

Select employee_name ,street,city

From employee natural joinworks

Where company_name = ‘FirstBank Corporation’ and salary >10000;

 

C. 找出数据库中所有不为“First Bank Corporation”工作的雇员。

(Select employee_name

From employee)

Except

(select employee_name

From employee natural joinworks

Where company_name = ‘FirstBank Corporation’);

 

D.找出数据库中工资高于“Small Bank Corporation”的每个雇员的所有雇员。

Select employee_name

From works

Where salary > (selectmax(salary)

From works

Where company_name = ‘Small Bank Corporation’

Group by company_name);

E. 假设一个公司可以在好几个城市有分部。找出位于“Small Bank Corporation”所有所在城市的所有公司。

原始答案

Select company_name

Form Company

Where city in (select city

From company

Where company_name = ‘SmallBank Corporation’);

       修改后答案

       原始答案中最后生成的公司名称会包含Small Bank Corporation,可能我们并不想包含Small Bank Corporation公司

(Select company_name

Form Company

Where city in (select city

From company

Where company_name = ‘SmallBank Corporation’))

       Except

(select company_name

From company

Where company_name = ‘Small Bank Corporation’);

 

F.  找出雇员最多的公司。

With A as(selectcompany_name, count(employee_name) as num

From works

Group by company_name)

       Select company_name, max(num)

       From A;

       另一种写法

       Select company_name

       From works

       Group by company_name

       Having count (employee_name) >= all(selectcount(employee_name)

From works

Group by company_name);

G.找出平均工资高于“First Bank Corporation”平均工资的那些公司。

With A as (select company_name, avg(salary) as avg_salary

From works

Group by company_name)

       Select company_name

       From A

       Where avg_salary > (select avg_salary

From A

Where company_name = ‘First Bank Corporation’);

3.10 考虑图3-20的关系数据库,给出下面每个查询的SQL表达式:

A. 修改数据库使“Jones”现在居住在“Newtown”市。

       Update employee

       Set city = ‘Newtown’

       Where employee_name = ‘Jones’;

B. 为“FirstBank Corporation”所有工资不超过100000美元的经理增长10%的工资,对工资超过100000美元的只增长3%

       Updata works as T

       Set T.salary = t.salary *1.03

       Where T.employee_name in (selectmanager_name

From manages)

                     And T.company_name = ‘FirstBank Corporation’

And t.salary >100000;

 

       Updata works as T

       Set T.salary = t.salary *1.1

       Where T.employee_name in (selectmanager_name

From manages)

                     And T.company_name = ‘FirstBank Corporation’

And t.salary <=100000;

另一种写法

Update works

Set salary= salary*(case

When salary>100000 then 1.03

Else 1.1)

Where employee_namein (select manager_name

Frome manager)

              And company_name = ‘First BankCorporation’;

你可能感兴趣的:(基础知识学习)