在 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 中查找排名最高的相交行的主要内容,如果未能解决你的问题,请参考以下文章

嵌套相交

Mysql查询 - 返回两个日期范围相交的日期

sql:在sql中相交(加入概率)

查找与点相交的圆[重复]

sql查询中的相交操作问题

如何让 sql 排名查询工作以查找特定 id 的排名