在MySql中我有一个表 device ,其中包含timestamp(long)和status(boolean)的列:
| ts | status |
+------+--------+
| 1 | 1 |
| 2 | 1 |
| 5 | 1 |
| 17 | 0 |
| 18 | 0 |
| 26 | 0 |
| 31 | 1 |
| 32 | 1 |
| 37 | 1 |
需要查询来计算状态为1的时间。
对于给定的情况,它是:(17-1) + (37-31) = 22
答案 0 :(得分:1)
http://sqlfiddle.com/#!9/e27644/1
第一步创建一个视图ordered_status
(mysql不支持窗口函数,如排名;-()
(您可以通过在position
表格中直接添加AUTO_INCREMENT
device
列来跳过此视图
create view ordered_status as
select
count(*) position,
A.ts,
A.status
from
device A
left join device B on
A.ts >= B.ts
group by
A.ts,A.status
第二步,将每一行加入下一行并仅计算status=1
的时间戳增量,sum
总计:
select
sum(case
when A.status=1 then B.ts-A.ts
else 0
end)
from
ordered_status A
left join ordered_status B on
A.position+1 = B.position
或无视图:http://sqlfiddle.com/#!9/97b97/1
select
sum(case
when A.status=1 then B.ts-A.ts
else 0
end)
from
(select count(*) position, A.ts,A.status
from device A left join device B on A.ts >= B.ts
group by A.ts,A.status) A
left join
(select count(*) position, A.ts,A.status
from device A left join device B on A.ts >= B.ts
group by A.ts,A.status) B on
A.position+1 = B.position
order by
A.position
答案 1 :(得分:0)
由于您无法使用窗口功能,解决方案稍微复杂一些
select sum(final.ts * final.sign)
from
(
select device.ts,
case when status = 1 and (prevstatus is null or prevstatus = 0) then -1 else 1 end sign
from
(
select d1.ts, d2.status, prev.ts prevts, prev.status prevstatus, next.ts nextts, next.status nextstatus
from (
select d1.ts,
d1.status,
max(d2.ts) prevts
from device d1
left join device d2 on d1.ts > d2.ts
group by d1.ts, d1.status
) d1
left join (
select d1.ts,
d1.status,
min(d2.ts) nextts
from device d1
left join device d2 on d1.ts < d2.ts
group by d1.ts, d1.status
) d2 on d1.ts = d2.ts
left join device prev on prev.ts = d1.prevts
left join device next on next.ts = d2.nextts
) devicePrevNext
where (status = 1 and (prevstatus is null or prevstatus = 0 or nextstatus is null)) or
(status = 0 and prevstatus = 1)
) final
答案 2 :(得分:0)
我会将此短语称为“获取下一个0”并将该信息用于总和:
select next_ts_0, min(ts) as ts_1, max(ts) as ts_1_end
from (select d.*,
(select d2.ts
from device d2
where d2.status = 0 and d2.ts > d.ts
order by d2.ts asc
limit 1
) as next_ts_0
from device d
) d
where status = 1
group by next_ts_0;
然后你可以加上结果:
select sum(coalesce(next_ts_0, ts_1_end) - ts_1)
from (select next_ts_0, min(ts) as ts_1, max(ts) as ts_1_end
from (select d.*,
(select d2.ts
from device d2
where d2.status = 0 and d2.ts > d.ts
order by d2.ts asc
limit 1
) as next_ts_0
from device d
) d
where status = 1
group by next_ts_0
) d;
Here是此解决方案的SQL小提琴。
device(status, ts)
上的索引可能有所帮助。如果性能是一个问题,您可能需要使用变量的解决方案。