Аналитические функции для «атрибута из строки с максимальной датой» - PullRequest
1 голос
/ 27 апреля 2010

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

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

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

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, которая делает это?

Ответы [ 4 ]

2 голосов
/ 27 апреля 2010

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

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;
1 голос
/ 27 апреля 2010

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

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;
1 голос
/ 27 апреля 2010

Есть аналитика 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';

Поскольку аналитика работает с выбранными строками, вам все еще нужен подзапрос / встроенное представление, чтобы отфильтровать те, которые вам не нужны. В этом примере INDEX_NAME является общим идентификатором

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;
0 голосов
/ 27 апреля 2010

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

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
...