我在Oracle 12c中有一个类似于:
的表CREATE TABLE test (
id INT PRIMARY KEY,
foo VARCHAR2(20),
seconds int,
system_dt DATE
);
使用一组数据,如
ABC, 10, 2016-01-01 00:00:01
ABC, 11, 2016-01-01 00:00:02
ABC, 5, 2016-01-01 00:35:54
ABC, 6, 2016-01-01 00:41:01
DEF, 15, 2016-01-01 00:00:02
DEF, 14, 2016-01-01 00:01:03
DEF, 51, 2016-01-01 00:36:55
DEF, 1, 2016-01-01 00:42:02
(值得注意的是id
,system_dt
(显然rownum
)不会以任何一致的值递增)
我想要做的是按foo, system_dt
对此表格进行排序,然后在每N行中找到MAX(seconds)
,按foo
分组。
所以在上面的例子中,N是2,输出将是:
ABC, 11, 2015-01-01 00:00:02
ABC, 6, 2016-01-01 00:41:01
DEF, 15, 2016-01-01 00:00:02
DEF, 51, 2016-01-01 00:36:55
我考虑过使用rownum,但rownum增量在以下查询中并不一致:
SELECT foo, rownum, seconds, system_dt FROM test ORDER BY foo, system_dt ----- ABC, 3, 20 ABC, 134 25 ABC, 137, 18 ABC, 5086, 15 ABC, 5098, 16
答案 0 :(得分:1)
您可以使用rownum
或row_number()
:
select foo, max(seconds),
max(system_dt) keep (dense_rank first order by seconds desc) as system_dt
from (select t.*,
row_number() over (partition by foo order by system_dt) - 1 as seqnum
from test t
) t
group by foo, trunc(seqnum / 2);
答案 1 :(得分:0)
以下是使用MATCH_RECOGNIZE(仅限Oracle 12.1以来可用)按固定行数进行分组的解决方案。不幸的是,至少在12.1(我使用的版本)中,MATCH_RECOGNIZE尚不支持聚合函数FIRST / LAST;如果是的话,一切都可以在match_recognize中完成,并且不需要GROUP BY。
with
test ( foo, seconds, system_dt ) as (
select 'ABC', 10, to_date('2016-01-01 00:00:01', 'yyyy-mm-dd hh24:mi:ss') from dual union all
select 'ABC', 11, to_date('2016-01-01 00:00:02', 'yyyy-mm-dd hh24:mi:ss') from dual union all
select 'ABC', 5, to_date('2016-01-01 00:35:54', 'yyyy-mm-dd hh24:mi:ss') from dual union all
select 'ABC', 6, to_date('2016-01-01 00:41:01', 'yyyy-mm-dd hh24:mi:ss') from dual union all
select 'DEF', 15, to_date('2016-01-01 00:00:02', 'yyyy-mm-dd hh24:mi:ss') from dual union all
select 'DEF', 14, to_date('2016-01-01 00:01:03', 'yyyy-mm-dd hh24:mi:ss') from dual union all
select 'DEF', 51, to_date('2016-01-01 00:36:55', 'yyyy-mm-dd hh24:mi:ss') from dual union all
select 'DEF', 1, to_date('2016-01-01 00:42:02', 'yyyy-mm-dd hh24:mi:ss') from dual
)
-- end of test data (not part of the SQL query); query begins BELOW THIS LINE
select foo, max(seconds) as seconds,
max(system_dt) keep (dense_rank last order by seconds) as system_dt
from test
match_recognize (
partition by foo
order by system_dt
measures match_number() as mn
all rows per match
pattern ( a{2} | a+ $ )
define a as 0 = 0
)
group by foo, mn
;
FOO SECONDS SYSTEM_DT
--- ------- -------------------
ABC 11 01/01/2016 00:00:02
ABC 6 01/01/2016 00:41:01
DEF 15 01/01/2016 00:00:02
DEF 51 01/01/2016 00:36:55