1

データベースから累積頻度データを取得しようとしています。私たちが確認したすべての一意のステータス更新カウントと、その量のステータス更新を持つユーザーの数を含む単純な一時テーブルを作成しました。

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

私の現在のクエリは次のとおりです。

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;

しかし、これにはかなりの時間がかかり、クエリの数は急速に増加します。したがって、私が持っている〜50,000行で、50,000の階乗行を読み取る必要があります。ここに座ってクエリがすり減るのを見ながら、まだ解決していないより良い解決策があることを願っています。

このようなものを得ることを望んで:

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
4

1 に答える 1

2

PostgreSQL 8.4以降を使用している場合は、ウィンドウ関数で解決できるはずです。私はそれが?total_statusesの線に沿ったビューまたは一時テーブルであると推測しています。select sum(frequency) from statuses_count_tmpここにCTEとして記述しました。これにより、ステートメントの期間中、結果が1回だけ計算されるようになります。

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

8.4のウィンドウ関数がない場合、最善の策は単にデータを繰り返し処理することです。

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();
于 2011-01-12T20:23:06.820 に答える