Вопрос

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

select my_members.member_index from my_members where my_members.active=1;

Скажем, я получил 1000 номеров индексов, теперь я хочу разделить их на 10 групп одинакового размера по индексу max и min членов. Что-то вроде:

Активные участники от 0 до 400: 100  Активные участники с 401 по 577: 100  ...  Активные участники с 1584 по 1765 год: 100

Лучшее, что я мог придумать, - это неоднократно запрашивать max (my_members.member_index) с увеличивающимся пределом rownum:

  for r in 1 .. 10 loop
  select max(my_members.member_index)
  into ranges(r)
  from my_members
   where  my_members.active = 1
   and rownum < top_row
   order by my_members.member_index asc;
   top_row    := top_row + 100;
  end loop;
Это было полезно?

Решение

NTILE - это путь, который стоит прочитать о аналитических функциях, поскольку они могут значительно упростить ваш SQL.

Небольшой комментарий к исходному коду - ограничение перед ограничением rownum может привести к неблагоприятным результатам

for r in 1 .. 10 loop
   select max(my_members.member_index)
   into ranges(r)
   from my_members
   where  my_members.active = 1
   and rownum < top_row
   order by my_members.member_index asc;
   top_row    := top_row + 100;

конец цикла;

Попробуйте сделать следующее:

create table example_nums (numval number)

begin
    for i in 1..100 loop
        insert into example_nums values (i);
   end loop;
end;

SELECT numval FROM example_nums 
WHERE rownum < 5 
ORDER BY numval DESC;

Чтобы получить ожидаемый результат, вам нужно сделать

SELECT numval FROM
   (SELECT numval FROM example_nums 
   ORDER BY numval DESC)
WHERE rownum < 5 

(Примечание: за кадром Oracle преобразует это в эффективную сортировку, которая когда-либо содержит только «4 верхних элемента»).

Другие советы

Это просто и намного быстрее, используя аналитическую функцию NTILE:

SELECT member_index, NTILE(10) OVER (ORDER BY member_index) FROM my_members;

Документация по Oracle 10g: " NTILE - это аналитическая функция. Он делит упорядоченный набор данных на количество сегментов, указанных выражением expr, и присваивает соответствующий номер сегмента каждой строке. Контейнеры пронумерованы от 1 до expr. & Quot;

Спасибо за помощь. Потребовалось некоторое время, чтобы объединить все в одно утверждение (по определенным причинам, что также было целью), поэтому вот что я придумала, похоже, это работает для меня:

select max(member_index), ranger
  from (SELECT member_index,
                    CASE
                        WHEN rownum < sized THEN 1
                        WHEN rownum < sized*2 THEN 2
                        WHEN rownum < sized*3 THEN 3
                        WHEN rownum < sized*4 THEN 4
                        WHEN rownum < sized*5 THEN 5
                        WHEN rownum < sized*6 THEN 6
                        WHEN rownum < sized*7 THEN 7
                        WHEN rownum < sized*8 THEN 8
                        WHEN rownum < sized*9 THEN 9
                        ELSE 10
                     END ranger
             from my_members,
                    (select count(*) / 10 sized
                        from my_members
                      where active = 1)
            where active = 1
            order by member_index)
 group by ranger;

Дайте мне мои результаты, как это:

member_index    ranger
2297683     1
2307055     2
2325667     3
2334819     4
2343982     5
2353325     6
2362247     7
6229146     8
8189767     9
26347329        10

Взгляните на оператор CASE в SQL и установите поле группы на основе желаемых диапазонов.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top