Pregunta

Estoy mirando para conseguir acumulada Frecuencia fuera de datos de nuestra base de datos. He creado una tabla temporal simple, con todas las cuentas de actualización de estado únicos que hemos visto, y el número de usuarios que tienen esa cantidad de actualizaciones de estado.

     Table "pg_temp_4.statuses_count_tmp"
     Column     |  Type   | Modifiers 
----------------+---------+-----------
 statuses_count | integer | 
 frequency      | bigint  | 
Indexes:
    "statuses_count_idx" UNIQUE, btree (statuses_count)

Mi consulta actual es:

select statuses_count, frequency/(select * from total_statuses)::float, (select sum(frequency)/(select * from total_statuses)::float AS percentage from statuses_count_tmp WHERE statuses_count <= SCT.statuses_count) AS cumulative_percent  FROM statuses_count_tmp AS SCT ORDER BY statuses_count DESC;

Pero esto lleva bastante tiempo y el número de consultas crece muy rápidamente. Así que con los ~ 50.000 filas que tengo, estoy mirando 50k filas factoriales para ser leído. Sentado aquí viendo la rutina consulta distancia espero theres una solución mejor que no lo he hecho a través de la todavía.

Con la esperanza de obtener algo como esto:

0       0.26975161      0.26975161
1       0.15306534      0.42281695
2       0.05513516      0.47795211
3       0.03050646      0.50845857
4       0.02064444      0.52910301
¿Fue útil?

Solución

En caso de ser solucionable con funciones de ventanas, suponiendo que tiene PostgreSQL 8.4 o posterior. Supongo que total_statuses es una vista o tabla temporal en la línea de select sum(frequency) from statuses_count_tmp? Lo escribí como un CTE aquí que debe hacer a calcular el resultado sólo una vez durante la duración de la declaración:

with total_statuses as (select sum(frequency) from statuses_count_tmp)
select statuses_count,
       frequency / (select * from total_statuses) as frequency,
       sum(frequency) over(order by statuses_count)
           / (select * from total_statuses) as cumulative_frequency
from statuses_count_tmp

Sin funciones de la ventana de 8.4 lo mejor es simplemente para procesar los datos de forma iterativa:

create type cumulative_sum_type as ( statuses_count int, frequency numeric, cumulative_frequency numeric );
create or replace function cumulative_sum() returns setof cumulative_sum_type strict stable language plpgsql as $$
declare
  running_total bigint := 0;
  total bigint;
  data_in record;
  data_out cumulative_sum_type;
begin
  select sum(frequency) into total from statuses_count_tmp;
  for data_in in select statuses_count, frequency from statuses_count_tmp order by statuses_count
  loop
    data_out.statuses_count := data_in.statuses_count;
    running_total := running_total + data_in.frequency;
    data_out.frequency = data_in.frequency::numeric / total;
    data_out.cumulative_frequency = running_total::numeric / total;
    return next data_out;
  end loop;
end;
$$;
select * from cumulative_sum();
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top