通过联合查询优化分组

问题描述

我有一个如下所示的MySQL表:

enter image description here

我想找到一个对表进行分组的查询,如下所示:

enter image description here

详细信息:

a_id =地图上的分隔区域

is_flag = 1-如果传感器在区域内/ 0-如果传感器不在区域内

基本上,第一张表描述了每个时间戳我的传感器在哪个区域。

第二张表告诉我传感器停留在每个区域内的时间。

我对每个area_id使用以下查询,并带有union all,以便在单个表中输出传感器在区域之间的移动时间以及每个区域内/下的停留时间。

select t.a_id,min(t.timestamp) starttime,max(t.timestamp) endtime,t.is_flag from(SELECT *,ROW_NUMBER() OVER(ORDER BY a.timestamp) - ROW_NUMBER() OVER(PARTITION BY 
a.is_flag ORDER BY a.timestamp) as GRP
FROM tablename a where areas_id=25 ) t
group by is_flag,GRP,a_id

这是我的dbfiddle:https://www.db-fiddle.com/f/5pHiYKyx4yHoirRbGX4kP4/0

我的查询可以满足我的需求,但需要花费一整天的时间。

解决方法

WITH 
cte1 AS (SELECT CAST(JSON_UNQUOTE(`timestamp`) AS DATETIME) ts,areas_id,is_in_or_out
         FROM inouts),cte2 AS (SELECT ts,is_in_or_out,CAST(ROW_NUMBER() OVER (PARTITION BY areas_id ORDER BY ts ASC) AS SIGNED)
               -CAST(ROW_NUMBER() OVER (PARTITION BY areas_id ORDER BY is_in_or_out,ts ASC) AS SIGNED) AS grp
         FROM cte1)
SELECT areas_id,ANY_VALUE(is_in_or_out) is_in_or_out,MIN(ts) min_ts,MAX(ts) max_ts
FROM cte2 
GROUP BY areas_id,grp
ORDER BY areas_id,min_ts;

fiddle

PS1。源数据略有更改。

PS2。 MySQL中需要CAST,因为ROW_NUMBER()会产生未签名的bigint。可以替换为0.0 + ...

,

这是sql server的语法,但在主要dbms中应该相同

with
x as (
    -- find start/end of each period
    select areas_id,is_in_or_out is_flag,timestamp t1,ISNULL(ABS(is_in_or_out - LAG(is_in_or_out,1) over (partition by areas_id order by timestamp)),1) T_START,ISNULL(ABS(is_in_or_out - LEAD(is_in_or_out,1) T_END
    from inouts
),y as (
    select *,LEAD(t1,1) over (partition by areas_id order by t1) t2
    from x
    WHERE T_START<>0 OR T_END<>0
)
select areas_id,is_flag,t1 starttime,t2 endtime
from y
WHERE T_START<>0 
order by areas_id,t1 

应该做到这一点

,

更多信息(例如示例数据和失败的查询)将有所帮助,但看来您可以将其分组。

select a_id,min(timestamp) as starttime,max(timestamp) as endtime
  from tablename
  group by a_id,is_flag
,

我在这里想念什么?您是否可能“思想过度”?下面的SQL提供与示例db-fiddle相同的结果集(我在副本上进行了测试),非常简单,并且运行速度更快。它为每个areas_id / is_in_or_out组合(按GROUP BY)给出一行。我不太明白为什么您需要UNION和ROW_NUMBER()OVER来使查询复杂化。希望这可以帮助。自己尝试一下,让我知道是否有任何问题!

SELECT areas_id,starttime,endtime,is_in_or_out
FROM   (SELECT areas_id,MIN(timestamp) starttime,MAX(timestamp) endtime,is_in_or_out
        FROM   inouts
        GROUP  BY is_in_or_out,areas_id) x
ORDER  BY starttime; 

P.S。我认为MBeale的解决方案实际上也是正确的(尽管它错过了ORDER BY)。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...