例如:找出年龄小于20岁的所有储户的身份证编号、姓名、年龄
正确执行:create view test6_00 as select pid,name,age from bk.deptor where age>20
Oracle扩展后方便写法:
create or replace view test6_00 as select pid,name,age from bk.deptor where age>20
1. 在储户表bk.deptor中统计名字(姓名最多3汉字,姓名的第一位是姓氏,其余为名字,不考虑复姓)的使用的频率,仅查询频率大于5的那些名字,将统计结果创建成视图test6_01中,视图如下。
First_name frequency
国强 1034
红 1232
卫东 2323
..................

create view test6_01 as
select cast(substr(pname,2) as varchar2(20)) as first_name,count(*) as frequency
from bk.deptor
gourp by substr(pname,2)
having count(*)>5
sql
create view test6_01 as
select cast(substr(pname,2) as varchar2(20)) as first_name,count(*) as frequency
from bk.deptor
group by substr(pname,2)
having count(*)>5
2. 在储户表bk.deptor中统计名字(姓名最多3汉字,姓名的第一位是姓氏,不作统计,名字指姓名的第二个之后的汉字)的每个字使用的频率,仅查询频率大于10的那些字,将统计结果创建成视图test6_02中,视图如下。
letter frequency
锋 1034
红 1232
鹏 2323
..................
思路·:单独统计两个字的名字和三个字名字的人 理论上可以用case when then
列框架
create view test6_02 as
select letter, count(*) as
from(
A
union
B
)
where
group by
having count(*)>10
处理两个字和三个字的AB情况
create view test6_02 as
select letter, count(*) as
from(
select letter ,count(*) as frequency
from bk.deptor
group by substr(pname,2,1)
union
select letter ,count(*) as frequency
from bk.deptor
group by substr(pname,3,1)
)
group by letter
having count(*)>10
处理代词letter= cast(substr(pname(3,1) as varchar(10))
create view test6_02 as
select letter, sum(frequency) frequency
from(
select cast(substr(pname(2,1) as varchar(10)) as letter ,count(*) as frequency
from bk.deptor
group by substr(pname,2,1)
union all
select cast(substr(pname(3,1) as varchar(10)) as letter ,count(*) as frequency
from bk.deptor
where length(panme)>2
group by substr(pname,3,1)
)
group by letter
having sum(frequency)>10

3. 找出40岁男性且总存款大于60万储户的储户信息(身份证号pid、姓名pname、性别sex、年龄age、出生日期birthdate、父母身份证编号parentpid,select后可以用星号代表所有列,即select *from......)。
两种实现方法,查询速度相差20多秒,思考原因
Select * from bk.deptor where pid in (select pid from bk.deposit group by ......having......) and ......
Select * from bk.deptor t1 where exsits(select * from bk.deposit where ...... group by
...... having ......) and......
create view test6_03 as
select pid,pname,sex,age,birthdate,parentpid
from bk.deptor t1 inner join bk.deposit t2 on t1.pid=t2.pid
where sex='男' and age=40
group by pid
having sum(amount)>600000
select *
from bk.deptor
where pid in (
select pid
from bk.deposit
where sex='男' and age=40
group by pid
haivng sum(amount)>600000
)
select *
from bk.deptor d1
where sex='男' and age=40 and exists(
select pid
from bk.deposit d2
where d1.pid=d2.pid
group by pid
having sum(amount)>600000
)
sql
CREATE VIEW test6_02 AS
SELECT
letter,
SUM(frequency) AS frequency
FROM (
-- 统计名字的第2个字
SELECT
CAST(SUBSTR(pname, 2, 1) AS VARCHAR(10)) AS letter,
COUNT(*) AS frequency
FROM bk.deptor
GROUP BY SUBSTR(pname, 2, 1)
UNION ALL
-- 统计名字的第3个字(需确保名字长度大于2)
SELECT
CAST(SUBSTR(pname, 3, 1) AS VARCHAR(10)) AS letter,
COUNT(*) AS frequency
FROM bk.deptor
WHERE LENGTH(pname) > 2 -- 修正了拼写错误 panme -> pname
GROUP BY SUBSTR(pname, 3, 1)
) AS temp_table -- 派生表必须起一个别名
GROUP BY letter
HAVING SUM(frequency) > 10;
存在的截止条件更松弛,找到就停止

4. 查询在北京的所有银行的合计存款大于50万并且存单数量大于60的年龄>30的女性储户的身份证编号、姓名、性别、年龄、在北京的所有银行的存单数量(列名count_amount)、在北京的所有银行的合计存款(列名sum_amount)。
select pid,pname,sex,age,count(*) as count_amount, sum(amount) as sum_amount
from bk.deptor t1,bk.deposit t2,bk.bank t3
where t1.pid=t2.pid and t2.bid=t3.bid and city='北京' and sex='女' and age>30
group by t1.pid,pname,sex,age
having sum(amount)>500000 and count(*)>60
sql
select
t1.pid, -- 加上 t1. 前缀
t1.pname, -- 加上 t1. 前缀
t1.sex, -- 加上 t1. 前缀
t1.age, -- 加上 t1. 前缀
count(*) as count_amount,
sum(t2.amount) as sum_amount -- 加上 t2. 前缀,养成好习惯
from
bk.deptor t1,
bk.deposit t2,
bk.bank t3
where
t1.pid = t2.pid
and t2.bid = t3.bid
and t3.city = '北京' -- 加上 t3. 前缀,防止 bank 和 deptor 都有 city 字段
and t1.sex = '女' -- 加上 t1. 前缀
and t1.age > 30 -- 加上 t1. 前缀
group by
t1.pid, -- GROUP BY 也要加前缀
t1.pname,
t1.sex,
t1.age
having
sum(t2.amount) > 500000
and count(*) > 60;

5. 查询每个银行的最大存单金额、最大存单笔数,test6_05有四个列:银行编号bid、银行名称bname、最大存单金额max_amount、最大金额的存单笔数max_amount_count。
BID BNAME MAX_AMOUNT MAX_AMOUNT_COUNT
1652 西宁农业银行 100300 4
1752 郑州农业银行 9800 1
............
2052 太原农业银行 100300 2
2152 济南农业银行 9900 2
2252 兰州农业银行 100300 2
思路1,参考讲义关于标量子查询(只返回包含单个属性的单个元组)。
Select cid,name,(select max() from pub.student_course t1 where t1.xx=t0.xx ......)max_score,
(select count(......) from from pub.student_course t1 where t1.xx=t0.xx ......) max_count
From pub.course t0
思路2:
With
tmp1 as (select cid max(course) max_score from pub.student_course group by...... ),--每门课最大成绩
tmp3 as(select cid count(......) max_count from pub.student_course where可以使用tmp1 group by......)--每门课最大成绩人数
Select ...... from pub.couse t1,tmp1,tmp2,tmp3
Where ......
思路3:
Select ...... from pub.couse t1,
(select cid max(course) max_score from pub.student_course group by...... )t2,--每门课最大成绩
(select cid count(......) max_count from pub.student_course group by......)t3,--每门课最大成绩人数
Where
说明:思路1和思路3对比,思路1更加简单,一个子查询就是解决一个值统计。效率会低一些
核心在于两个聚集函数如何获得,一种思路是CTE,单独计算,二表可以引用一表的最大值做in匹配
一种是直接嵌套select,用in匹配
bid来自bank
bname来自bank
amount来自deposit
BID BNAME MAX_AMOUNT MAX_AMOUNT_COUNT
select b.bid,b.bname,(select max(amount) from bk.deposit t1 where t1.bid=b.bid) as max_score,
(select count(*) from bk.deposit where amount in (select max(amount) from bk.deposit t1 where t1.bid=b.bid)) as max_count
from bk.bank b
sql
CREATE OR REPLACE VIEW test6_05 AS
WITH max_amt AS (
-- 第一步:计算每家银行的最大存单金额
SELECT bid, MAX(amount) AS max_amount
FROM bk.deposit
GROUP BY bid
),
max_cnt AS (
-- 第二步:计算最大金额的笔数
-- 通过连接原表和第一步的结果,筛选出等于最大金额的记录
SELECT t1.bid, COUNT(*) AS max_amount_count
FROM bk.deposit t1
JOIN max_amt t2 ON t1.bid = t2.bid
WHERE t1.amount = t2.max_amount
GROUP BY t1.bid
)
-- 第三步:将银行表与上述统计结果连接
SELECT
t3.bid,
t3.bname,
t1.max_amount,
t2.max_amount_count
FROM max_amt t1
JOIN max_cnt t2 ON t1.bid = t2.bid
JOIN bk.bank t3 ON t1.bid = t3.bid;

6. 找出在同一个银行有多于3个大于6000元的存单的所有40岁女性储户的储户信息。
select pid,pname,sex,age,birthdate,parentid
from bk.deptor t1, bk.deposit t2
where t1.pid=t2.pid and sex='女' and age=40 and amount>6000
group by pid,bid
haivng count(*)>3
sql
SELECT
t.pid, t.pname, t.sex, t.age, t.birthdate, t.parentid
FROM
bk.deptor t
WHERE
t.sex = '女'
AND t.age = 40
AND EXISTS (
SELECT 1
FROM bk.deposit d
WHERE d.pid = t.pid
AND d.amount > 6000
GROUP BY d.bid
HAVING COUNT(*) > 3
);

7. 找出在所有银行都有大于200元存单的女性储户的储户信息(身份证编号、姓名、性别、年龄、出生日期,父母身份证号)。这是实验二之10的扩展。
所有->不存在这样的银行,银行中没有她的200元
搭建框架
select
from bk.deptor t1
where not exists(
where not exists(
)
)
填写双层格式
select
from bk.deptor t1 【输出表对象】
wher not exists(
select *
from bk.bank t2【不存在这样的银行】
where in not exists(
select *
from bk.deposit t3【不存在银行记录没有200元】
where
)
)
select *
from bk.deptor t1
where sex='女' and not exists(
select *
from bk.bank t2
where in not exists(
select *
from bk.deposit t3
where t3.bid=t2,bid and t3.pid=t1.pid and amount>200
)
)
sql
SELECT *
FROM bk.deptor t1
WHERE sex = '女'
AND NOT EXISTS (
-- 寻找"是否存在一家银行,使得该女性没有大于200的存单"
SELECT *
FROM bk.bank t2
WHERE NOT EXISTS (
-- 寻找"该女性在该银行是否有大于200的存单"
SELECT *
FROM bk.deposit t3
WHERE t3.bid = t2.bid -- 修正点1:用点号连接
AND t3.pid = t1.pid -- 关联外层储户
AND t3.amount > 200
)
);

8. 找出所有那些不是独生子女(即有兄弟姐妹的)的储户的储户信息。
进一步思考题:1.找出所有双胞胎。2.找出不是独生子女的家长
create view test6_08 as
select distinct pid,pname,sex,age,birthdate,parentid
from bk.deptor t1,bk.deptor t2
where t1.parentid=t2.parentid and t1.pid<>t2.pid
order by parentid
sql
SELECT DISTINCT
t1.pid,
t1.pname,
t1.sex,
t1.age,
t1.birthdate,
t1.parentpid
FROM
bk.deptor t1,
bk.deptor t2
WHERE
t1.parentpid = t2.parentpid
AND t1.pid <> t2.pid
ORDER BY
t1.parentpid;

9. 找出在"北京" 有大于30万元合计存款并且在"西宁"没有存单大于40岁的女性储户的储户信息。
select *
from bk.deptor
where sex='女' and age>40 in (
select pid
from bk.deposit t1,bk.bank t2
where t1,bid=t2.bid and t2.city='北京'
gourp by pid
haivng sum(amount) >300000
and not in(
select pid
from bk.deposit t1, bk.bank t2
where t1.bid=t2.bid and t2.city='西宁'
)
)
sql
SELECT *
FROM bk.deptor
WHERE sex = '女'
AND age > 40
AND pid IN (
-- 修正 1:子查询必须加括号
SELECT t1.pid
FROM bk.deposit t1, bk.bank t2
WHERE t1.bid = t2.bid
AND t2.city = '北京'
GROUP BY t1.pid
HAVING SUM(t1.amount) > 300000
)
AND pid NOT IN (
-- 修正 2:NOT IN 必须放在主查询的 WHERE 中
SELECT t3.pid
FROM bk.deposit t3, bk.bank t4
WHERE t3.bid = t4.bid
AND t4.city = '西宁'
);

10. 储户存款前20名排行榜,排名rank,身份证编号pid,合计存款sum_amount。
select rownum rank,pid,sum_amount
from(
select pid,sum(amount) sum_amount
from bk.deposit
group by pid
order by sum(amount) asc
)
where rownum <=20

sql
SELECT
rownum AS "rank", -- 建议加引号或改名,避免保留字冲突
pid,
sum_amount
FROM (
SELECT
pid,
SUM(amount) AS sum_amount
FROM
bk.deposit
GROUP BY
pid
ORDER BY
SUM(amount) DESC -- ❌ 修正点:必须改为 DESC (从大到小)
)
WHERE
rownum <= 20;