SQL QUERY 在对表进行排序后合并连续的相同值

Posted

技术标签:

【中文标题】SQL QUERY 在对表进行排序后合并连续的相同值【英文标题】:SQL QUERY Merge Consecutive Same Values After Sorting the Table 【发布时间】:2021-05-04 11:15:23 【问题描述】:

假设我们有这张桌子

id |begin | end | location
1  |    5 |  10 | MALL A
2  |    1 |   3 | MALL B
3  |   13 |  17 | MALL A
4  |   21 |  25 | MALL C
5  |   36 |  38 | MALL D
6  |   31 |  33 | MALL D
7  |   26 |  29 | MALL F
8  |   40 |  45 | MALL D

然后我们按开始列 asc 对表格进行排序。因此我们有这张表

id |begin | end | location
2  |    1 |   3 | MALL B
1  |    5 |  10 | MALL A
3  |   13 |  17 | MALL A
4  |   21 |  25 | MALL C
7  |   26 |  29 | MALL F
6  |   31 |  33 | MALL D
5  |   36 |  38 | MALL D
8  |   40 |  45 | MALL D

我想要一张这样的桌子。 (连续位置相同的行将被合并)

begin | end | location
    1 |   3 | MALL B
    5 |  17 | MALL A
   21 |  25 | MALL C
   26 |  29 | MALL F
   31 |  45 | MALL D

我如何做到这一点?

我认为我可以使用 RANK() 然后按排名值对其进行分组。但我做不到。我以为这是因为表格没有先排序。

如果你想在 SQL 上创建表,我提供了这些 SQL 语法来创建它。

CREATE TABLE `t` (
  `id` int NOT NULL,
  `begin` int DEFAULT NULL,
  `end` int DEFAULT NULL,
  `location` varchar(45) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

INSERT INTO t (id, begin, end, location) VALUES (1, 5,10, 'A');
INSERT INTO t (id, begin, end, location) VALUES (2, 1,3, 'B');
INSERT INTO t (id, begin, end, location) VALUES (3, 13,17, 'A');
INSERT INTO t (id, begin, end, location) VALUES (4, 21,25, 'C');
INSERT INTO t (id, begin, end, location) VALUES (5, 36,38, 'D');
INSERT INTO t (id, begin, end, location) VALUES (6, 31,33, 'D');
INSERT INTO t (id, begin, end, location) VALUES (7, 26,29, 'F');
INSERT INTO t (id, begin, end, location) VALUES (8, 40,45, 'D');

【问题讨论】:

供您参考,这被称为gaps-and-islands 问题。 【参考方案1】:

这是一种间隙和孤岛问题。在这种情况下,您可以使用lag() 来确定行应该在不同组中的位置。然后使用累积和来定义组和聚合:

select location, min(begin), max(end)
from (select t.*,
             sum(case when prev_location = location then 0 else 1 end) over (order by begin) as grp
      from (select t.*,
                   lag(location) over (order by begin) as prev_location
            from t
           ) t
     ) t
group by grp, location;

其实,因为你不关心结尾和后面的开始之间的差距,你可以使用稍微简单的行号差异:

select location, min(begin), max(end)
from (select t.*,
             row_number() over (order by begin) as seqnum,
             row_number() over (partition by location order by begin) as seqnum_2
      from t
     ) t
group by location, (seqnum - seqnum_2);

这有点难以解释,但是如果你看一下子查询的结果,你会发现在位置相同的情况下,两个row_number()s 之间的差异是如何保持不变的。

【讨论】:

谢谢。第一个按预期工作。但是第二个不起作用,我认为有语法错误。 "FUNCTION t.location 不存在" 选择位置,min(begin) as begin,max(end),(seqnum - seqnum_2) AS grp from (select t.*, row_number() over (order by begin) as seqnum, row_number () over (partition by location order by begin) as seqnum_2 from t) t group by location, grp order by begin @ShalahuddinAl-Ayyubbi 。 . .那是一个错字——缺少一列。

以上是关于SQL QUERY 在对表进行排序后合并连续的相同值的主要内容,如果未能解决你的问题,请参考以下文章

常见排序算法

PCB MS SQL 排序应用---相邻数据且相同合并处理

SQL怎样合并显示两个没有关联的表

SQL如何将某一列中相同的数据合并

算法 合并表记录

如何在 PDO 语句中对表名进行参数化? [复制]