2010-04-27 3 views
1

Я рефакторинг кода сотрудника, и у меня есть несколько случаев, когда он использует курсор, чтобы получить «последнюю строку, которая соответствует некоторый предикат»:Аналитические функции для «атрибута из строки с максимальной датой»

Его метод состоит в том, чтобы написать объединение как курсор, заказать его по дате, по убыванию, открыть курсор, получить первую строку и закрыть курсор.

Для этого требуется вызывать курсор для каждой строки набора результатов, который управляет этим, что дорого для многих строк. Я бы предпочел, чтобы иметь возможность присоединиться, но что-то дешевле, чем коррелированные подзапросы:

select a.id_shared_by_several_rows, a.foo from audit_trail a 
where a.entry_date = (select max(a.entry_date) 
        from audit_trail b 
        where b.id_shared_by_several_rows = a.id_shared_by_several_rows 
        ); 

Я предполагаю, что, поскольку это общая потребность, есть аналитическая функция Oracle, что делает это?

ответ

1

Имеются аналитики RANK, DENSE_RANK и ROW_NUMBER для идентификации порядкового номера строки в соответствии с критериями сортировки. Они отличаются тем, как они обрабатывают строки, которые не отличаются в столбцах заказа. [Например, вы можете получить 1,1,3 или 1,1,2 или 1,2,3.]

select index_name, column_name, column_position, 
     rank() over (partition by table_name order by column_position) rnk, 
     dense_rank() over (partition by table_name order by column_position) drnk, 
     row_number() over (partition by table_name order by column_position) rn 
from all_ind_columns 
where index_owner = 'SYSMAN' 
and table_name = 'MGMT_JOB_EXECUTION'; 

Поскольку аналитики работают на выбранных строках, вы по-прежнему нужен вид подзапрос/инлайн отфильтровывать те, которые вы не хотите. В этом примере, ИМЯ_ИНДЕКС является общим идентификатором

select index_name, column_name 
from 
    (select index_name, column_name, column_position, 
     row_number() over (partition by index_name order by column_position) rn 
    from all_ind_columns 
    where index_owner = 'SYSMAN' 
    and table_name = 'MGMT_JOB_EXECUTION') 
where rn = 1; 
2

Это будет делать только один проход над данными, и может быть использован, чтобы получить стольких столбцов из таблицы по мере необходимости, не делая автообъединение.

select DISTINCT 
     a.id_shared_by_several_rows, 
     FIRST_VALUE(a.foo) 
     OVER (PARTITION BY a.id_shared_by_several_rows 
      ORDER BY a.entry_date DESC) 
     AS foo 
from audit_trail a; 
0

Попробуйте это:

select id_shared_by_several_rows, foo from (
select a.id_shared_by_several_rows, a.foo, a.entry_date, max(a.entry_date) over (partition by a.id_shared_by_several_rows) max_entry_date 
from audit_trail_a 
) where entry_date = max_entry_date 
1

Я считаю, что вы хотите использовать

select 
    max(id_shared_by_several_rows) keep (dense_rank first order by entry_date), 
    max(foo      ) keep (dense_rank first order by entry_date) 
from 
    audit_trail;