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

時間範囲で個別のユーザーグループを選択する

    カウントすべて

    SELECT date, '1_D' AS time_series,  count(DISTINCT user_id) AS cnt
    FROM   uniques
    GROUP  BY 1
    
    UNION  ALL
    SELECT DISTINCT ON (1)
           date, '2_W', count(*) OVER (PARTITION BY week_beg ORDER BY date)
    FROM   uniques
    
    UNION  ALL
    SELECT DISTINCT ON (1)
           date, '3_M', count(*) OVER (PARTITION BY month_beg ORDER BY date)
    FROM   uniques
    ORDER  BY 1, time_series
    
    • あなたの列はweek_beg およびmonth_beg 100%冗長であり、 date_trunc('week'、date + 1)-1で簡単に置き換えることができます。 およびdate_trunc('month'、date) それぞれ。

    • あなたの週は日曜日に始まるようです(1つずつずれています)。したがって、 + 1 ..-1

    • ウィンドウ関数のデフォルトフレーム ORDER BYを使用 OVERで 句の使用は、UNBOUNDEDPRECEDINGとCURRENTROWの間の範囲です。 。それがまさにあなたが必要としているものです。

    • UNION ALLを使用する 、 UNIONではありません 。

    • time_seriesの不幸な選択 (D、W、M)はうまくソートされないので、名前を変更して、最終的な ORDER BYにしました。 簡単です。

    • このクエリは、1日に複数の行を処理できます。カウントには、1日のすべてのピアが含まれます。

    • DISTINCT ONの詳細 :

    1日あたりのDISTINCTユーザー

    すべてのユーザーを1日に1回だけカウントするには、CTE> DISTINCT ONを使用 :

    WITH x AS (SELECT DISTINCT ON (1,2) date, user_id FROM uniques)
    SELECT date, '1_D' AS time_series,  count(user_id) AS cnt
    FROM   x
    GROUP  BY 1
    
    UNION ALL
    SELECT DISTINCT ON (1)
           date, '2_W'
          ,count(*) OVER (PARTITION BY (date_trunc('week', date + 1)::date - 1)
                          ORDER BY date)
    FROM   x
    
    UNION ALL
    SELECT DISTINCT ON (1)
           date, '3_M'
          ,count(*) OVER (PARTITION BY date_trunc('month', date) ORDER BY date)
    FROM   x
    ORDER BY 1, 2
    

    動的な期間にわたるDISTINCTユーザー

    いつでも相関サブクエリに頼ることができます 。大きなテーブルでは遅くなる傾向があります!
    前のクエリに基づいて構築する:

    WITH du AS (SELECT date, user_id FROM uniques GROUP BY 1,2)
        ,d  AS (
        SELECT date
              ,(date_trunc('week', date + 1)::date - 1) AS week_beg
              ,date_trunc('month', date)::date AS month_beg
        FROM   uniques
        GROUP  BY 1
        )
    SELECT date, '1_D' AS time_series,  count(user_id) AS cnt
    FROM   du
    GROUP  BY 1
    
    UNION ALL
    SELECT date, '2_W', (SELECT count(DISTINCT user_id) FROM du
                         WHERE  du.date BETWEEN d.week_beg AND d.date )
    FROM   d
    GROUP  BY date, week_beg
    
    UNION ALL
    SELECT date, '3_M', (SELECT count(DISTINCT user_id) FROM du
                         WHERE  du.date BETWEEN d.month_beg AND d.date)
    FROM   d
    GROUP  BY date, month_beg
    ORDER  BY 1,2;
    

    SQLフィドル 3つのソリューションすべてに対して。

    density_rank()で高速化

    @Clodoaldo 大きな改善を思いついた:ウィンドウ関数dense_rankを使用する() 。最適化されたバージョンの別のアイデアがあります。毎日の重複をすぐに除外する方がさらに速いはずです。パフォーマンスの向上は、1日あたりの行数とともに増加します。

    簡略化およびサニタイズされたデータモデルに基づいて構築する -冗長な列なし-day dateの代わりに列名として

    日付標準SQLで予約されている単語 です。 PostgreSQLの基本的な型名であり、識別子として使用しないでください。

    CREATE TABLE uniques(
       day date     -- instead of "date"
      ,user_id int
    );
    

    改善されたクエリ:

    WITH du AS (
       SELECT DISTINCT ON (1, 2)
              day, user_id 
             ,date_trunc('week',  day + 1)::date - 1 AS week_beg
             ,date_trunc('month', day)::date         AS month_beg
       FROM   uniques
       )
    SELECT day, count(user_id) AS d, max(w) AS w, max(m) AS m
    FROM  (
        SELECT user_id, day
              ,dense_rank() OVER(PARTITION BY week_beg  ORDER BY user_id) AS w
              ,dense_rank() OVER(PARTITION BY month_beg ORDER BY user_id) AS m
        FROM   du
        ) s
    GROUP  BY day
    ORDER  BY day;
    

    SQLフィドル 4つのより高速なバリアントのパフォーマンスを示しています。それはあなたにとって最速のデータ分布に依存します。
    それらはすべて、相関サブクエリバージョンの約10倍の速度です(相関サブクエリにとっては悪くありません)。



    1. jdbcを介して実行されるストアドプロシージャ

    2. PHPからmysqlに接続するにはどうすればよいですか?

    3. OracleDBのSQLクエリでDateTimeパラメータを渡す方法

    4. MySQL-Pythonインストール-eggをビルドできませんでした