Разделение результатов SQL на диапазоны
-
03-07-2019 - |
Вопрос
Я хотел бы взять простой запрос по списку членов, которые проиндексированы числом, и сгруппировать их в «корзины» одинакового размера. Итак, базовый запрос:
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 и установите поле группы на основе желаемых диапазонов.