次の表があります。
CREATE TABLE trans (
id SERIAL PRIMARY KEY,
trans_date date,
trans_time time
);
次のような見方をしたい
CREATE OR REPLACE VIEW daily_trans AS
SELECT trans_date,
max(trans_time) as first,
min(trans_time) as last,
calculate_status(min(trans_time), max(trans_time)) as status
GROUP BY trans_date
maxおよびmin trans_timeのIDを指定する列があります。
それ、どうやったら出来るの?
あなたはできますウィンドウ関数 で1ステップでこれを計算します:
CREATE OR REPLACE VIEW daily_trans AS
SELECT DISTINCT
trans_date
, first_value(trans_time) OVER w AS first_time
, first_value(id) OVER w AS first_id
, last_value(trans_time) OVER w AS last_time
, last_value(id) OVER w AS last_id
, calculate_status(min(trans_time) OVER w
, max(trans_time) OVER w) AS status
FROM trans
WINDOW w AS (PARTITION BY trans_date ORDER BY trans_time, id
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
ORDER BY 1;
id
をセカンダリORDER
列としてwindow句に追加して、1日の時間が同じ場合でもソート順を安定させるようにしました。
ウィンドウ関数に慣れていない場合は、必ずこの マニュアルの章 をお読みください。
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
は、last_value()
が常に現在までの最後の値ではなく、パーティション全体の最後の値(日付)を返すようにするため、ウィンドウフレームを調整するためにあまり使用されない句です。 (ピアを含む)ソート順に従って。
DISTINCT
とウィンドウ関数を組み合わせる方法:
大まかに、あなたは
select min_trans_time, min_trans.id as min_trans_time_id,
max_trans_time, max_trans.id as max_trans_time_id
from (
select trans_date,
max(trans_time) as max_trans_time,
min(trans_time) as min_trans_time,
from trans
group by trans_date) min_max_trans,
trans as min_trans,
trans as max_trans
where min_trans.trans_time = min_max_trans.min_trans_time
and max_trans.trans_time = min_max_trans.max_trans_time
複数のtrans
esが同じtrans_time
を共有している場合、安定しない可能性があります(つまり、同じデータセットでクエリを実行すると、異なる結果が生じる可能性があります。これを解決する簡単な方法の1つは、たとえば、最大または最小IDを選択することです。もちろん、これにより結果にバイアスがかかる可能性があります:).
PostgreSQL 8.4以降を使用している場合は、ウィンドウ関数も使用できます。それらはより明確なクエリを提供し(ウィンドウ関数に慣れている場合は明確です:)、上記の戦略で実行するのがかなり難しいことを可能にします(たとえば、最大値ではなく2番目に高い値を取得します)。ただし、私の短い経験では、ここで提案する自己結合アプローチよりもパフォーマンスが劣っていました。アーウィンの回答には、ウィンドウ関数を使用したクエリのバージョンが含まれています。どのクエリがより適切に実行されるか、および/または(インデックスを追加するなどして)より適切に最適化できるかに注目すると興味深いでしょう。