简体   繁体   English

Postgresql 从另一列中减去一列中的逗号分隔字符串

[英]Postgresql subtract comma separated string in one column from another column

The format is like:格式如下:

col1 col1 col2 col2
V1,V2,V3,V4,V5,V6 V1,V2,V3,V4,V5,V6 V4,V1,V6 V4,V1,V6
V1,V2,V3 V1,V2,V3 V2,V3 V2,V3

I want to create another column called col3 which contains the subtraction of two columns.我想创建另一个名为 col3 的列,其中包含两列的减法。

What I have tried:我试过的:

UPDATE myTable
SET col3=(replace(col1,col2,''))

It works well for rows like row2 since the order of replacing patterns matters.它适用于像 row2 这样的行,因为替换模式的顺序很重要。

I was wondering if there's a perfect way to achieve the same goal for rows like row1.我想知道是否有一种完美的方法可以为 row1 之类的行实现相同的目标。

So the desired output would be:所以所需的输出将是:

col1 col1 col2 col2 col3 col3
V1,V2,V3,V4,V5,V6 V1,V2,V3,V4,V5,V6 V4,V1,V6 V4,V1,V6 V2,V3,V5 V2,V3,V5
V1,V2,V3 V1,V2,V3 V2,V3 V2,V3 V1 V1

Any suggestions would be appreciated!任何建议,将不胜感激!

Split values into tables, subtract sets and then assemble it back.将值拆分为表格,减去集合,然后将其组合回来。 Everything is possible as an expression defining new query column.一切都可以作为定义新查询列的表达式。

with t (col1,col2) as (values
('V1,V2,V3,V4,V5,V6','V4,V1,V6'),
('V1,V2,V3','V2,V3')
)
select col1,col2
     , (
         select string_agg(v,',')
         from (
           select v from unnest(string_to_array(t.col1,',')) as a1(v)
           except
           select v from unnest(string_to_array(t.col2,',')) as a2(v)
         ) x
        )
from t

DB fiddle 数据库小提琴

You will have to unnest the elements then apply an EXCEPT clause on the "unnested" rows and aggregate back:您必须取消嵌套元素,然后在“未嵌套”行上应用 EXCEPT 子句并聚合回来:

select col1, 
       col2, 
       (select string_agg(item,',' order by item)
        from (
           select *
           from string_to_table(col1, ',') as c1(item)
           except 
           select *
           from string_to_table(col2, ',') as c2(item)
        ) t)
from the_table;        
           

I wouldn't store that result in a separate column, but if you really need to introduce even more problems by storing another comma separated list.我不会将该结果存储在单独的列中,但如果您确实需要通过存储另一个逗号分隔列表来引入更多问题。

update the_table
  set col3 =  (select string_agg(item,',' order by item)
               from (
                  select *
                  from string_to_table(col1, ',') as c1(item)
                  except 
                  select *
                  from string_to_table(col2, ',') as c2(item)
               ) t)
;

string_to_table() requires Postgres 14 or newer. string_to_table()需要 Postgres 14 或更高版本。 If you are using an older version, you need to use unnest(string_to_array(col1, ',')) instead如果您使用的是旧版本,则需要使用unnest(string_to_array(col1, ','))代替


If you need that a lot, consider creating a function:如果您需要很多,请考虑创建一个函数:

create function remove_items(p_one text, p_other text)
  returns text
as
$$
  select string_agg(item,',' order by item)
  from (
     select *
     from string_to_table(col1, ',') as c1(item)
     except 
     select *
     from string_to_table(col2, ',') as c2(item)
  ) t;
$$
language sql
immutable;

Then the above can be simplified to:那么上面的可以简化为:

select col1, col2, remove_items(col1, col2)
from the_table;

Note, POSTGRESQL is not my forte, but thought I'd have a go at it.请注意, POSTGRESQL不是我的强项,但我想我会尝试一下。 Try:尝试:

SELECT col1, col2, RTRIM(REGEXP_REPLACE(Col1,CONCAT('\m(?:', REPLACE(Col2,',','|'),')\M,?'),'','g'), ',') as col3 FROM myTable

See an online fidle .查看在线文件


The idea is to use a regular expession to replace all values, based on following pattern:这个想法是使用常规表达式来替换所有值,基于以下模式:

  • \m - Word-boundary at start of word; \m - 单词开头的单词边界;
  • (?:V4|V1|V6) - A non-capture group that holds the alternatives from col2; (?:V4|V1|V6) - 一个非捕获组,包含 col2 的备选方案;
  • \M - Word-boundary at end of word; \M - 词尾的词边界;
  • ,? - Optional comma. - 可选逗号。

When replaced with nothing we need to clean up a possible trailing comma with RTRIM() .当替换为空时,我们需要使用RTRIM()清理可能的尾随逗号。 See an online demo where I had to replace the word-boundaries with the \b word-boundary to showcase the outcome.请参阅在线演示,我必须将单词边界替换为\b单词边界以展示结果。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM