web-dev-qa-db-ja.com

Postgres-ウィンドウ関数のランクとカウント

トラックの周りのアスリートの時間を追跡するいくつかのテーブルがあります。

コンテスト、competition_users、competion_user_sessions

提供された「competition_user」ごとに現在のランクと競合他社の総数を抽出するクエリを作成していますが、ランクは大丈夫ですが、私のカウント(totalUsers)は、競合のすべての競合他社をカウントしていません。提供されたユーザーに(例えば、ランクと同じものを与える)

SELECT compUserId, rank, totalUsers 
    FROM (
        SELECT cu.competition_user_id as compUserId, cu.user_id as userId,  
    count(*) OVER w as totalUsers, rank() OVER w as rank 
        FROM competition_users cu 
        LEFT JOIN current_competition_sessions ccs ON cu.competition_user_id = ccs.competition_user_id 
        LEFT JOIN competition_user_sessions cus ON cus.competition_user_session_id = ccs.competition_user_session_id 
        WHERE cu.left_competition = false 
        AND cu.competition_id in (:compIds)
        WINDOW w AS (PARTITION BY cu.competition_id ORDER BY cus.time_in_seconds ASC) 
    ) as sub 
WHERE compUserId in (:compUserIds)

私の理解では、デフォルトのフレームはウィンドウ全体でしたが、これはフレームの開始から現在の行まで数えているようです?

8
DaveB

問題は、COUNT(*)rank()の両方に同じWINDOWwという名前)を適用していることです。

ORDER BY句を含むWINDOWを使用し、次にSUMCOUNTなどの特定の集計を適用すると、 集計は順序全体で継続的に適用されます 、これがCOUNTrank()が同一である理由です。

クエリを変更する場合、複数のウィンドウ

SELECT compUserId, rank, totalUsers 
FROM (
    SELECT cu.competition_user_id as compUserId, cu.user_id as userId,  
    count(*) OVER (PARTITION BY cu.competition_id) as totalUsers, 
    rank() OVER (PARTITION BY cu.competition_id ORDER BY cus.time_in_seconds ASC) as rank 
    FROM competition_users cu 
    LEFT JOIN current_competition_sessions ccs ON cu.competition_user_id = ccs.competition_user_id 
    LEFT JOIN competition_user_sessions cus ON cus.competition_user_session_id = ccs.competition_user_session_id 
    WHERE cu.left_competition = false 
    AND cu.competition_id in (:compIds)
) as sub 
WHERE compUserId in (:compUserIds);

PARTITION BYCOUNT(*)ウィンドウにのみ適用し、PARTITION BYORDER BYの両方の句をrank()に指定すると、必要な結果が得られると思います。

これを参照として参照してくださいSQL FIDDLE。ここで、汎用のidフィールド、com_numフィールドがあります。競技IDを表すにはcom_timeフィールドを使用して、競技者の時間を表します。

14
Chris