如何在DATEDIFF中消除重复的子查询/表达式?

时间:2015-11-27 20:43:02

标签: mysql compare rows

我的数据库是登录日期的示例。我想计算不同行上连续登录日期之间的约会。例如:

user_id     login_date  
1   2012-05-22
1   2012-05-25
/* difference is 3 days */

我能够找出两个查询来进行此计算,但在两个查询中我都需要复制子查询/表达式以获得我想要的结果。

我尝试使用' nextdate'在约会中,但得到一个错误:

#1054 - Unknown column 'nextdate' in 'field list' 

有没有办法消除重复?如果它产生了期望的结果,则可以接受全新的查询。

示例数据库

CREATE TABLE IF NOT EXISTS `tbl` (
  `user_id` int(11) DEFAULT NULL,
  `login_date` date DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

INSERT INTO `tbl` (`user_id`, `login_date`) VALUES
(1, '2012-04-01'),
(1, '2012-04-25'),
(1, '2012-05-03'),
(1, '2012-05-04'),
(1, '2012-05-05'),
(1, '2012-05-06'),
(1, '2012-05-07'),
(1, '2012-05-09'),
(1, '2012-05-10'),
(1, '2012-05-11'),
(1, '2012-05-12'),
(1, '2012-05-16'),
(1, '2012-05-19'),
(1, '2012-05-20'),
(1, '2012-05-21'),
(1, '2012-05-22'),
(1, '2012-05-25'),
(2, '2012-04-02'),
(2, '2012-04-03'),
(2, '2012-04-04'),
(2, '2012-05-04'),
(2, '2012-05-06'),
(2, '2012-05-08'),
(2, '2012-05-09'),
(2, '2012-05-11'),
(2, '2012-05-17'),
(2, '2012-05-18'),
(2, '2012-05-19'),
(2, '2012-05-20'),
(2, '2012-05-21'),
(2, '2012-05-22'),
(2, '2012-05-25'),
(2, '2012-05-26'),
(2, '2012-05-27'),
(2, '2012-05-28'),
(2, '2012-05-29'),
(2, '2012-05-30'),
(2, '2012-05-31'),
(2, '2012-06-01'),
(2, '2012-06-02');

工作查询#1

SELECT 
a.`user_id`,
a.`login_date`,
(SELECT 
    MIN(b.`login_date`) 
    FROM `tbl` b 
    WHERE a.`login_date` < b.`login_date` 
    AND a.`user_id` = b.`user_id`
) AS `nextdate`,
DATEDIFF((SELECT 
    MIN(b.`login_date`) 
    FROM `tbl` b 
    WHERE a.`login_date` < b.`login_date` 
    AND a.`user_id` = b.`user_id`
), a.`login_date`) AS `timespan`
FROM `tbl` a 
WHERE 1=1
AND (a.`login_date` >= '2012-05-10' AND a.`login_date` <= '2012-05-25')
HAVING `nextdate` IS NOT NULL
ORDER BY a.`user_id` ASC, a.`login_date` ASC

工作查询#2

SELECT 
a.`user_id`,
a.`login_date`,
MIN(b.`login_date`) AS `nextdate`,
DATEDIFF(MIN(b.`login_date`), a.`login_date`) AS `timespan`
FROM 
(
    SELECT 
    `user_id`, 
    `login_date`
    FROM `tbl`
) a 
JOIN 
(
    SELECT 
    `user_id`,
    `login_date`
    FROM `tbl`
) b 
ON a.`user_id` = b.`user_id`
AND a.`login_date` < b.`login_date` 
WHERE 1=1 
AND (a.`login_date` >= '2012-05-10' AND a.`login_date` <= '2012-05-25')
GROUP BY a.`user_id`,a.`login_date`

期望的结果

user_id     login_date  nextdate    timespan    
1   2012-05-10  2012-05-11  1
1   2012-05-11  2012-05-12  1
1   2012-05-12  2012-05-16  4
1   2012-05-16  2012-05-19  3
1   2012-05-19  2012-05-20  1
1   2012-05-20  2012-05-21  1
1   2012-05-21  2012-05-22  1
1   2012-05-22  2012-05-25  3
2   2012-05-11  2012-05-17  6
2   2012-05-17  2012-05-18  1
2   2012-05-18  2012-05-19  1
2   2012-05-19  2012-05-20  1
2   2012-05-20  2012-05-21  1
2   2012-05-21  2012-05-22  1
2   2012-05-22  2012-05-25  3
2   2012-05-25  2012-05-26  1

1 个答案:

答案 0 :(得分:1)

此查询与查询#2基本相同,但只使用简单的自联接。 group by和min(login_date)的自联接是最简单的,你可以将此查询减少到tbl a上的范围扫描,然后是tbl b上的键查找。

select a.user_id, a.login_date, min(b.login_date), datediff(min(b.login_date), a.login_date)
from   tbl a
join   tbl b on a.user_id = b.user_id and a.login_date < b.login_date
where  (a.login_date >= '2012-05-10' AND a.login_date <= '2012-05-25')
group by a.user_id, a.login_date
order by a.user_id, a.login_date, b.login_date
;