web-dev-qa-db-ja.com

最大および最小の日付と行ごとの関連するIDを含むPostgreSQLクエリ

次の表があります。

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を指定する列があります。

それ、どうやったら出来るの?

7
Random Joe

あなたはできますウィンドウ関数 で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とウィンドウ関数を組み合わせる方法:

10

大まかに、あなたは

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

複数のtransesが同じtrans_timeを共有している場合、安定しない可能性があります(つまり、同じデータセットでクエリを実行すると、異なる結果が生じる可能性があります。これを解決する簡単な方法の1つは、たとえば、最大または最小IDを選択することです。もちろん、これにより結果にバイアスがかかる可能性があります:).

PostgreSQL 8.4以降を使用している場合は、ウィンドウ関数も使用できます。それらはより明確なクエリを提供し(ウィンドウ関数に慣れている場合は明確です:)、上記の戦略で実行するのがかなり難しいことを可能にします(たとえば、最大値ではなく2番目に高い値を取得します)。ただし、私の短い経験では、ここで提案する自己結合アプローチよりもパフォーマンスが劣っていました。アーウィンの回答には、ウィンドウ関数を使用したクエリのバージョンが含まれています。どのクエリがより適切に実行されるか、および/または(インデックスを追加するなどして)より適切に最適化できるかに注目すると興味深いでしょう。

4
alex