数据库作战记录6 实验6

例如:找出年龄小于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;
相关推荐
AC赳赳老秦2 小时前
DBA 专属方案:用 OpenClaw 实现 SQL 语句优化、慢查询分析、数据库备份巡检全自动化
服务器·前端·数据库·ffmpeg·自动化·deepseek·openclaw
学术阿凡提2 小时前
Spring Boot 优雅实现异步调用:从入门到自定义线程池与异常处理
java·数据库·算法
夏末蝉未鸣012 小时前
跨境电商SQL Server报表生成优化:索引一改,600秒变75秒
数据库
hhb_6182 小时前
SQL高性能查询优化与复杂场景实战指南
服务器·数据库·sql
2301_773553622 小时前
Redis怎样优化复制缓冲池大小_调大repl-backlog-size减少频繁的全量同步触发
jvm·数据库·python
wangyangyangcumt2 小时前
银河麒麟V10 SP3离线安装Nginx1.21.5全记录
linux·运维·数据库
tongyiixiaohuang2 小时前
基于轻易云的数据集成,实现企业系统间灵活对接
java·前端·数据库
weixin_381288182 小时前
HTML lang 属性的正确取值规范:BCP 47 格式详解与最佳实践
jvm·数据库·python
阿丰资源2 小时前
基于SpringBoot智能化体育馆管理系统(附源码+文档+数据库,一键运行)
数据库·spring boot·后端