使用 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) 不止一次...
您可以将元素转换为行,检查前一行是否与当前行不同,然后仅保留发生变化的行。然后可以将其聚合回逗号分隔列表:
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;
我有一列数据在单个字段中看起来像这样:
"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) 不止一次...
您可以将元素转换为行,检查前一行是否与当前行不同,然后仅保留发生变化的行。然后可以将其聚合回逗号分隔列表:
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;