在 SQL 中查找排名最高的相交行
Posted
技术标签:
【中文标题】在 SQL 中查找排名最高的相交行【英文标题】:Find highest-ranked pieces of intersecting rows in SQL 【发布时间】:2022-01-15 14:04:05 【问题描述】:这可能属于“只要我知道它的正确名称,我就可以用谷歌搜索它”的类别,但这里是这样。
我有一个交叉活动时间表的表格,以及这些活动的排名。在删除每个排名较高的交叉点后,我需要获取每行的剩余时间范围。
我尝试将每一行与每个相交的行连接起来,但根据每个单独的交叉点调整开始和结束时间并不能考虑更高级别的交叉点。这是我在决定我可能在概念上接近这个错误之前所做的事情。
select
Activity
,rank
,case
when b.startTime <= a.startTime then b.endTime
when b.endtime >= a.endTime then b.starttime
else a.startTime
end as starttimeAdj
,case
when b.starttime <= b.startTime then a.endtime
when b.endtime >= a.endTime then b.starttime
else a.endTime
end as endtimeAdj
from myTable as a
left join myTable as b
on b.startTime< a.endTime
and b.endTime> a.startTime
and b.Activity!= a.Activity
and b.Rank<a.rank
where
b.segID is null or
not (b.starttime <= a.startTime and b.endtime >= a.endTime)
order by a.starttime,a.rank,b.starttime,b.rank
这是一个例子。这是起始数据:
Activity rank StartTime EndTime
Meeting 1 8:00 9:00
Startup 2 8:00 8:10
Shift 4 8:00 19:00
Break1 3 10:15 10:30
Break2 3 17:00 17:15
这就是我想要达到的目标:
Activity rank StartTime EndTime
Meeting 1 8:00 9:00
Shift 4 9:00 10:15
Break1 3 10:15 10:30
Shift 4 10:30 17:00
Break2 3 17:00 17:15
Shift 4 17:15 19:00
Startup 活动已消失,因为它完全包含在更高级别的活动中。 Shift 活动作为最低等级,已被与其相交的每个事物分割,只剩下不相交的时段。
按等级的视觉表示:
<--Meeting-->
<Startup>
<Break1> <Break2>
<-----------------------------------------------Shift------------------------------------>
变成
<--Meeting--><--Shift-><Break><-----------------Shift--------------------><Break><-Shift->
【问题讨论】:
这不是很清楚 - “需要结果”示例是原始数据吗?如果是这样的话,我真的不知道如何从那个例子中得到你想要的结果 谢谢,我澄清了一点,希望它更有意义。 这没有任何意义。您的示例数据非常模糊,以至于细节都消失了。 @Sean Lange 编辑了更多细节 这是一个空白和孤岛问题。 【参考方案1】:我会咬人的。这里有一些东西可以尝试。我对每个活动的前沿和后沿的处理略有不同,因为我们希望在处理前沿结果时包含当前活动,而在处理后沿结果时排除当前活动。
CTE term | Description |
---|---|
edge1 | Leading edge start time rank of overlapping rows |
edge2 | Trailing edge end time rank of overlapping rows |
xall | Just UNION the leading and trailing edge times of the best ranked rows |
xprune | Determine which adjacent rows (having the same segID) can be pruned |
final | Reduce to the final set of rows while calculating the new end times |
最后一个查询表达式选择感兴趣的列并删除表示活动间隙的行。
Fiddle for SQL Server
SQL:
WITH edge1 AS (
SELECT t2.Activity
, t2.rank
, t1.StartTime
, t2.segID
, ROW_NUMBER() OVER (PARTITION BY t1.StartTime ORDER BY t2.rank) AS rnk
FROM segments AS t1
LEFT JOIN segments AS t2
ON t1.StartTime >= t2.StartTime
AND t1.StartTime < t2.EndTime
)
, edge2 AS (
SELECT t2.Activity
, t2.rank
, t1.EndTime
, t2.segID
, ROW_NUMBER() OVER (PARTITION BY t1.EndTime ORDER BY t2.rank) AS rnk
FROM segments AS t1
LEFT JOIN segments AS t2
ON t1.EndTime > t2.StartTime
AND t1.EndTime < t2.EndTime
AND t1.segID <> t2.segID
)
, xall AS (
SELECT * FROM edge1 WHERE rnk = 1
UNION
SELECT * FROM edge2 WHERE rnk = 1
)
, xprune AS (
SELECT *
, CASE WHEN LAG(segID) OVER (ORDER BY StartTime) = segID THEN 1 ELSE 0 END AS prune
FROM xall
)
, final AS (
SELECT *
, LEAD(StartTime) OVER (ORDER BY StartTime) AS EndTime
FROM xprune
WHERE prune = 0
)
SELECT Activity, rank, StartTime, EndTime
FROM final
WHERE Activity IS NOT NULL
ORDER BY StartTime
;
结果:
+----------+------+-----------+---------+
| Activity | rank | StartTime | EndTime |
+----------+------+-----------+---------+
| Meeting | 1 | 800 | 900 |
| Shift | 4 | 900 | 1015 |
| Break1 | 3 | 1015 | 1030 |
| Shift | 4 | 1030 | 1700 |
| Break2 | 3 | 1700 | 1715 |
| Shift | 4 | 1715 | 1900 |
+----------+------+-----------+---------+
【讨论】:
谢谢你!您的解决方案完美运行,我很欣赏故障,以便我可以剖析和学习。以上是关于在 SQL 中查找排名最高的相交行的主要内容,如果未能解决你的问题,请参考以下文章