説明の結果、テーブル定義は次のようになります。
CREATE TABLE tbl (
lap_id serial PRIMARY KEY
, lap_no int NOT NULL
, car_type enum NOT NULL
, race_id int NOT NULL -- REFERENCES ...
, UNIQUE(race_id, car_type, lap_no)
);
このクラスの問題の一般的な解決策
最長のシーケンスを取得するには(結果が1つ、最長の場合、同点の場合は任意に選択):
SELECT race_id, car_type, count(*) AS seq_len
FROM (
SELECT *, count(*) FILTER (WHERE step)
OVER (ORDER BY race_id, car_type, lap_no) AS grp
FROM (
SELECT *, (lag(lap_no) OVER (PARTITION BY race_id, car_type ORDER BY lap_no) + 1)
IS DISTINCT FROM lap_no AS step
FROM tbl
) x
) y
GROUP BY race_id, car_type, grp
ORDER BY seq_len DESC
LIMIT 1;
count(*) FILTER (WHERE step)
カウントのみTRUE
(=次のグループへのステップ)。これにより、新しいグループごとに新しい番号が作成されます。
SOに関連する質問、plpgsqlによる手続き型ソリューションを特徴とする1つの答え:
一番の要件がパフォーマンスである場合、この特定のケースでは、plpgsql関数は通常、1回のスキャンで結果を計算できるため高速です。
連続番号の方が速い
連続 lap_no
してシーケンスを定義するという事実を利用して、よりシンプルで高速なバージョンを作成できます。
SELECT race_id, car_type, count(*) AS seq_len
FROM (
SELECT race_id, car_type
, row_number() OVER (PARTITION BY race_id, car_type ORDER BY lap_no) - lap_no AS grp
FROM tbl
) x
GROUP BY race_id, car_type, grp
ORDER BY seq_len DESC
LIMIT 1;
連続したラップは同じ結果になりgrp
ます。ラップが欠落するたびに、grp
パーティションごとに低くなります。
これは存在する(race_id, car_type, lap_no)
ことに依存していUNIQUE NOT NULL
ます。NULL値または重複は、ロジックを破壊する可能性があります。
ジャックのより単純な代替案の議論
@Jackのバージョンは、これの前のものlap_no
がrace_id
同じであったすべてのラップ(行)を効果的にカウントしますcar_type
。それはより簡単で、より速く、正確です-それぞれcar_type
がにつき1 つのシーケンスしか持つことができない限りrace_id
。
しかし、そのような単純なタスクの場合、クエリはさらにシンプルになります。論理的には、lap_no
per (car_type, race_id)
はすべて順番に並んでいる必要があり、ラップを数えるだけです。
SELECT race_id, car_type, count(*) AS seq_len
FROM tbl
GROUP BY race_id, car_type
ORDER BY seq_len DESC
LIMIT 1;
一方、race_idごとに複数の個別のシーケンスを使用car_type
できる場合(および質問では特に指定されていない場合)、Jackのバージョンは失敗します。
特定のレース/車のタイプにより高速
質問のコメント/説明への回答:クエリを指定 (race_id, car_type)
されたものに制限すると、もちろんはるかに速くなります:
SELECT count(*) AS seq_len
FROM (
SELECT row_number() OVER (ORDER BY lap_no) - lap_no AS grp
FROM tbl
WHERE race_id = 1
AND car_type = 'red'
) x
GROUP BY grp
ORDER BY seq_len DESC
LIMIT 1;
db <> fiddle here
古いSQL Fiddle
索引
最高のパフォーマンスの鍵は、フィッティングインデックスです(前述の手順ソリューションを除き、単一の順次スキャンで動作します)。複数列インデックスこのような最高の機能します:
CREATE INDEX tbl_mult_idx ON tbl (race_id, car_type, lap_no);
テーブルにUNIQUE
私が一番上に想定した制約がある場合、それは内部でこの(一意の)インデックスだけで実装され、別のインデックスを作成する必要はありません。