2011-01-24 24 views
6

我試圖獲得特定的時間或時間跨度之間的行總數。 基本上,我們在下表說:mysql選擇時間跨度之間的行數

CREATE TABLE IF NOT EXISTS `downloads` (
`id` int(7) NOT NULL AUTO_INCREMENT, 
`stuff_id` int(7) NOT NULL, 
`user_id` int(7) NOT NULL, 
`dl_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, 
PRIMARY KEY (`id`) 
) ENGINE=MyISAM DEFAULT CHARSET=latin1; 

而且每次有人下載東西時該表被填充。

所以我真正需要的是獲得一個用戶列表(user_id),這些用戶列表在例如24小時的時間段內做出了比例如100次下載更多的用戶列表。不是在過去的24小時內,但在那個確切的時間內,即使它在去年聖誕節期間=)

任何想法?

+0

如果該查詢接受一個時間戳「時期的開始」,計算「期末」,並列出誰超過了在此期間的下載量所有用戶,還是應該列出每24小時超過x次下載量的所有用戶? –

+0

@Patrick沒有開始也沒有結束期...只列出誰超過在Y的X下載(因爲這可能是一個時間從24小時不同時間段)的時間限制 – eduardev

+0

我在想一個(可能的)解決方案的所有用戶。如果您仍然對此感興趣,我會解決它,並將其發佈到此處,但這會帶來負面影響:想象一下,我只在一小時內完成100次下載,然後會有很多時間段超出限制。例如:今天上午8點到9點之間下載100次。昨天上午9點至今天上午9點=下載100次。昨天上午10點直到今天上午10點=下載100次。昨天上午11點至今天上午11點=下載100次。待續... –

回答

6

OK,我知道我有點晚了,但我想反正張貼我的答案:-)

你需要什麼可以使用子查詢來完成,但是這可能需要年齡完成對大表...

思考這個問題我來到兩種不同的方法。

其中一個問題已經在其他答案中處理過了,它在特定時間點開始工作,查看此時開始的時間間隔,然後查看緊接着的相同時間間隔。這導致清晰,可理解的結果,並且可能是需要的(例如,每個日曆日用戶不得超過100次下載)。然而,這將完全錯過用戶在午夜前一小時下載99次而在新一天的第一小時內下載99次的情況。

因此,如果所需結果更多是「前十名下載者列表」,那麼這是另一種方法。乍一看,這裏的結果可能不會被理解,因爲一次下載可以計算多個時間間隔。這是因爲間隔將(並且需要)重疊。

這是我的設置。我從你的語句創建表,並增加了兩個指標:

CREATE INDEX downloads_timestamp on downloads (dl_date); 
CREATE INDEX downloads_user_id on downloads (user_id); 

我已經插入到表中的數據:

SELECT * FROM downloads; 
+----+----------+---------+---------------------+ 
| id | stuff_id | user_id | dl_date    | 
+----+----------+---------+---------------------+ 
| 1 |  1 |  1 | 2011-01-24 09:00:00 | 
| 2 |  1 |  1 | 2011-01-24 09:30:00 | 
| 3 |  1 |  1 | 2011-01-24 09:35:00 | 
| 4 |  1 |  1 | 2011-01-24 10:00:00 | 
| 5 |  1 |  1 | 2011-01-24 11:00:00 | 
| 6 |  1 |  1 | 2011-01-24 11:15:00 | 
| 7 |  1 |  1 | 2011-01-25 09:15:00 | 
| 8 |  1 |  1 | 2011-01-25 09:30:00 | 
| 9 |  1 |  1 | 2011-01-25 09:45:00 | 
| 10 |  1 |  2 | 2011-01-24 08:00:00 | 
| 11 |  1 |  2 | 2011-01-24 12:00:00 | 
| 12 |  1 |  2 | 2011-01-24 12:01:00 | 
| 13 |  1 |  2 | 2011-01-24 12:02:00 | 
| 14 |  1 |  2 | 2011-01-24 12:03:00 | 
| 15 |  1 |  2 | 2011-01-24 12:00:00 | 
| 16 |  1 |  2 | 2011-01-24 12:04:00 | 
| 17 |  1 |  2 | 2011-01-24 12:05:00 | 
| 18 |  1 |  2 | 2011-01-24 12:06:00 | 
| 19 |  1 |  2 | 2011-01-24 12:07:00 | 
| 20 |  1 |  2 | 2011-01-24 12:08:00 | 
| 21 |  1 |  2 | 2011-01-24 12:09:00 | 
| 22 |  1 |  2 | 2011-01-24 12:10:00 | 
| 23 |  1 |  2 | 2011-01-25 14:00:00 | 
| 24 |  1 |  2 | 2011-01-25 14:12:00 | 
| 25 |  1 |  2 | 2011-01-25 14:25:00 | 
+----+----------+---------+---------------------+ 
25 rows in set (0.00 sec) 

正如你可以看到,所有的下載前一天或當天發生並由兩個不同的用戶執行。現在

,我們必須頭腦什麼是以下幾點:有(數學)的24間小時的間隔(或任何其他時間間隔)「2011-01-24 0:00」和「2011-2015之間的無限多01-25 23:59:59'。但是,隨着服務器的精度爲1秒,這歸結爲86,400區間:

First interval: 2011-01-24 0:00:00 -> 2011-01-25 0:00:00 
Second interval: 2011-01-24 0:00:01 -> 2011-01-25 0:00:01 
Third interval: 2011-01-24 0:00:02 -> 2011-01-25 0:00:02 
    . 
    . 
    . 
86400th interval: 2011-01-24 23:59:59 -> 2011-01-25 23:59:59 

因此,我們可以使用一個循環遍歷所有這些區間和計算每個用戶和每個區間的下載數量。當然,並不是所有的時間間隔對我們都有相同的興趣,所以我們可以通過使用表中的時間戳作爲「時間間隔開始」來跳過其中的一些時間間隔。

這是下面的查詢做什麼。它使用表中的每個下載時間戳記作爲「間隔開始時間」,添加間隔持續時間,然後查詢此間隔期間每個用戶的下載次數。

SET @duration = '24:00:00'; 
SET @limit = 5; 
SELECT * FROM 
    (SELECT t1.user_id, 
      t1.dl_date startOfPeriod, 
      ADDTIME(t1.dl_date,@duration) endOfPeriod, 
      (SELECT COUNT(1) 
      FROM downloads t2 
      WHERE t1.user_id = t2.user_id 
      AND t1.dl_date <= t2.dl_date 
      AND ADDTIME(t1.dl_date,@duration) >= t2.dl_date) count 
    FROM downloads t1) t3 
WHERE count > @limit; 

這裏的結果:

+---------+---------------------+---------------------+-------+ 
| user_id | startOfPeriod  | endOfPeriod   | count | 
+---------+---------------------+---------------------+-------+ 
|  1 | 2011-01-24 09:00:00 | 2011-01-25 09:00:00 |  6 | 
|  1 | 2011-01-24 09:30:00 | 2011-01-25 09:30:00 |  7 | 
|  1 | 2011-01-24 09:35:00 | 2011-01-25 09:35:00 |  6 | 
|  1 | 2011-01-24 10:00:00 | 2011-01-25 10:00:00 |  6 | 
|  2 | 2011-01-24 08:00:00 | 2011-01-25 08:00:00 | 13 | 
|  2 | 2011-01-24 12:00:00 | 2011-01-25 12:00:00 | 12 | 
|  2 | 2011-01-24 12:01:00 | 2011-01-25 12:01:00 | 10 | 
|  2 | 2011-01-24 12:02:00 | 2011-01-25 12:02:00 |  9 | 
|  2 | 2011-01-24 12:03:00 | 2011-01-25 12:03:00 |  8 | 
|  2 | 2011-01-24 12:00:00 | 2011-01-25 12:00:00 | 12 | 
|  2 | 2011-01-24 12:04:00 | 2011-01-25 12:04:00 |  7 | 
|  2 | 2011-01-24 12:05:00 | 2011-01-25 12:05:00 |  6 | 
+---------+---------------------+---------------------+-------+ 
12 rows in set (0.00 sec) 
+0

那裏很好的東西!不知道這兩個想法的表現如何,無論如何,主要目的不會錯過任何可能的「24小時」時期。爲了完整起見,我改變了這個答案。 – eduardev

2

這將返回在1天的任何時期都取得了超過100所下載的user_id的列表:

SELECT user_id, count(user_id) as downloads_count, DATE(dl_date) 
FROM downloads 
GROUP BY user_id, DATE(dl_date) 
HAVING count(user_id) > 100; 
+0

按日期有趣的分組將承擔1整天,我會給你有用的,如果我能八邑,反正可以說週期將是任何東西,從一整天的不同,例如像8周或更復雜的東西幾個小時......很難對嗎?我很可能會接受這個,因爲它現在會做!謝謝 – eduardev

+1

對於其他時間段,您可以將時間戳分組到四分之一的時間段:GROUP BY user_id,unix_timestamp(dl_date) - (unix_timestamp(dl_date)%3600)'(1小時) – arnaud576875

+0

Spot on,非常感謝 – eduardev

0

你想使用BETWEEN,小組USER_ID在兩個日期值過濾,然後使用HAVING過濾分組結果。

三個參數,--Date1--,--Date2--和--Threshhold--

select user_id 
    , count(*) 
    from downloads 
where dl_date between --Date1-- and --Date2-- 
group by user_id 
having count(*) > --Threshhold-- 
+0

感謝這個想法,但是,沒有開始或結束日期值...請參閱上面的Patrick Echterbruch! – eduardev

1

如果你有一個週期這樣的,其小於或等於24小時:

SET @period_start='2010-10-10 06:00:00'; 
SET @period_end='2010-10-11 05:59:59'; 

然後,

SELECT user_id, COUNT(id) AS num 
FROM downloads WHERE dl_date>= @period_start AND dl_date<= @period_end 
GROUP BY user_id HAVING num> 100; 

但是,如果你有一段這樣的,這是超過24h更大:

SET @period_start='2010-10-10 06:00:00'; 
SET @period_end='2011-09-17 13:15:12'; 

你想如何計算你的下載數量?它是@period_end還是@period_start的24小時塊。或者你只是想要最近的24小時?