仅在某些条件发生时循环和分组
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
【讨论】:
以上是关于仅在某些条件发生时循环和分组的主要内容,如果未能解决你的问题,请参考以下文章