2016-08-11 3 views
0

Мы используем Oracle rownum для запроса двух таблиц t1->t2, которые имеют один ко многим отношений:Oracle ROWNUM на «родительской» таблицы

select * from 
(
select t1.key, t1.a, t2.b 
    from t1, t2 
where t1.key=t2.key and <filter conditions> 
order by t1.a, t2.b 
) 
where rownum <= 500 

Это прекрасно работает в том, что он возвращает первые 500 строк. Но мы хотим вернуть первые 500 строк из t1, а затем все строки t2, которые идут вместе с этим. Каков наилучший способ сделать это?

Мы можем удалить использование rownum sql и на Java просто прочитать первые 500 уникальных значений t1.key из набора результатов (который будет содержать более 500 полных строк в наборе результатов). Но неясно, будет ли это значительно медленнее.

+0

Просьба предоставить соответствующие структуры таблиц, образец данных в обеих таблицах и желаемый результат. –

ответ

4

Я думаю, что вы можете сделать это с помощью dense_rank() аналитической функции:

select * from 
(
select t1.key, t1.a, t2.b, 
     dense_rank() over (order by t1.a, t1.key) as rnk 
    from t1, t2 
where t1.key=t2.key 
    and <filter conditions> 
) 
where rnk <= 500 
order by a, b 

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

EDIT

выше должно работать нормально, если t1.a гарантированно иметь уникальные значения в t1. Если нет, то вы можете обнаружить, что мой запрос не совсем соответствует логике order by вашего исходного запроса. Но я не знаю, есть ли что-нибудь, что я могу сделать.

Проблема заключается в том, что, поскольку вы заказываете на t1.a, t2.b, то в исходном запросе, нет никакой гарантии, что все результаты с теми же t1.key значений будут сгруппированы вместе, что делает неясным, как ваши «первые 500 строк» логика должна работать на основе t1.key.

+0

Может показаться, что было бы более эффективно фильтровать сначала 'rnk <= 500', а только тогда сделать соединение (что, если таблица' t1' имеет 30 миллионов строк?) В некоторых случаях оптимизатор будет подталкивать условия вниз к подзапросам или отдельным таблицам в соединении и т. д., но я не уверен, что это верно для аналитических функций ... ?? – mathguy

+0

@mathguy: На самом деле, в большей степени, чем производительность, чем больше я думаю об этом, тем меньше я уверен, что мой запрос является точным. Я борется с тем, что 'order by' находится на' a, b', тогда как единственным известным уникальным ключом в 't1' является' key'. Я кое-что не делаю. – sstan

+0

Также вы, вероятно, имели в виду 'rank' -' dense_rank' до 500 может возвращать 700 строк. Или, если им не нужны связи, и они хотят 500 строк, «row_number» будет стандартным выбором. – mathguy

0

Не существует понятия «первые 500 строк таблицы», поскольку таблицы представляют неупорядоченный комплектов. Но, если вы имеете в виду t1.a, то это может быть быстрее:

select . . . 
from (select t.* 
     from (select t1.*, 
      from t1 
      where exists (select 1 from t2 where t2.key = t1.key and <conditions>) 
      order by t1.a 
      ) t1 
     where rownum <= 500 
    ) join 
    t2 
    on t1.key = t2.key and <filter conditions> 
order by t1.a, t2.b; 

ли это быстрее, зависит от того, может ли подзапрос использовать индексы. Без условия фильтра будет работать индекс на t1(a, key). Неясно, будет ли это работать с неизвестными условиями.

Смежные вопросы