如何获得每个岛屿的第一排和最后一排?

Posted

技术标签:

【中文标题】如何获得每个岛屿的第一排和最后一排?【英文标题】:How to get first and last row of each island? 【发布时间】:2020-06-07 00:55:28 【问题描述】:

所以我最近在一个问题上得到了很好的帮助。但是,我需要更精确一些,希望这在 SQL 中是可行的。

这是我的最后一个问题:

Select only rows that has a column changed from the rows before it, given an unique ID

澄清:

我在那个问题上得到的帮助是让我开始每个岛屿。但是,我想要每个岛的起点和终点。

我的细微差别是这样的:

personID | status | unixtime | column d | column e | column f
    1        2       213214      x            y        z
    1        2       213325      x            y        z
    1        2       213326      x            y        z
    1        2       213327      x            y        z
    1        2       213328      x            y        z <-- I want this
    1        3       214330      x            y        z <-- Any of this is OK     
    1        3       214331      x            y        z
    1        3       214332      x            y        z <-- I want this or
    1        2       324543      x            y        z <-- I want this

所以我想要的是岛屿的尽头,而不是岛屿的起点。如果我在两者之间得到一些东西,那完全没问题,最好是结束。但是我真的想要状态变化的“之前”和“之后”是什么,如果这有任何意义的话。这可能是一个特定的状态。

【问题讨论】:

【参考方案1】:

此查询生成所有结束或开始分区的行(或在单行分区的情况下两者):

SELECT *
FROM  (
   SELECT *
        , lag(status)  OVER w IS DISTINCT FROM status AS partition_start
        , lead(status) OVER w IS DISTINCT FROM status AS partition_end
   FROM   tbl
   WINDOW w AS (PARTITION BY personID ORDER BY unixtime)
   ) sub
WHERE (partition_start OR partition_end)
ORDER  BY personID, unixtime;

db小提琴here

请注意,对于PARTITION BY personID,具有不同personID 的行不会中断“孤岛”。我在小提琴的测试用例中添加了行来演示效果。

如果您的要求不同,则必须定义方式。

【讨论】:

【参考方案2】:
select t.*
from (select t.*, 
       case when status <> lag(status,1,NULL) over(partition by personID order by unixtime) 
            then 1
            when lag(status,1,NULL) over(partition by personID order by unixtime) is null
            then 1
            else 0 end as start_status,
       case when status <> lead(status,1,NULL) over(partition by personID order by unixtime) 
            then 1
            when lead(status,1,NULL) over(partition by personID order by unixtime) is null
            then 1
            else 0 end as end_status
      from mytable t
) t
where end_status = 1
--or start_status = 1    -- uncomment this line if you want start statuses as well

【讨论】:

以上是关于如何获得每个岛屿的第一排和最后一排?的主要内容,如果未能解决你的问题,请参考以下文章

如何获得一个月内每周的第一天和最后一天?

python怎么获得每个月的第一天和最后一天

如何使用 tidyr 在分组变量的每个值中填写已完成的行?

获取每组的最后一行

有15人站成一排,按“1,2,1,2…报数,报2的留下,报1的出列,留下的人再按“1,2,1,2…

C#如何获得当前月的第一天与最后一天