sql >> データベース >  >> RDS >> PostgreSQL

条件付きリード/ラグ関数PostgreSQL?

    あなたの定義:

    グループBのアクティビティは、常にグループAのアクティビティの後に行われます。

    ..論理的には、ユーザーごとに、1つ以上のAアクティビティの後に0または1つのBアクティビティがあることを意味します。連続して1Bを超えるアクティビティはありません。

    単一のウィンドウ関数DISTINCT ONで動作させることができます およびCASE 、これは少数の最速の方法です。 ユーザーあたりの行数(以下も参照):

    SELECT name
         , CASE WHEN a2 LIKE 'B%' THEN a1 ELSE a2 END AS activity
         , CASE WHEN a2 LIKE 'B%' THEN a2 END AS next_activity
    FROM  (
       SELECT DISTINCT ON (name)
              name
            , lead(activity) OVER (PARTITION BY name ORDER BY time DESC) AS a1
            , activity AS a2
       FROM   t
       WHERE (activity LIKE 'A%' OR activity LIKE 'B%')
       ORDER  BY name, time DESC
       ) sub;
    

    db<>ここでフィドル

    SQL CASE 式のデフォルトはNULL ELSEがない場合 ブランチが追加されたので、短くしました。

    timeを想定 定義されているNOT NULL 。それ以外の場合は、NULLS LASTを追加することをお勧めします 。なぜですか?

    • 列ASCで並べ替えますが、最初にNULL値を使用しますか?

    (activity LIKE 'A%' OR activity LIKE 'B%') activity ~ '^[AB]'よりも冗長です 、ただし、Postgresの古いバージョンでは通常高速です。パターンマッチングについて:

    • PostgreSQLのLIKE、SIMILAR TO、または正規表現とのパターンマッチング

    条件付きウィンドウ関数?

    それは実際には可能です 。集約されたFILTERを組み合わせることができます OVERを含む句 ウィンドウ関数の句。 ただし

    1. FILTER 句自体は、現在の行の値でのみ機能します。

    2. さらに重要なのは、FILTER lead()のような純粋な本物の関数には実装されていません またはlag() (Postgres 13まで)-集計関数のみ。

    試してみる場合:

    lead(activity) FILTER (WHERE activity LIKE 'A%') OVER () AS activity
    

    Postgresはあなたに教えてくれます:

    FILTER is not implemented for non-aggregate window functions
    

    FILTERについて :

    • 追加の(個別の)フィルターを使用して列を集約します
    • ウィンドウ関数のFILTER句で現在の行を参照する

    パフォーマンス

    少数の場合 少数のユーザー ユーザーあたりの行数、ほぼ インデックスがなくてもクエリは高速です。

    多くの場合 ユーザーと少数 ユーザーあたりの行数、上記の最初のクエリが最速である必要があります。参照:

    • 各GROUPBYグループの最初の行を選択しますか?

    多くの場合 ユーザーあたりの行数は、(潜在的に多く )セットアップの詳細に応じて、より高速なテクニック。参照:

    • GROUP BYクエリを最適化して、ユーザーごとに最新の行を取得します


    1. 「ユーザーpostgresのパスワード認証に失敗しました」

    2. SQL Server 2005でテーブル内の複数の列の合計を見つける方法は?

    3. 配列タイプのarray_agg

    4. 別のテーブルのデータからカウント列を更新します