2017-01-12 24 views
0

テーブルactivitiesには、フィールドがstarttime (TIMESTAMP)stoptime (TIMESTAMP)のテーブルがあります。ほとんどの活動が起こっている瞬間を見つけたい。そのような瞬間が最初に返されるはずです。Google BigQuery - 時間間隔に基づく最もアクティブな時間

私はすべてstarttimeタイムスタンプを取得しようとしましたが、それぞれの時点で発生しているアクティビティの数をカウントしました。そして、最大の発見:

#standardSQL 
SELECT 
    time, 
    (
    SELECT COUNT(*) 
    FROM activities 
    WHERE starttime <= time AND time <= stoptime 
) AS cnt 
FROM (
    SELECT DISTINCT starttime AS time 
    FROM activities 
    ORDER BY time 
) 
ORDER BY cnt DESC, time ASC 
LIMIT 1 

残念ながら、それは言う:LEFT OUTER JOIN cannot be used without a condition that is an equality of fields from both sides of the join.

私はデータベースの世界のこの外のための適切なアルゴリズムは、すべてのstarttimesstoptimesは、彼らの方法で配列に入れて取得することだと思いますそれを並べ替えてから、その配列を順番に調べて、最大の瞬間を探します。しかし、私はどのようにSQLでそのようなアルゴリズムを表現するか分かりません。

私はthisを見ましたが、それはどのような形であれ助けてくれないと思います。

+0

何あなたの瞬間の細かさがある - それは秒であります、分または時間か他の何か? –

+0

@MikhailBerlyant私はそれがミリ秒だと思います。 –

+0

なので、ほとんどのアクティビティを取得した全体の期間中に正確にミリ秒で検出する必要がありますか?これは大部分のユースケースでは実用的ではないと思われますが、特殊なケースがあるかもしれません。 –

答えて

2

質問に記載されているアルゴリズムに近いものを実現しました。それはすばらしく速く動作しますが、あなたが何か良いものを見つけたら、それを見てうれしく思います。です - -

#standardSQL 
SELECT time, SUM(add) OVER(ORDER BY time ASC, add DESC) AS cumsum 
FROM (
    SELECT starttime AS time, 1 AS add 
    FROM activities UNION ALL 
    SELECT stoptime AS time, -1 AS add 
    FROM activities 
) 
ORDER BY cumsum DESC 
1

はそれがより実用的な出力を返す私の視点から、バージョン
の下に考えてみて、同じレベルの連続した活動の全ての期間(それぞれの開始と終了を)
だからあなたは今だけ起動しません最も高いアクティビティを持つ期間全体(開始日と終了日)。そして1つだけでなく、それらのすべて

#standardSQL 
WITH intervals AS (
    SELECT time AS start_, LEAD(time) OVER(ORDER BY time) AS end_ 
    FROM (
    SELECT DISTINCT time FROM (
     SELECT starttime AS time FROM activities UNION ALL 
     SELECT stoptime AS time FROM activities)) 
), 
equals AS (
    SELECT start_, end_, COUNT(1) AS cumsum 
    FROM intervals AS i 
    JOIN activities AS a 
    ON i.start_ >= a.starttime AND i.end_ <= a.stoptime 
    GROUP BY start_, end_ 
), 
grps AS (
    SELECT 
    start_, end_, cumsum, 
    IFNULL(
     CAST(end_ = LEAD(start_) OVER(ORDER BY start_) AND LEAD(cumsum) OVER(ORDER BY start_) = cumsum AS INT64), 
     CAST(NOT((start_ = LAG(end_) OVER(ORDER BY start_) AND LAG(cumsum) OVER(ORDER BY start_) = cumsum)) AS INT64) 
    ) AS flag 
    FROM equals 
) 
SELECT MIN(start_) AS start_, MAX(end_) AS end_, cumsum 
FROM (
    SELECT start_, end_, cumsum, SUM(flag) OVER(ORDER BY start_) AS grp 
    FROM grps 
) 
GROUP BY cumsum, grp 
ORDER BY start_ 

あなたはダミー活動にテーブルを使用して、上記で遊ぶことができます

WITH activities AS (
    SELECT 1 AS starttime, 3 AS stoptime UNION ALL 
    SELECT 1 AS starttime, 4 AS stoptime UNION ALL 
    SELECT 4 AS starttime, 5 AS stoptime UNION ALL 
    SELECT 7 AS starttime, 8 AS stoptime UNION ALL 
    SELECT 7 AS starttime, 10 AS stoptime UNION ALL 
    SELECT 8 AS starttime, 12 AS stoptime 
) 

または

WITH activities AS (
    SELECT TIMESTAMP_ADD(CURRENT_TIMESTAMP(), INTERVAL 1 MINUTE) AS starttime, TIMESTAMP_ADD(CURRENT_TIMESTAMP(), INTERVAL 3 MINUTE) AS stoptime UNION ALL 
    SELECT TIMESTAMP_ADD(CURRENT_TIMESTAMP(), INTERVAL 1 MINUTE) AS starttime, TIMESTAMP_ADD(CURRENT_TIMESTAMP(), INTERVAL 4 MINUTE) AS stoptime UNION ALL 
    SELECT TIMESTAMP_ADD(CURRENT_TIMESTAMP(), INTERVAL 4 MINUTE) AS starttime, TIMESTAMP_ADD(CURRENT_TIMESTAMP(), INTERVAL 5 MINUTE) AS stoptime UNION ALL 
    SELECT TIMESTAMP_ADD(CURRENT_TIMESTAMP(), INTERVAL 7 MINUTE) AS starttime, TIMESTAMP_ADD(CURRENT_TIMESTAMP(), INTERVAL 8 MINUTE) AS stoptime UNION ALL 
    SELECT TIMESTAMP_ADD(CURRENT_TIMESTAMP(), INTERVAL 7 MINUTE) AS starttime, TIMESTAMP_ADD(CURRENT_TIMESTAMP(), INTERVAL 10 MINUTE) AS stoptime UNION ALL 
    SELECT TIMESTAMP_ADD(CURRENT_TIMESTAMP(), INTERVAL 8 MINUTE) AS starttime, TIMESTAMP_ADD(CURRENT_TIMESTAMP(), INTERVAL 12 MINUTE) AS stoptime 
) 
関連する問題