Bru*_*oLM 67 oracle greatest-n-per-group
我有一张这样的表:
ID | Val | Kind
----------------------
1 | 1337 | 2
2 | 1337 | 1
3 | 3 | 4
4 | 3 | 4
Run Code Online (Sandbox Code Playgroud)
我想制作一个SELECT只返回每个 的第一行,按Val排序Kind。
示例输出:
ID | Val | Kind
----------------------
2 | 1337 | 1
3 | 3 | 4
Run Code Online (Sandbox Code Playgroud)
如何构建此查询?
bil*_*nkc 73
使用公共表表达式(CTE) 和窗口/排名/分区函数,如ROW_NUMBER。
这个查询将创建一个名为 ORDERED 的内存表,并添加一个额外的 rn 列,它是一个从 1 到 N 的数字序列。PARTITION BY表示每次 Val 的值改变时它应该从 1重新开始,我们想要排序按 Kind 的最小值排列。
WITH ORDERED AS
(
SELECT
ID
, Val
, kind
, ROW_NUMBER() OVER (PARTITION BY Val ORDER BY Kind ASC) AS rn
FROM
mytable
)
SELECT
ID
, Val
, Kind
FROM
ORDERED
WHERE
rn = 1;
Run Code Online (Sandbox Code Playgroud)
上述方法应该适用于任何已实现 ROW_NUMBER() 函数的 RDBMS。如mik 的回答所示,Oracle 具有一些优雅的功能,通常会产生比此答案更好的性能。
小智 46
该解决方案还使用了keep,但val并kind也可以简单地计算出每个组没有子查询:
Run Code Online (Sandbox Code Playgroud)select min(id) keep(dense_rank first order by kind) id , val , min(kind) kind from mytable group by val;身份证 | 价值 | 种类 -: | ---: | ---: 3 | 3 | 4 2 | 第1337章 1
dbfiddle在这里
KEEP...FIRST 和 KEEP...LAST 是特定于 Oracle 的聚合特性——您可以在此处的 Oracle 文档或ORACLE_BASE 上阅读:
FIRST 和 LAST 函数可用于返回有序序列的第一个或最后一个值
Lei*_*fel 27
bilinkc 的解决方案工作正常,但我想我也会扔掉我的。它具有相同的成本,但可能更快(或更慢,我还没有测试过)。不同之处在于它使用 First_Value 而不是 Row_Number。因为我们只对第一个值感兴趣,所以在我看来它更直接。
SELECT ID, Val, Kind FROM
(
SELECT First_Value(ID) OVER (PARTITION BY Val ORDER BY Kind) First, ID, Val, Kind
FROM mytable
)
WHERE ID = First;
Run Code Online (Sandbox Code Playgroud)
测试数据。
--drop table mytable;
create table mytable (ID Number(5) Primary Key, Val Number(5), Kind Number(5));
insert into mytable values (1,1337,2);
insert into mytable values (2,1337,1);
insert into mytable values (3,3,4);
insert into mytable values (4,3,4);
Run Code Online (Sandbox Code Playgroud)
如果您愿意,这里是 CTE 等效项。
WITH FirstIDentified AS (
SELECT First_Value(ID) OVER (PARTITION BY Val ORDER BY Kind) First, ID, Val, Kind
FROM mytable
)
SELECT ID, Val, Kind FROM FirstIdentified
WHERE ID = First;
Run Code Online (Sandbox Code Playgroud)
Jac*_*las 17
您可以使用从每个组中keep选择一个id:
Run Code Online (Sandbox Code Playgroud)select * from mytable where id in ( select min(id) keep (dense_rank first order by kind, id) from mytable group by val );身份证 | 价值 | 种类 -: | ---: | ---: 2 | 第1337章 1 3 | 3 | 4
dbfiddle在这里