是否有一个 PostgreSQL 函数让我获取一个大字符串,将其分成子字符串,然后只替换这些子字符串中的项目?

Is there a PostgreSQL function that let's me take a large string, separate it into substrings, and then only replace items in those substrings?

架构:fruit_schema

table: fruit_table

.

我在 my_column 列的一个单元格中有这个字符串。

x:y。是我不感兴趣的文字

    <Item>
    <Name>First</Name>
    <Subject>x:y. Food: Apple. x:y. </Subject>
    </Item>

    <Item>
    <Name>Second</Name>
    <Subject>x:y. x:y. Food: Apple. Type: Red. x:y. x:y.</Subject>
    </Item>

我想将 'Type: Red' 添加到第一项。 到目前为止我已经写了这个查询:

    DO
    $$
    DECLARE
        oldItem varchar := 'Food: Apple.';
        newItem varchar;
    BEGIN
        newItem  = 'Food: Apple. Type: Red.';

        UPDATE 
            fruit_schema.fruit_table AS profile
        SET 
            my_column = REPLACE(my_column, oldItem, newItem)
        WHERE
            profile.my_column ILIKE '%First%</Item>%';
    END$$;

但是,这是我的输出:

    <Item>
    <Name>First</Name>
    <Subject>x:y. Food: Apple. Type: Red. x:y. </Subject>
    </Item>

    <Item>
    <Name>Second</Name>
    <Subject>x:y. x:y. Food: Apple. Type: Red. Type: Red. x:y. x:y.</Subject>
    </Item>

第一项正确更新,但第二项被替换为副本 "Type: Red"。无论如何,我可以将这个巨大的字符串分别拆分为第一项和第二项吗?我只想处理第一个子字符串,从 <Name>First</Name></Item>

我想为我想要处理的所有其他项目执行此操作。 如果可能的话,我想避免手动计算项目中的字符数。

对于特定的主题,你可以做一个regexp_replace:

SELECT regexp_replace('<Item>
    <Name>First</Name>
    <Subject>x:y. Food: Apple. x:y. </Subject>
    </Item>

    <Item>
    <Name>Second</Name>
    <Subject>x:y. x:y. Food: Apple. Type: Red. x:y. x:y.</Subject>
    </Item>', 'Food: Apple\. ', 'Food: Apple. Type: Red ', '');

如果您的替换内容不同,您可能需要进行一些调整

您需要 regexp_replace() 函数和 negative lookahead,例如:

# select replace(e'aaa\naaa bbb', 'aaa', 'aaa bbb');
┌─────────────┐
│   replace   │
├─────────────┤
│ aaa bbb    ↵│
│ aaa bbb bbb │
└─────────────┘

# select regexp_replace(e'aaa\naaa bbb', 'aaa(\s+)(?!bbb)', 'aaa bbb', 'g');
┌────────────────┐
│ regexp_replace │
├────────────────┤
│ aaa bbb       ↵│
│ aaa bbb        │
└────────────────┘

使用您的数据:

# select regexp_replace(
  '<Item><Name>First</Name>
     <Subject>x:y. Food: Apple. x:y. </Subject>
   </Item>
   <Item><Name>Second</Name>
     <Subject>x:y. x:y. Food: Apple. Type: Red. x:y. x:y.</Subject>
   </Item>
   <Item><Name>Third</Name>
     <Subject>x:y. Food: Apple. x:y. </Subject>
   </Item>',
  'Food: Apple\.(\s+)(?!Type: Red\.)',
  'Food: Apple. Type: Red.', 'g');
┌─────────────────────────────────────────────────────────────────────┐
│                           regexp_replace                            │
├─────────────────────────────────────────────────────────────────────┤
│ <Item>\n<Name>First</Name>                                         ↵│
│      <Subject>x:y. Food: Apple. Type: Red. x:y. </Subject>         ↵│
│    </Item>                                                         ↵│
│    <Item>\n<Name>Second</Name>                                     ↵│
│      <Subject>x:y. x:y. Food: Apple. Type: Red. x:y. x:y.</Subject>↵│
│    </Item>                                                         ↵│
│    <Item>\n<Name>Third</Name>                                      ↵│
│      <Subject>x:y. Food: Apple. Type: Red. x:y. </Subject>         ↵│
│    </Item>                                                          │
└─────────────────────────────────────────────────────────────────────┘

更新:如何仅替换特定项目的文本:

with t(x) as (values('<Item><Name>First</Name>
     <Subject>x:y. Food: Apple. x:y. </Subject>
   </Item>
   <Item><Name>Second</Name>
     <Subject>x:y. x:y. Food: Apple. Type: Red. x:y. x:y.</Subject>
   </Item>
   <Item><Name>Third</Name>
     <Subject>x:y. Food: Apple. x:y. </Subject>
   </Item>'))
select
    string_agg(
        case
            when xx like any(array['%<Name>Third</Name>%','%<Name>Second</Name>%']) then
                regexp_replace(xx, 'Food: Apple\.(\s+)(?!Type: Red\.)', 'Food: Apple. Type: Red.', 'g')
            else xx
        end || '</Item>', e'\n')
from t, unnest(string_to_array(replace(x, e'\n', ''), '</Item>')) as xx
where xx <> '';
┌───────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│                                                string_agg                                                 │
├───────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ <Item><Name>First</Name>     <Subject>x:y. Food: Apple. x:y. </Subject>   </Item>                        ↵│
│    <Item><Name>Second</Name>     <Subject>x:y. x:y. Food: Apple. Type: Red. x:y. x:y.</Subject>   </Item>↵│
│    <Item><Name>Third</Name>     <Subject>x:y. Food: Apple. Type: Red. x:y. </Subject>   </Item>           │
└───────────────────────────────────────────────────────────────────────────────────────────────────────────┘