如何通过不间断的序列进行GROUP条目?

时间:2015-09-02 09:47:12

标签: sql postgresql gaps-and-islands

CREATE TABLE entries (
  id serial NOT NULL,
  title character varying,
  load_sequence integer
);

和数据

INSERT INTO entries(title, load_sequence) VALUES ('A', 1);
INSERT INTO entries(title, load_sequence) VALUES ('A', 2);
INSERT INTO entries(title, load_sequence) VALUES ('A', 3);

INSERT INTO entries(title, load_sequence) VALUES ('A', 6);

INSERT INTO entries(title, load_sequence) VALUES ('B', 4);
INSERT INTO entries(title, load_sequence) VALUES ('B', 5);

INSERT INTO entries(title, load_sequence) VALUES ('B', 7);
INSERT INTO entries(title, load_sequence) VALUES ('B', 8);

PostgreSQL中是否有一种方法可以编写SQL,在title对它们进行排序之后,它们按相同的load_sequence段对数据进行分组。 我的意思是:

=# SELECT id, title, load_sequence FROM entries ORDER BY load_sequence;
 id | title | load_sequence 
----+-------+---------------
  9 | A     |             1
 10 | A     |             2
 11 | A     |             3
 13 | B     |             4
 14 | B     |             5
 12 | A     |             6
 15 | B     |             7
 16 | B     |             8

我想要小组:

=# SELECT title, string_agg(id::text, ',' ORDER BY id) FROM entries ???????????;

结果将是:

 title | string_agg  
-------+-------------
 A     | 9,10,11
 B     | 13,14
 A     | 12
 B     | 15,16

2 个答案:

答案 0 :(得分:4)

您可以使用以下查询:

SELECT title, string_agg(id::text, ',' ORDER BY id)
FROM (
  SELECT id, title, 
         ROW_NUMBER() OVER (ORDER BY load_sequence) -
         ROW_NUMBER() OVER (PARTITION BY title 
                            ORDER BY load_sequence) AS grp
  FROM entries ) AS t
GROUP BY title, grp

计算的grp字段用于标识具有连续title值的load_sequence条记录的切片。在GROUP BY子句中使用此字段,我们可以在id值上实现所需的聚合。

Demo here

答案 1 :(得分:0)

有一个技巧可以用sum作为在lag ged窗口上运行的窗函数。

这个想法是当你遇到边缘/不连续时你返回1,否则你返回0.你使用lag窗口函数检测不连续性。

SELECT title, string_agg(id::text, ', ') FROM (
  SELECT 
   id, title, load_sequence,
   sum(title_changed) OVER (ORDER BY load_sequence) AS partition_no
  FROM (
    SELECT
      id, title, load_sequence,
      CASE WHEN title = lag(title, 1) OVER (ORDER BY load_sequence) THEN 0 ELSE 1 END AS title_changed FROM entries
  ) x
) y
GROUP BY partition_no, title;