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

連続訪問数をカウントする

    私はmysqlタグを見逃し、この解決策を書きました。残念ながら、ウィンドウ関数をサポートしていないため、これはMySQLでは機能しません

    とにかく投稿しますので、少し力を入れています。 PostgreSQLでテスト済み。 OracleまたはSQLServer(またはウィンドウ関数をサポートするその他の適切なRDBMS)でも同様に機能します。

    テストセットアップ

    CREATE TEMP TABLE v(id int, visit date);
    INSERT INTO v VALUES
     (444631, '2011-11-07')
    ,(444631, '2011-11-06')
    ,(444631, '2011-11-05')
    ,(444631, '2011-11-04')
    ,(444631, '2011-11-02')
    ,(444631, '2011-11-01')
    ,(444632, '2011-12-02')
    ,(444632, '2011-12-03')
    ,(444632, '2011-12-05');
    

    シンプルバージョン

    -- add 1 to "difference" to get number of days of the longest period
    SELECT id, max(dur) + 1 as max_consecutive_days
    FROM (
    
       -- calculate date difference of min and max in the group
       SELECT id, grp, max(visit) - min(visit) as dur
       FROM (
    
          -- consecutive days end up in a group
          SELECT *, sum(step) OVER (ORDER BY id, rn) AS grp
          FROM   (
    
             -- step up at the start of a new group of days
             SELECT id
                   ,row_number() OVER w AS rn
                   ,visit
                   ,CASE WHEN COALESCE(visit - lag(visit) OVER w, 1) = 1
                    THEN 0 ELSE 1 END AS step
             FROM   v
             WINDOW w AS (PARTITION BY id ORDER BY visit)
             ORDER  BY 1,2
             ) x
          ) y
          GROUP BY 1,2
       ) z
    GROUP  BY 1
    ORDER  BY 1
    LIMIT  1;
    

    出力:

       id   | max_consecutive_days
    --------+----------------------
     444631 |                    4
    

    速い/短い

    私は後でさらに良い方法を見つけました。 grp 数値は連続的ではありません(ただし、連続的に増加します)。これらは目的を達成するための手段にすぎないため、問題ではありません。

    SELECT id, max(dur) + 1 AS max_consecutive_days
    FROM (
        SELECT id, grp, max(visit) - min(visit) AS dur
        FROM (
          -- subtract an integer representing the number of day from the row_number()
          -- creates a "group number" (grp) for consecutive days
          SELECT id
                ,EXTRACT(epoch from visit)::int / 86400
               - row_number() OVER (PARTITION BY id ORDER BY visit) AS grp
                ,visit
          FROM   v
          ORDER  BY 1,2
          ) x
        GROUP BY 1,2
        ) y
    GROUP  BY 1
    ORDER  BY 1
    LIMIT  1;
    

    SQLフィドル 両方のために。

    その他



    1. #1115-不明な文字セット:'utf8mb4'

    2. SQLiteに存在する場合のドロップテーブル

    3. SQLでは、OR付きの括弧の使用はどういう意味ですか?

    4. ClusterControl 1.7.2の発表:TimescaleDBとMySQL8.0のPostgreSQLバックアップとサポートの改善