我有一个问题。假设我在SQL中有这个表:
date user_id
2015-03-17 00:06:12 143
2015-03-17 01:06:12 143
2015-03-17 02:06:12 143
2015-03-17 09:06:12 143
2015-03-17 10:10:10 200
我想获得连续数小时。例如,对于用户143,我希望获得2小时,对于用户200 0小时。我试过这样:
select user_id, TIMESTAMPDIFF(HOUR,min(date), max(date)) as hours
from myTable
group by user_id
但是此查询会提取所有非连续小时数。是否可以通过查询解决问题,还是需要在PHP中对结果进行后处理?
答案 0 :(得分:2)
使用变量与上一行进行比较。
SELECT user_id, SUM(cont_hour) FROM (
SELECT
user_id,
IF(CONCAT(DATE(@prev_date), ' ', HOUR(@prev_date), ':00:00') - INTERVAL 1 HOUR = CONCAT(DATE(t.date), ' ', HOUR(t.date), ':00:00')
AND @prev_user = t.user_id, 1, 0) AS cont_hour
, @prev_date := t.date
, @prev_user := t.user_id
FROM
table t
, (SELECT @prev_date := NULL, @prev_user := NULL) var_init_subquery
WHERE t.date BETWEEN <this> AND <that>
ORDER BY t.date
) sq
GROUP BY user_id;
我的比较比你想象的要复杂得多,但我认为有必要,你不要只是比较小时,而且,它是同一天(或前一天,当它在午夜左右)。
作为一个简短的解释:ORDER BY
非常重要,以及SELECT
子句中的顺序。 @prev_date
保存&#34;前一行&#34;,因为我们在进行比较后分配了当前行的值。
答案 1 :(得分:1)
使用临时变量的另一个版本:
SET @u := 0;
SET @pt := 0;
SET @s := 0;
SELECT `user_id`, MAX(`s`) `conseq` FROM
(
SELECT
@s := IF(@u = `user_id`,
IF(UNIX_TIMESTAMP(`date`) - @pt = 3600, @s + 1, @s),
0) s,
@u := `user_id` `user_id`,
@pt := UNIX_TIMESTAMP(`date`) pt
FROM `users`
ORDER BY `date`
) AS t
GROUP BY `user_id`
子查询按日期对行进行排序,然后将user_id
与之前的值进行比较。如果用户ID相等,则计算date
与上一个时间戳@pt
之间的差异。如果差异是一小时(3600秒),则@s
计数器将增加1。否则,计数器重置为0:
s user_id pt
0 143 1426529172
1 143 1426532772
2 143 1426536372
2 143 1426561572
0 200 1426565410
外部查询收集每user_id
的最大计数器值,因为最大计数器值对应于每user_id
的最后一个计数器值。
输出
user_id conseq
143 2
200 0
注意,查询接受恰好1小时的差异。如果您想要更灵活的条件,只需调整比较即可。例如,您可以接受3000到4000秒之间的间隔差异,如下所示:
@s := IF(@u = `user_id`,
IF( (UNIX_TIMESTAMP(`date`) - @pt) BETWEEN 3000 AND 4000, @s + 1, @s),
0) s