PL/SQL Challenge 每周一题:2022-9-10 first_value函数

[复制链接]
查看11 | 回复3 | 2008-9-15 01:28:12 | 显示全部楼层 |阅读模式
**答对且答案未经编辑的puber将获得纪念章一枚(答案不可编辑但可发新贴补充或纠正),其他会员如果提供有价值的分析、讨论也可获得纪念章一枚。
每两周的优胜者可获得itpub奖励的技术图书一本。
以往旧题索引:
http://www.itpub.net/forum.php?m ... eid&typeid=1808
原始出处:
https://devgym.oracle.com/
作者:Kim Berg Hansen
运行环境:SQLPLUS, SERVEROUTPUT已打开, **版本要求:12.1
注:本题给出答案时候要求给予简要说明才能得到奖品
我有一张表,存储着每个国家每年的销售统计:
create table qz_stats (
country varchar2(2)
, yearinteger
, amountinteger not null
, primary key (country, year)
);
insert into qz_stats values ('US', 2019, 11000);
insert into qz_stats values ('US', 2020, 15000);
insert into qz_stats values ('US', 2021, 13000);
insert into qz_stats values ('DK', 2019, 12000);
insert into qz_stats values ('DK', 2020,9000);
insert into qz_stats values ('DK', 2021, 11000);
insert into qz_stats values ('NL', 2019,8000);
insert into qz_stats values ('NL', 2020, 11000);
insert into qz_stats values ('NL', 2021, 14000);
commit;
我想要以如下的顺序来输出这张表的数据:
国家必须以它们首年的销售额的降序来排序。
如果国家之间有平局,则平局的国家以字母顺序排序。
在每个国家中,数据行以年份排序。
哪些选项包含了一个查询,可以执行不出错并且产生这个所需的输出:
CO YEAR AMOUNT
-- ---------- ----------
DK 201912000
DK 2020 9000
DK 202111000
US 201911000
US 202015000
US 202113000
NL 2019 8000
NL 202011000
NL 202114000

(A)
select
country, year, amount
from qz_stats
order by
first_value(amount) over (partition by country order by year) desc
, country
, year;
(B)
select
country, year, amount
from (
select
country, year, amount
, first_value(amount) over (partition by country order by year) as first_year_amount
from qz_stats
)
order by
first_year_amount desc
, country
, year;
(C)
select
country, year, amount
, first_value(amount) over (partition by country order by year) as first_year_amount
from qz_stats
order by
first_year_amount desc
, country
, year;
(D)
select
country, year, amount
from qz_stats
order by
(
select amount
from qz_stats stats2
where stats2.country = qz_stats.country
order by year
fetch first 1 row only
) desc
, country
, year;
(E)
select
qz_stats.country, qz_stats.year, qz_stats.amount
from qz_stats
join (
select
country
, max(amount) keep (dense_rank first order by year) as first_year_amount
from qz_stats
group by country
) stats2
on stats2.country = qz_stats.country
order by
stats2.first_year_amount desc
, qz_stats.country
, qz_stats.year;


回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
ABCDE
ABC方法一样,但是C多输出了一列。
A:sql 执行顺序
1.先执行from,join 确定表之间的连接关系,得到初步数据。
2.where 对数据进行普通的初步筛选。
3.group by 分组。
4.各组分别执行having 中的普通筛选或者聚合筛选。
5.select 查询出来 可以是普通字段也可以是聚合函数处理后的字段。
6.distinct 将查询结果去重
7.orderby 对结果进行排序
8.fetch first / nextN row(s) only取前N行
所以A答案中 order by 后边直接跟了 first_value窗口函数。

B:用first_value窗口函数写了个子查询
C:同A就是多输出了一列数据
D:试过了也可以,原来标量子查询能跟在orderby后边。
E: 先用keep (dense_rank first order by year) 找出每个国家第一年的amount重命名为first_year_amount 然后用国家关联回原表并参照 first_year_amount作为排序依据。
另外需要请教苏神个问题:
SELECT e.empno,e.ename,e.sal,e.deptno
,FIRST_VALUE(E.SAL) OVER (PARTITION BY E.DEPTNO ORDER BY E.SAL) FIRST_VAL1
,FIRST_VALUE(E.SAL) OVER (PARTITION BY E.DEPTNO) FIRST_VAL2
,LAST_VALUE(E.SAL) OVER (PARTITION BY E.DEPTNOORDER BY E.SAL) LAST_VAL1
,LAST_VALUE(E.SAL) OVER (PARTITION BY E.DEPTNO)LAST_VAL2
,NTH_VALUE(E.SAL,1)OVER (PARTITION BY E.DEPTNO ORDER BY E.SAL) NTH_VAL1
,NTH_VALUE(E.SAL,1)OVER (PARTITION BY E.DEPTNO) NTH_VAL2
FROM EMP E ;
这段里的last_val1和last_val2 结果不一样,发现容易在这个地方迷失自我。

回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
答案ABDE, 2楼得奖。(C只是输出不同,这不是重点)
A:
分析函数在执行查询的操作中执行得很晚——例如,它们在 WHERE、GROUP BY 和 HAVING 之后运行。但它们在 ORDER BY 之前运行,因此我们可以直接在 ORDER BY 子句中使用分析函数。
B:
很常见的是,我们需要在内联视图中计算分析函数的结果,因此我们可以在外部查询中使用这个结果。如果我们想在例如 WHERE 子句中使用结果,则需要像本选项这样做。
正如我们在前一选项中看到的,当我们在 ORDER BY 子句中使用分析函数结果时,这并不是真正需要的,它当然也可以正常工作,即使不是严格要求。
C:
正如我们在选项 A 中看到的,分析函数在 ORDER BY 之前执行,因此也允许为结果提供列别名并在 ORDER BY 中使用别名。此查询将正常工作并根据需要对行进行排序 ---- 但是问题中所要求的输出不应该包含 FIRST_YEAR_AMOUNT 列,因此在这个问题的上下文中,这是一个错误的答案,会产生这个错误的输出:
CO YEAR AMOUNT FIRST_YEAR_AMOUNT
-- ---------- ---------- -----------------
DK 201912000
12000
DK 2020 9000
12000
DK 202111000
12000
US 201911000
11000
US 202015000
11000
US 202113000
11000
NL 2019 8000
8000
NL 202011000
8000
NL 202114000
8000
如果你不需要担心多余的额外列(例如,你可以忽略客户端代码中的列),这可能是一种合理的方法。

D:
除了使用分析函数,我们当然可以通过在 ORDER BY 中使用标量子查询而不是分析函数 FIRST_VALUE 来模拟A选项。但是,这将需要多次访问数据并且性能更差,因此不推荐。
E:
除了前一选项中的标量子查询,我们还可以创建一个内联视图,使用 GROUP BY 计算每个国家/地区的 FIRST_YEAR_AMOUNT,然后我们可以将其与 QZ_STATS 表连接以获得所需的结果。但是我们仍然需要访问该表两次,所以这不是推荐的选择。
回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
谢谢苏老师
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

主题

0

回帖

4882万

积分

论坛元老

Rank: 8Rank: 8

积分
48824836
热门排行