仅在某些条件发生时循环和分组

Posted

技术标签:

【中文标题】仅在某些条件发生时循环和分组【英文标题】:Loop and group by only when some conditions occur 【发布时间】:2015-07-31 19:21:23 【问题描述】:

我的行程有多个站点

Trip  Stop  Time 
1     A     1:10
1     B     1:15
1     B     1:20
1     B     1:25
1     C     1:30
2     A     2:10
2     B     2:15
2     C     2:20
2     B     2:25  

我想把桌子转移到:

Trip  Stop  Time  WaitTime
1     A     1:10   0
1     B     1:15   10min
1     C     1:30   0
2     A     2:10   0
2     B     2:15   0
2     C     2:20   0
2     B     2:25   0

我想知道oracle查询是否可以实现它或游标? 伪代码: SELECT case when previousstop = stop then time-lag(time) over (partition by trip order by trip,time) 作为等待时间,但我不知道如何按 B 分组。

仅供参考:在第二次旅行中,我确实想保留两个 B。我想按 B 分组的唯一时间是它们彼此按顺序排列。我认为 max, min 不适用于这种情况。

【问题讨论】:

这个不需要游标,应该有游标标签吗? 也许我们真正需要的是一个 DontUseACursorToDoThisEver 标签。 如果您认为不需要光标,请用简单的查询启发我。 vkp 为您提供了在答案中没有光标的情况下执行此操作的代码。他的回答很好,用吧。 只是关于速度的旁注,预期使用的框架是 O(n),递归 CTE O(lg N) 和光标 O(n^2) 【参考方案1】:
with y as (select trip, stop, min(time) mintime, max(time) maxtime 
       from tablename group by trip, stop)
select y.trip, y.stop, y.mintime, (y.maxtime-y.mintime) waittime
 from y join tablename t 
  on t.trip = y.trip and t.stop = y.stop

【讨论】:

不是这么简单,您使用的查询可能满足trip1,但对于trip2,我想保留两个B。如果我将行程 1 延长为 A、B、B、C、B,我希望结果为 A、B、C、B。 max 和 min 将失去第三个 B 得到它..将尝试获得您需要的解决方案 感谢您的帮助! :)【参考方案2】:

这是一个适用于 SQL Server 的解决方案,假设时间间隔始终为 5 分钟。我相信 Oracle 对这里的所有内容都有相同的功能,但需要进行一些语法更改:

;with cte AS (
          SELECT   a.Trip
                  ,a.Stop
                  ,MIN(a.Time) AS Time                
                  ,x.Time AS EndTime                  
          FROM Table1 a
          OUTER APPLY (
                SELECT TOP 1 Time = a2.[Time]
                FROM Table1 a2
                WHERE  a.[Time] < a2.[Time]
                   AND a.[Stop] <> a2.[Stop]
                   AND a.[Trip] = a2.[Trip]
                ORDER BY a2.[Time]
               ) x
          GROUP BY a.Trip ,a.Stop, x.Time
          )
SELECT Trip,Stop,Time, WaitTime = COALESCE(DATEDIFF(minute,Time,EndTime)-5,0)
FROM cte
ORDER BY Trip,Time
;

演示:SQL Fiddle

如果时间间隔不一致,则需要额外的步骤。

【讨论】:

@SailorMoon 查看更新,它是 SQL Server 语法,但很确定 Oracle 不需要太多更改。 感谢我会尝试回来。我想出了另一个解决方案,如果行程是 A、B、B、B、C、B,我可以将停靠序列命名为 1、2、2、2、3、4,然后我可以 Max/Min 查询.但是我还没有弄清楚如何通过查询将 row_number() 分区到那个停止序列。我知道如何在 C# 中做到这一点> 如果您在第一组 B 和第二组 B 之间有区别,那么您只需在 GROUP BY 中包含该区别。 @SailorMoon 哦,我以为您已经找到了一种方法,可以将第二个 B 区分为“1,2,2,2,3,4”。 OUTER APPLY 方法是我所拥有的。【参考方案3】:

嗨,我自己想通了!如果有人需要,这是答案

With TB AS (select t1.*
  ,sum(decode(t1.stop,t1.prev_stp,0,1)) over (partition by trip order by time) new_seq
from  
 (select t.*
        ,lag(stop) over (order by t.trip, t.time) prev_stp
  from   test t
  order  by tm) t1)

SELECT trip,stop,new_seq,min(etime) as Etime1, (max(etime)-min(etime)) wait time from TB 
group by trip,stop,new_seq
order by trip,new_seq

【讨论】:

以上是关于仅在某些条件发生时循环和分组的主要内容,如果未能解决你的问题,请参考以下文章

如何在 MDX 中对同一维度进行分组和过滤

Python分组;仅在满足条件时保留

如果仅在 MongoDB 中满足特定条件,则分组

按 id 和某些条件过滤掉数据分组

无循环的分组和条件(大数据)

在sql中使用case语句根据某些条件对列进行分组