2

次のようなスキーマを持つ運動会の結果のデータベースがあるとします。

DATE,NAME,FINISH_POS

アスリートが少なくとも 3 つのイベントで優勝せずに出場したすべての行を選択するクエリを実行したいと考えています。たとえば、次のサンプル データの場合

2013-06-22,Johnson,2
2013-06-21,Johnson,1
2013-06-20,Johnson,4
2013-06-19,Johnson,2
2013-06-18,Johnson,3
2013-06-17,Johnson,4
2013-06-16,Johnson,3
2013-06-15,Johnson,1

次の行:

2013-06-20,Johnson,4
2013-06-19,Johnson,2

一致します。私は次のスタブでのみ開始することができました:

select date,name FROM table WHERE ...;

where句について頭を悩ませようとしてきましたが、始めることさえできません

4

3 に答える 3

4

これはさらに簡単/高速になると思います:

SELECT day, place, athlete
FROM  (
   SELECT *, min(place) OVER (PARTITION BY athlete
                              ORDER BY day
                              ROWS 3 PRECEDING) AS best
   FROM   t
   ) sub
WHERE  best > 1

->SQLfiddle

集計関数min()をウィンドウ関数として使用して、最後の 3 行と現在の行の最小の場所を取得します。ウィンドウ関数は句のに適用される
ため、「勝てない」( ) の簡単なチェックは次のクエリ レベルで実行する必要があります。したがって、ウィンドウ関数の結果に対する条件には、サブセレクトのCTEが少なくとも 1 つ必要です。best > 1WHERE

ウィンドウ関数呼び出しの詳細については、こちらのマニュアルを参照してください。特に:

frame_endを省略すると、デフォルトで になりますCURRENT ROW

place( finishing_pos) が NULL になる可能性がある場合は、代わりにこれを使用します。

WHERE  best IS DISTINCT FROM 1

min()は値を無視しNULLますが、フレーム内のすべての行が である場合NULL、結果はNULLです。

型名と予約語を識別子として使用しないdayでくださいdate

これは、1 日に最大 1 つの競技を想定していtimestampますdate

@Craigは、これを高速化するためのインデックスについてすでに言及しています。

于 2013-06-22T12:44:52.403 に答える
1
; with  CTE as
        (
        select  row_number() over (partition by athlete order by date) rn
        ,       *
        from    Table1
        )
select  *
from    CTE cur
where   not exists
        (
        select  *
        from    CTE prev
        where   prev.place = 1
                and prev.athlete = cur.athlete
                and prev.rn between cur.rn - 3 and cur.rn
        )

SQL Fiddle での実例。

于 2013-06-22T05:54:48.747 に答える