差距和岛屿 - POSTGRESQL

Posted

技术标签:

【中文标题】差距和岛屿 - POSTGRESQL【英文标题】:Gap & Islands - POSTGRESQL 【发布时间】:2018-07-27 21:20:41 【问题描述】:

我有下表

Name PathID PathLength PathStepNum
A      1      5          1
A      1      5          2
B      1      5          3
C      1      5          4
A      1      5          5
Y      2      3          1
Z      2      3          2
Z      2      3          3

我需要得到

PathID   PathName
1        A x2 > B x1 > C x1 > A x1
2        Y x1 > Z x2

所以本质上我需要做的是:对于每个PathID,计算Name连续出现的次数,并按照PathStepNum的顺序将Name + NumConsecOccurrences拼接在一起。

有什么想法吗? 谢谢!

【问题讨论】:

那么x1x2是从哪里来的? @GordonLinoff - 这些是连续出现的次数(即 x2 = 2 次) 【参考方案1】:

具有窗口和聚合函数的经典解决方案:

select 
    pathid, 
    string_agg(format('%s x%s', name, count), ' > ' order by min) as path
from (
    select 
        pathid, name, min(pathstepnum), 
        count(*)
    from (
        select 
            pathid, name, pathstepnum, 
            sum(mark) over w as grp
        from (
            select 
                pathid, name, pathstepnum, 
                (name <> lag(name, 1, name) over w)::int as mark
            from my_table
            window w as (partition by pathid order by pathstepnum)
            ) s
        window w as (partition by pathid order by pathstepnum)
        ) s
    group by pathid, name, grp
    ) s
group by pathid

 pathid |           path            
--------+---------------------------
      1 | A x2 > B x1 > C x1 > A x1
      2 | Y x1 > Z x2
(2 rows)    

DbFiddle.

然而,这似乎可以在客户端应用程序(在 python、java 或其他任何使用的)中以更简单和更有效的方式实现。

【讨论】:

嘿@klin - 这看起来很完美。但是,我遇到的唯一问题是我的 POSTGRESQL 版本不支持顶部 string_agg 中的 ORDER BY MIN - 我只有 8.0。你知道如何打破 ORDER BY MIN 以便为这个版本运行吗? 不幸的是,我无法在 8.0 中对此进行测试,但您可以尝试将 order by 从聚合中移动到子查询中,例如 this example. 啊,现在我在 SUM(mark) OVER w AS grp 中的“w”上遇到语法错误...叹息哈哈。如果您无法使用 8.0 进入杂草,请不要担心 - 您提供了一个非常优雅的解决方案 @klin

以上是关于差距和岛屿 - POSTGRESQL的主要内容,如果未能解决你的问题,请参考以下文章

差距和岛屿 - 如何按 ID 对每组连续行求和

差距和岛屿 - 使用 Postgresql 获取某个日期范围内的失业日期列表

差距和孤岛 - Microsoft Access

使用差距和孤岛知识找到最长时间不改变就业(SQL)

岛屿和间隙的 SQL:岛屿可以重叠

岛屿问题--DFS问题