8

この質問は以前に尋ねられましたが、私は少し異なる問題に直面しています。

イベントをログに記録し、それらのタイムスタンプを(日時として)保存するテーブルがあります。時間をチャンクに分割し、その間隔で発生したイベントの数を取得できる必要があります。間隔はカスタムにすることができます(5分から1時間、さらにはそれ以上と言います)。

明らかな解決策は、日時をunix_timestampに変換し、それを間隔内の秒数で除算し、そのフロア関数を取得して、秒数で乗算することです。最後に、unix_timestampを日時形式に変換し直します。

これは、短い間隔で正常に機能します。

select 
from_unixtime(floor(unix_timestamp(event.timestamp)/300)*300) as start_time,
count(*) as total 
from event 
where timestamp>='2012-08-03 00:00:00' 
group by start_time;

これにより、正しい出力が得られます

+---------------------+-------+
| start_time          | total |
+---------------------+-------+
| 2012-08-03 00:00:00 |    11 |
| 2012-08-03 00:05:00 |     4 |
| 2012-08-03 00:10:00 |     4 |
| 2012-08-03 00:15:00 |     7 |
| 2012-08-03 00:20:00 |     8 |
| 2012-08-03 00:25:00 |     1 |
| 2012-08-03 00:30:00 |     1 |
| 2012-08-03 00:35:00 |     3 |
| 2012-08-03 00:40:00 |     3 |
| 2012-08-03 00:45:00 |     5 |
~~~~~OUTPUT SNIPPED~~~~~~~~~~~~

しかし、間隔を1時間(3600秒)と言うように増やすと

mysql> select from_unixtime(floor(unix_timestamp(event.timestamp)/3600)*3600) as start_time, count(*) as total from event where timestamp>='2012-08-03 00:00:00' group by start_time;
+---------------------+-------+
| start_time          | total |
+---------------------+-------+
| 2012-08-02 23:30:00 |    35 |
| 2012-08-03 00:30:00 |    30 |
| 2012-08-03 01:30:00 |    12 |
| 2012-08-03 02:30:00 |    18 |
| 2012-08-03 03:30:00 |    12 |
| 2012-08-03 04:30:00 |     4 |
| 2012-08-03 05:30:00 |     3 |
| 2012-08-03 06:30:00 |    13 |
| 2012-08-03 07:30:00 |   269 |
| 2012-08-03 08:30:00 |   681 |
| 2012-08-03 09:30:00 |  1523 |
| 2012-08-03 10:30:00 |   911 |
+---------------------+-------+

私が判断できる限り、境界が適切に設定されていない理由は、unix_timestampが時刻をローカルタイムゾーン(GMT + 0530)からUTCに変換してから、数値を出力するためです。

したがって、2012-08-03 00:00:00のような値は、実際には2012-08-0218:30:00になります。フロアを分割して使用すると、分の部分が00に設定されます。ただし、from_unixtimeを使用すると、GMT + 0530に変換されるため、30分から始まる間隔が得られます。

タイムゾーンに関係なく、クエリが正しく機能することを確認するにはどうすればよいですか?MySQL 5.1.52を使用しているため、to_seconds()は使用できません

編集: クエリは、間隔(時間、分、日など)に関係なく正しく実行される必要があります。一般的な解決策をいただければ幸いです

4

2 に答える 2

7

TIMESTAMPDIFF時間間隔でグループ化するために使用できます。

指定された時間間隔で、次を使用できます。

SELECT   '2012-08-03 00:00:00' + 
         INTERVAL FLOOR(TIMESTAMPDIFF(HOUR, '2012-08-03 00:00:00', timestamp) / <n>) * <n> HOUR AS start_time,
         COUNT(*) AS total 
FROM     event 
WHERE    timestamp >= '2012-08-03 00:00:00'
GROUP BY start_time

2012-08-03 00:00:00の発生を最小入力日に置き換えます。

<n>は指定された時間間隔(2時間、3時間など)であり、同じことを数分間行うことができます。

SELECT   '2012-08-03 00:00:00' + 
         INTERVAL FLOOR(TIMESTAMPDIFF(MINUTE, '2012-08-03 00:00:00', timestamp) / <n>) * <n> MINUTE AS start_time,
         COUNT(*) AS total 
FROM     event 
WHERE    timestamp >= '2012-08-03 00:00:00'
GROUP BY start_time

<n>指定した間隔は分単位でどこにありますか(毎45分、90分など)。

2012-08-03 00:00:00の2番目のパラメーターとして最小入力日(この例では)を渡していることを確認してくださいTIMESTAMPDIFF


編集:関数で選択する間隔の単位を気にしたくない場合はTIMESTAMPDIFF、もちろん、秒単位で間隔を設定します(300 = 5分、3600 = 1時間、7200 = 2時間など)。

SELECT   '2012-08-03 00:00:00' + 
         INTERVAL FLOOR(TIMESTAMPDIFF(SECOND, '2012-08-03 00:00:00', timestamp) / <n>) * <n> SECOND AS start_time,
         COUNT(*) AS total 
FROM     event 
WHERE    timestamp >= '2012-08-03 00:00:00'
GROUP BY start_time

EDIT2:最小パラメーター日付を渡さなければならないステートメント内の領域の数を減らすことに関するコメントに対処するには、次を使用できます。

SELECT   b.mindate + 
         INTERVAL FLOOR(TIMESTAMPDIFF(SECOND, b.mindate, timestamp) / <n>) * <n> SECOND AS start_time,
         COUNT(*) AS total 
FROM     event 
JOIN     (SELECT '2012-08-03 00:00:00' AS mindate) b ON timestamp >= b.mindate
GROUP BY start_time

そして、最小日時パラメータを結合副選択に1回渡すだけです。

秒間隔の結合副選択で2番目の列を作成し(たとえば)、列に...3600のような名前を付けてから、 'sをに変更することもできます。これにより、最小の日付パラメーターと間隔をそれぞれ1回だけ渡す必要があります。 。secinterval<n>b.secinterval


SQLFiddleデモ

于 2012-08-03T06:06:40.753 に答える
1

より簡単な方法は次のとおりです。

方法1

select date(timestamp) as date_timestamp, hour(timestamp) as hour_timestamp, count(*) as total 
from event
where timestamp>='2012-08-03 00:00:00' 
group by date_timestamp, hour_timestamp

オリジナルのアプローチを使用したい場合。

方法2

select from_unixtime(floor(unix_timestamp(event.timestamp-1800)/3600)*3600+1800) as start_time, 
count(*) as total 
from event 
where timestamp>='2012-08-03 00:00:00' 
group by start_time;

編集1

最初の方法では、ユーザーが異なる間隔を設定することもできます。たとえば、ユーザーがログを15分ごとにグループ化する場合、

select date(time) as date_timestamp, 
    hour(time) as hour_timestamp,  
    floor(minute(time) as minute_timestamp / 15) * 15 as minute_timestamp
    count(*) as total
from event
group by date_timestamp, hour_timestamp, minute_timestamp
于 2012-08-03T05:53:27.527 に答える