使用 postgresQL 删除逗号分隔列表中有序顺序重复项的最佳方法

Best way to remove ordered sequential duplicates in a comma separated list with postgresSQL

我有一列数据在单个字段中看起来像这样:

"a,a,b,b,c,a,b,b,b,a,a,a,a,a,a,c,a,a,b"

使用某种正则表达式或 SQL 函数我想让它看起来像这样:

"a,b,c,a,b,a,c,a,b"

本质上,我试图摆脱按顺序出现的重复值,但保留从一个值到另一个值的独特变化。

我对正则表达式的了解几乎只限于删除重复项。非常感谢任何帮助!

我的理解是:

如果字符与前一个字符相同,则要将其从字符串中删除。

所以在这种情况下我将使用 while 循环和 if 语句:

--CREATE TABLE TEST (ID VARCHAR(100));
--INSERT INTO TEST VALUES ('a,a,b,b,c,a,b,b,b,a,a,a,a,a,a,c,a,a,b');

DO $$
DECLARE  
   V_NEWSTRING VARCHAR(100) := '';  
   V_I INTEGER := 1;
   V_LENGTH INTEGER := 0;
   V_CURRENT VARCHAR(10) := '';
   V_LAST VARCHAR(10) := '';
BEGIN  
   SELECT LENGTH(ID) FROM TEST INTO V_LENGTH;
   WHILE V_I <= V_LENGTH LOOP
     SELECT SUBSTRING(ID,V_I,1) from TEST INTO V_CURRENT;
     IF V_CURRENT <> V_LAST THEN
       V_NEWSTRING = V_NEWSTRING || V_CURRENT || ',';
     END IF;
     V_LAST = V_CURRENT;
     V_I = V_I + 2;
   END LOOP;
   raise notice 'Value: %', V_NEWSTRING;
END $$;

测试结果(PostgreSQL-9.4):

使用正则表达式:

SELECT regexp_replace('a,a,b,b,c,a,b,b,b,a,a,a,a,a,a,c,a,a,b', '(\w)(,)+', '', 'g')

(\w)(,)+ mutches: (any word char) and following (, and this same word char) 不止一次...

Fiddle example
RegExr example

您可以将元素转换为行,检查前一行是否与当前行不同,然后仅保留发生变化的行。然后可以将其聚合回逗号分隔列表:

select string_agg(ch, ',' order by idx)
from (
 select u.ch, u.idx, 
        coalesce(u.ch <> lag(u.ch) over (order by u.idx), true) as is_change
 from unnest(string_to_array('a,a,b,b,c,a,b,b,b,a,a,a,a,a,a,c,a,a,b', ',')) with ordinality as u(ch, idx)
) t
where is_change

with ordinality returns 原始数组索引,以便我们在聚合时可以正确排序元素。

这也可以放入一个函数中:

create or replace function cleanup(p_input text)
  returns text
as
$$
  select string_agg(ch, ',' order by idx)
  from (
   select u.ch, u.idx, 
          coalesce(u.ch <> lag(u.ch) over (order by u.idx), true) as is_change
   from unnest(string_to_array(p_input, ',')) with ordinality as u(ch, idx)
  ) t
  where is_change;
$$
language sql;

Online example