【3.4】

【a题】☆☆☆☆☆
涉及表格:
人员------participated.driver_id
交通事故------accident
要统计driver_id,要用count(*)。约束是2017年,约束的字段是accident表的year字段,因此思路是先交两个表格,那么必须以外域键为约束,然后再用2017为约束限制。
select count(*)
from accident, participated
where accident.report_number=participated.report_number and year = 2017
写错了:
因为这会筛选出来所有在2017年发生车祸的所有记录,而不是人数,可能有菜逼司机撞了六七次。因此count对象要distinct,而且筛选字段是driver_id
【正解】
select count(distinct driver_id)
from accident, participated
where accident.report_number=participated.report_number and accident.year = 2017

【b题】☆☆☆☆☆
涉及表格:
汽车------car
ID为X的人------owns
思路:找到这个人拥有的所有汽车,再约束年份为2010,涉及两个表格,因此要用license_plate外域键做约束,再用car.year=2010再次约束
delete from car, owns**[启发1]**
where car.license_plate = owns.license_plate and owns.driver_id = '12345' and car.year=2010
写错了:
严重语法错误:不能同时删两个表
标准 SQL 的 DELETE 语句一次只能删除一个表的数据 。你不能写 DELETE FROM table1, table2。题目要求是"删除汽车",所以只能 DELETE FROM car。
正确思路与写法:
我们要从 car 表中删除数据,条件是:这辆车的车牌号必须出现在 owns 表中(且属于司机 '12345'),并且年份是 2010。
启发1:删除只能删一个表,因此但凡涉及其他表都有用子查询或ETAwith语句。
启发2:用in在子查询中,必须前后一致

【正解】
delete from car
where year = 2010 and license_plate in (
select license_plate[启发2]
from owns
where driver_id='12345'
)
【3.8】

【a题】★☆☆☆☆
考点:Except使用
涉及表格:
客户的ID------用borrower不要用depositor
有账户------depositor
思路:有账号的人是customer,借了钱的是borrower,ID可以差集出来,差集except要求列的数量一致
【正解】
select ID
from depositor
except
select ID
from borrower

【b题】★☆☆☆☆
考点:in的使用,in代表有一个匹配即可,全匹配要用双否
涉及表格:客户------customer
【正解】
select ID
from customer
where (customer_street, customer_city) in (
select customer_street, customer_city
from customer
where ID='12345'
)

【c题】★☆☆☆☆
考点:至少一位的表达
涉及表格:支行------branch
客户------customer
思路:至少一位 some/Any(表格),先子查询出该分行中开设了账户的客户
select branch_name
from branch
where branch_city = Any(
select customer_city
from customer, depositor
where customer.ID=depositor.ID and customer.customer_street="Harrison"
)
不对
涉及的表格是branch account customer depositor
因此要把所有内容笛卡尔积出来,筛选
【正解】
select b.branch_name
from account as a, branch as b, customer as c, depositor as d
where a.branch_name=b.branch_name and c.ID=d.ID and a.account_number = d.account_number and c.customer_city="Harrison";
【3.9】

【a题】☆☆☆☆☆
设计表格:雇员------employee
工作------works
但是二者之间没有之间关系。必须引入work表
select e.ID e.person_name e.city
from employee as e, work as w, company as c
where e.ID=w.ID and w.company_name= c.company_name and c.company_name='First Bank Corporation'
冗余了,不需要company表,company_name包含在works中了
【正解】
select e.ID e.person_name e.city
from employee as e, work as w
where e.ID=w.ID and w.company_name='First Bank Corporation';
【b题】☆☆☆☆☆
select e.ID e.person_name e.city
from employee as e, work as w, company as c
where e.ID=w.ID and w.company_name= c.company_name and c.company_name='First Bank Corporation' and w.salary>10000;
同上,冗余了,不需要company表
【正解】
select e.ID e.person_name e.city
from employee as e, work as w
where e.ID=w.ID and w.company_name='First Bank Corporation' and w.salary>10000;
【c题】☆☆☆☆☆
考点:Except的使用
使用except
select e.ID
from employee as e, company as c
where except (
select e.ID
from e,c
where c.company_name='First Bank Corporation'
)
思路是对的,但是except使用错误
except是要用在两个表中,但是不是嵌套查询而是平级查询
因此:
【正解】
select ID
from employee
except
select ID
from works
where works.company_name='First Bank Corporation'

【d题】 ★☆☆☆☆
考点:全称量词ALL的使用
思路:先聚集函数得到公司最高值,或者ALL一次,
select e.ID
from employee as e, works as w
where e.ID=w.ID and w.salary> ALL(
select salary
from e,w,company as c
where c.company_name='First Bank Corporation' and e.ID=w.ID
)
子查询别名错误 :子查询的 FROM 子句中不能直接写 from e, w,必须写完整的表名 from employee e, works w。
【正解】
select e.ID
from employee as e, works as w
where e.ID=w.ID and w.salary> ALL(
select w2.salary
from works as w2
where w2.company_name='First Bank Corporation' and e.ID=w.ID
)
【e题】★★☆☆☆
考点:自交使用
先找到SBC的所有所在城市,然后找这些城市有哪些公司,典型的自交问题【单表排查类型】
子查询是select city,
select c.company_name
from company as c
where c.city in (
select c.city
from c
where c.company_name="Small Bank Corporation"
)
修正后:
【正解】
select c1.company_name
from company as c1, company as c2
where c2.company_name = c1.company_name and c1.company_name != 'Small Bank Corporation' and c2.company_name = 'Small Bank Corporation'
【f题】★☆☆☆☆
考点:全称量词ALL的使用
思路:统计问题用count
select c.company_name
from company as c, works as w
where c.company_name = w.company_name and count(distinct ID) >= (
select count(distinct ID)
from c,w
where c.company_name = w.company_name
)
依然是老问题,companyname已经在works中了,直接用works即可
比较逻辑错误 :你不能拿一个具体的 count 去和一个子查询的 count 直接在 WHERE 里比(除非用 HAVING)
🎯 考察点: GROUP BY 分组统计、HAVING 子句过滤分组结果、ALL 与聚合函数的结合。
【正解】
select c.company_name
from works as w
group by w.company_name
having count(w.ID) > ALL(
select count(w2.ID)
from works as w2
group by w2.company_name
)
如果取一个的话,也可以用order解决
select company_name
from works
group by company_name
order by count(works) ASC

【g题】★☆☆☆☆
思路:明显的分桶问题 groupby 聚类,
select
from company as c. works as w
where c.ID=w.ID
group by c.company_name
having avg(salary)>
【正解】
select w.company_name
from works as w
group by w.company_name
having avg(w.salary)>(
select avg(w2.salary)
from works w2
where w2.company_name="First Bank Corporation"
)
【问题】
这套题影响最大的是:要找对表格,不要引入冗余表
except的使用是平级表
子查询的from必须写完整表名,不可以用父查询的简写,且要别名
单表内部关系排查使用自交思路(比较同一个表中属性的关系)
不能拿一个具体的 count 去和一个子查询的 count 直接在 WHERE 里比(除非用 HAVING)
where c.company_name = w.company_name and count(distinct ID) >= (
select count(distinct ID)
having avg(w.salary)>(
select avg(w2.salary)
什么时候写 SELECT X,什么时候写 SELECT table.X?
核心原则:当列名在查询涉及的表中不唯一时,必须加表名(或别名)前缀;否则可以省略。
【3.15】


【a题】★★★★★
考点:双重否定
涉及表格:
账户------account
客户------customer depositor,二者有通外域键
支行------branch
思路:关键在于如何表达"在所有支行都有",这明显是双重否定
select *
from branch as b
where b.branch_city='Brooklyn' and
但是我不会
唯一一种办法是假设用户不会重复在一家支行开户,这样可以用在BK银行开户数量=支行数量来解。
【正解】
【计数法求解】
思路:客户在 Brooklyn 支行开的账户数 == Brooklyn 支行总数
核心属性就是account_number,先where过滤出在BK银行有账号的用户,然后按id将用户groupby,然后查每个桶的用户的branch_name数量和BK银行分行数量是否一致
select *
from branch as b, depositor as d, account as a
where b.branch_name="BK" and b.branch_name=a.branch_name and a.account_number = d.account_number
group by d.ID
having count(distinct b.branch_name) =(
select count *
from branch
where branch_name="BK"
)
【双重否定做法】


不存在这样的支行(在BKN的支行)
该用户没有在这里有账户
select c.customer_name
from deposit as d, customer as c
where c.ID=d.ID and not exist(
select *
from branch
where branch_city="BKN" and not exists (
select *
from account
where account.branch_name=branch.branch_name
)
)
不对,

select customer_name
from customer as c
where not EXISTS(
select *
from branch
where branch_city="BKN" and not EXISTS(
select *
from account,deposit
where account.branch_name = branch.branch_name and deposit.ID=c.ID --该用户没有在这里有账户
)
)


【b题】☆☆☆☆☆
【正解】
select sum(amount)
from loan
【c题】★☆☆☆☆
考点:where中不能用聚集函数
select b1.branch_name
from branch as b1, branch as b2
where b1.assets > min(b2.assets)
错误,不能在where中用聚集函数
【正解】
select branch_name
from branch
where assets>(
select min(asset)
from branch
where branch_name="BKN"
)
【3.16】


【a题】☆☆☆☆☆
【正解】
select e.ID, person_name
from employee as e, works as w, company as c
where e.ID=w.ID and w.company_name=c.company_name and e.city=company.city
【b题】★★★☆☆
考点:高级自交使用
涉及表:
manages
employee
【正解】
select e.ID, person_name
from employee as e,employee as m, maneges
where e.ID = manages.ID and m.ID=manages.manager_id and e.street=m.street and e.city=m.city



【c题】★☆☆☆☆
【正解】
select e.ID, e.person_name
from employee as e, works as w1
where e.ID=w1.ID and w.salary > (
select avg(salary)
from works as w, company as c
where w.company_name=c.company_name
)
【d题】★★★★★
考点:多重映射
按公司的名字gb员工的工资,得到sum,然后父查询select min,得到的是最小的sum,但要映射到公司名字上,因此要再套一层having sum(salary)=这个最小值
【正解】
select company_name
from works
group by company_name
having sum(salary) =
(
select min(total)
from (
select sum(w.salary) as total
from works as w, company as c
where w.company_name = c.company_name
group by c.company_name
) as sum_salary
)
还有一个解法,就是排序取最小,但只能取出最小的一个
select company_name
from works
group by company_name
order by sum(salary) ASC
LIMIT 1;
【3.17】


【a题】☆☆☆☆☆
【正解】
update works
set salary = salary*1.1
where company_name="First Bank Corpoeration"
【b题】★★☆☆☆
考点:约束条件无法通过要修改的表约束,必须要用子查询
update works
set salary = salary*1.1
where company_name="First Bank Corpoeration" and ID in (
select ID
from employee,manages
where employee.ID=manages.manager_id
)
不对,不需要连接 employee 表,因为 manages 和 works 都通过 ID 关联即可
【正解】
update works
set salary = salary*1.1
where company_name="First Bank Corpoeration" and ID in (
select distinct manager_id
from manages
)
【c题】☆☆☆☆☆
【正解】
delete from works
where company_name="First Bank Corpoeration"
【3.21】

【a题】☆☆☆☆☆
至少一本-》in秒了
【正解】
select memb_no,name
from member
where member_no in (
select member_no
from member as m, book, borrowed as b
where book.publisher="MH" and b.isbn=book.isbn and b.memb_no = m.menb_no
)
【b题】★★★★★
考点:双重否定
类似3.15 a题,双否我肯定是写不出来的->不存在一本没借,因此还是用计数法
【正解】
【计数法】
select memb_no,name
from member,book,borrowed
where member.memb_no=borrowed.memb_no and borrowed.isbn=book.isbn
group by memb_no,name
having count(distinct isbn)(--拥有和这个出版社isbn一样多的isbn,就是找一个能唯一标识全部的属性
select distinct isbn
from book
where publiser="GH"
)
【双重否定法】
双重否定解释:
- 外层
NOT EXISTS:确保"不存在这样的书" - 内层
NOT EXISTS:这本书是该会员没借过的 - 合起来:"不存在一本 McGraw-Hill 的书是该会员没借过的" → 即他借了所有 McGraw-Hill 的书。
select memb_no,name
from member as m
where not exists(
select *
from book
where publisher ="GH" and not exists(--不存在这样的书
select *
from borrowed as br
where m.memb_no=br.memb_no and book.isbn=br.isbn
)
)

【c题】★★★★☆
**考点:**select的内容必须出现在groupby中!
显然的分组统计问题,groupby出版社,然后统计每个成员借的书,大于5输出
select m.memb_no,m.name
from member as m, book,borrowed as br
where m.memb_no=br.memb_no and br.isbn=book.isbn
group by book.publisher
having count(*)>5;
错误!select的内容必须出现在groupby中!!!
【正解】
select m.memb_no,m.name
from member as m, book, borrowed as br
where m.memb_no=br.memb_no and br.isbn=book.isbn
group by book.pulisher, m.memb_no, m.name
having count(*)>5;
【d题】★★★★☆
考点:with ATE的使用 小数除法的用法
总借出:
with
(select count(*)
from borrowed)
as total_bk
with
(select count(*)
from member)
as total_mem
select total_bk/total_mem as avg_bk
整数除法输出仍然是整数!!!必须CAST AS FLOAT 才行!!!
CTE错误!
【正解】
with total_bk AS(
select count(*) AS cnt from borrowed
),
total_mem AS(
select count(*) AS cnt from book
)
select CAST(b.cnt AS FLOAT)/(m.cnt) AS avg_bk
from total_bk as b, total_mem as m;
更简洁的:
select
CAST(count(br.isbn)AS FLOAT)/(select * from member) AS avg_bk
from borrowed br;