我有一个记录项目状态的表:
CREATE TABLE `project_states` (
`id` INT(10) NOT NULL AUTO_INCREMENT,
`state_id` INT(10) NULL DEFAULT NULL,
`project_id` INT(10) NULL DEFAULT NULL,
`created_at` TIMESTAMP NULL DEFAULT NULL,
PRIMARY KEY (`id`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
一些假数据:
id | state_id | project_id | created_at
-----------------------------------------------------
1 | 2 | 8 | 2014-05-27 10:58:12
2 | 3 | 8 | 2014-05-27 11:10:34
3 | 8 | 8 | 2014-05-27 11:56:48
4 | 2 | 10 | 2014-05-27 11:08:34
5 | 4 | 10 | 2014-05-27 11:59:01
我试图获得两个州之间的时差(比如说2和8),并且只针对确实这两个州的项目;在这种情况下,仅适用于项目8(因为10没有状态8)。
到目前为止,我完全设法选择符合条件的项目(包含两个值,而不仅仅是一个),但此查询返回每个匹配项目的结果元组:
SELECT t.*
FROM (
SELECT ps.*
FROM project_states ps
WHERE ps.state_id IN (2,8)
) as t
JOIN project_states pro ON pro.project_id = t.project_id
WHERE pro.state_id = 8
正确返回:
id | state_id | project_id | created_at
-----------------------------------------------------
1 | 2 | 8 | 2014-05-27 10:58:12
3 | 8 | 8 | 2014-05-27 11:56:48
我确信它有效,因为如果我将缺少的状态添加到另一个项目中,它会返回新的结果元组:
id | state_id | project_id | created_at
-----------------------------------------------------
1 | 2 | 8 | 2014-05-27 10:58:12
3 | 8 | 8 | 2014-05-27 11:56:48
4 | 2 | 10 | 2014-05-27 11:08:34
6 | 8 | 10 | 2014-05-27 12:03:08
但我如何计算时差呢?我使用PHP,我知道我可以通过project_id循环结果,然后计算差异,但我认为可能有一个纯SQL解决方案会产生如下结果:< / p>
project_id | difference
------------------------
8 | 0000-00-00 01:02:00
10 | 0000-00-00 01:05:26
嗯,实际上我的目标是计算项目位于这两个选定状态之间的平均时差,因此所有记录都可以归结为一个平均值,但可能我后来才知道这个问题。
答案 0 :(得分:1)
我会使用aggregation和having子句来执行此操作:
select ps.project_id,
timestampdiff(second, min(case when ps.state_id = 2 then created_at end),
max(case when ps.state_id = 8 then created_at)
) as diff_in_secs
from project_states ps
where ps.state_id in (2, 8)
group by ps.project_id
having count(distinct ps.state_id) = 2;
您也可以使用连接执行此操作:
select ps2.project_id, timestampdiff(second, ps2.created_at, ps8.created_at)
from project_states ps2 join
project_states ps8
on ps2.project_id = ps8.project_id and
ps2.state_id = 2 and ps8.state_id = 8;
答案 1 :(得分:1)
如果您只有2个状态,则可以使用简单的INNER JOIN。并且TIMESTAMPDIFF()可以在几分钟内获得差异,例如:
SELECT p.project_id,
TIMESTAMPDIFF(MINUTE,p.created_at,p1.created_at)
as state_minutes_diff
FROM project_states as p
JOIN project_states as p1
ON p.project_id=p1.project_id
AND p1.state_id=8
WHERE p.state_id=3
获得所有项目的平均值:
SELECT AVG(TIMESTAMPDIFF(MINUTE,p.created_at,p1.created_at))
as AVG_state_minutes_diff
FROM project_states as p
JOIN project_states as p1
ON p.project_id=p1.project_id
AND p1.state_id=8
WHERE p.state_id=3
答案 2 :(得分:1)
实际上,您不需要JOIN
,因为您可以通过指定正确的GROUP BY
子句来解决问题:
SELECT
SEC_TO_TIME(AVG(times.atime)) AS avg_time
FROM
(SELECT
project_id,
TIMEDIFF(MAX(created_at), MIN(created_at)) AS atime
FROM
project_states
WHERE
state_id IN (2,8)
GROUP BY
project_id
HAVING
COUNT(DISTINCT id)>1) as times
我似乎迟到了,但至少,因为fiddle我做了
答案 3 :(得分:0)
SELECT project_id,
timediff(min(created_at), max(created_at)) as difference
FROM project_states
WHERE state_id IN (2,8)
GROUP BY project_id
having count(distinct state_id) = 2