получить nth-самое низкое значение в предложении `group by` - PullRequest
0 голосов
/ 07 сентября 2018

Вот сложный вопрос: у меня есть данные, возвращающиеся во временную таблицу foo в таком виде:

id   n    v
--   -    -
1    3    1
1    3    10
1    3    100
1    3    201
1    3    300
2    1    13
2    1    21
2    1    300
4    2    1
4    2    7
4    2    19
4    2    21
4    2    300
8    1    11

Группируя по id, мне нужно получить строку с n-ным наименьшим значением для v на основе значения в n. Например, для группы с идентификатором 1 мне нужно получить строку, у которой v равен 100, поскольку 100 является третьим наименьшим значением для v.

Вот как должны выглядеть окончательные результаты:

id   n    v
--   -    -
1    3    100
2    1    13
4    2    7
8    1    11

Некоторые примечания о данных:

  • количество строк для каждого идентификатора может варьироваться
  • n всегда будет одинаковым для каждой строки с данным идентификатором
  • n для данного идентификатора никогда не будет больше количества строк с этим идентификатором
  • данные уже будут отсортированы по id, затем v

Бонусные баллы, если вы можете сделать это в универсальном SQL вместо специфических для оракула вещей, но это не является обязательным требованием (я подозреваю, что rownum может иметь большое значение в любых решениях). Это имеет место в моих попытках, но я запутываюсь, прежде чем я получаю рабочее решение.

Ответы [ 3 ]

0 голосов
/ 07 сентября 2018

Я бы использовал функцию row_number, чтобы сравнить номер строки со значением столбца n в CTE, еще один CTE, чтобы упорядочить номер строки по v дес.

get rn = 1, что является максимальным значением в группе чисел n.

CREATE TABLE foo(
   id int,
   n int,
   v int
);


insert into foo values (1,3,1);
insert into foo values (1,3,10);
insert into foo values (1,3,100);
insert into foo values (1,3,201);
insert into foo values (1,3,300);
insert into foo values (2,1,13);
insert into foo values (2,1,21);
insert into foo values (2,1,300);
insert into foo values (4,2,1);
insert into foo values (4,2,7);
insert into foo values (4,2,19);
insert into foo values (4,2,21);
insert into foo values (4,2,300);
insert into foo values (8,1,11);

Запрос 1 :

with cte as(
    select id,n,v 
    from
    (
        select t.*, row_number() over(partition by id ,n order by n) as rn
        from foo t
    ) t1 
    where rn <= n
), maxcte as (
    select id,n,v, row_number() over(partition by id ,n order by v desc) rn 
    from cte 
)
select id,n,v 
from maxcte
where rn = 1

Результаты

| ID | N |   V |
|----|---|-----|
|  1 | 3 | 100 |
|  2 | 1 |  13 |
|  4 | 2 |   7 |
|  8 | 1 |  11 |
0 голосов
/ 07 сентября 2018

Если ваша база данных версии 12.1 или выше, тогда существует гораздо более простое решение:

SELECT DISTINCT ID, n, NTH_VALUE(v,n) OVER (PARTITION BY ID) AS v
FROM foo
ORDER BY ID;


| ID | N |   V |
|----|---|-----|
|  1 | 3 | 100 |
|  2 | 1 |  13 |
|  4 | 2 |   7 |
|  8 | 1 |  11 |

В зависимости от ваших реальных данных вам может потребоваться добавить условие ORDER BY n и / или windowing_clause как RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING, см. NTH_VALUE

0 голосов
/ 07 сентября 2018

использовать оконную функцию

select * from
(
select t.*, row_number() over(partition by id ,n order by v) as rn
from foo  t
 ) t1 
 where t1.rn=t1.n

, поскольку для выходных данных ops просто нужно 3-е наибольшее значение, поэтому я помещаю туда, где условие t1.rn = 3, хотя согласно описанию это будет t1.rn = t1.n

https://dbfiddle.uk/?rdbms=oracle_11.2&fiddle=65abf8d4101d2d1802c1a05ed82c9064

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...