Séparer les résultats SQL en plages
-
03-07-2019 - |
Question
Je voudrais poser une requête simple à une liste de membres indexés par un nombre et les regrouper en "compartiments" de taille égale. La requête de base est donc:
select my_members.member_index from my_members where my_members.active=1;
Disons que je récupère 1 000 numéros d’index membres. Je souhaite maintenant les séparer en 10 groupes de taille égale en fonction des index max et min. Quelque chose comme:
Membres actifs entre 0 et 400: 100 Membres actifs de 401 à 577: 100 ... Membres actifs de 1584 à 1765: 100
Le mieux que je puisse trouver est d'interroger à plusieurs reprises le max (my_members.member_index) avec une limite de nombre croissant de 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;
La solution
NTILE est la voie à suivre - il vaut la peine de lire les fonctions analytiques, car elles peuvent grandement simplifier votre SQL.
Petit commentaire sur le code d'origine - appliquer une restriction rownum avant avant que ORDER BY ne donne des résultats défavorables
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;
boucle de fin;
Essayez ce qui suit:
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;
Pour obtenir le résultat escompté, vous devez le faire
SELECT numval FROM
(SELECT numval FROM example_nums
ORDER BY numval DESC)
WHERE rownum < 5
(Remarque: en coulisse, Oracle traduira ce résultat en un tri efficace ne contenant que les 4 éléments les plus consultés.)
Autres conseils
C’est simple et beaucoup plus rapide avec la fonction analytique NTILE:
SELECT member_index, NTILE(10) OVER (ORDER BY member_index) FROM my_members;
Documentation Oracle 10g: "NTILE est une fonction analytique. Il divise un ensemble de données ordonné en un nombre de compartiments indiqué par expr et attribue le numéro de compartiment approprié à chaque ligne. Les compartiments sont numérotés de 1 à expr. "
Merci pour l'aide. Il a fallu un certain temps pour que tout soit intégré dans une seule déclaration (pour certaines raisons, c'était également un objectif), alors voici ce que j'ai proposé qui ressemble à cela fonctionne pour moi:
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;
Donnez-moi mes résultats comme ceci:
member_index ranger
2297683 1
2307055 2
2325667 3
2334819 4
2343982 5
2353325 6
2362247 7
6229146 8
8189767 9
26347329 10
Examinez l'instruction CASE en SQL et définissez un champ de groupe basé sur les plages souhaitées.