Domanda

Vorrei prendere una semplice query su un elenco di membri che sono indicizzati da un numero e raggrupparli in "secchi" di uguale dimensione. Quindi la query di base è:

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

Supponi di recuperare 1000 numeri indice dei membri, ora voglio dividerli in 10 gruppi di dimensioni uguali per un indice membro massimo e minimo. Qualcosa del tipo:

Membri attivi da 0 a 400: 100  Membri attivi da 401 a 577: 100  ...  Membri attivi dal 1584 al 1765: 100

Il meglio che ho potuto trovare è quello di interrogare ripetutamente il massimo (my_members.member_index) con un limite di rownum crescente:

  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;
È stato utile?

Soluzione

NTILE è la strada da percorrere: vale la pena leggere le funzioni analitiche in quanto possono semplificare enormemente il tuo SQL.

Piccolo commento sul codice originale: fare una restrizione di rownum prima un ORDER BY può produrre risultati negativi

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;

Prova quanto segue:

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;

Per ottenere il risultato che ti aspetti di dover fare

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

(Nota: dietro le quinte, Oracle lo tradurrà in un ordinamento efficiente che contiene sempre e solo i "primi 4 elementi").

Altri suggerimenti

È semplice e molto più veloce usando la funzione analitica NTILE:

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

Documentazione Oracle 10g: " NTILE è una funzione analitica. Divide un set di dati ordinato in un numero di bucket indicato da EXPR e assegna il numero di bucket appropriato a ciascuna riga. I bucket sono numerati da 1 a espresso "

Grazie per l'aiuto. Ci è voluto un po 'di tempo per elaborare tutto in una frase (per alcuni motivi che era anche un obiettivo), quindi ecco cosa mi è venuto in mente che sembra funzionare per me:

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;

Dammi i miei risultati in questo modo:

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

Dai un'occhiata all'istruzione CASE in SQL e imposta un campo di gruppo basato sugli intervalli desiderati.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top