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);
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;
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;
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赔偿金)事故详情 |
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;
Selectdept_name
Fromdepartment
Where lower(dept_name) like ‘%sci%’;
Selectdistinct p.a1
Fromp,r1,r2
Wherep.a1=r1.a1 or p.a1=r2.a1
在什么条件下这个查询选择的p.a1值要么在r1中,要么在r2中?仔细考察r1或r2可能为空的情况。
P, r1,r2均非空
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
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’);
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’;