如何通过 Oracle regexp_replace 从空格分隔列表中删除重复项? [复制]

Posted

技术标签:

【中文标题】如何通过 Oracle regexp_replace 从空格分隔列表中删除重复项? [复制]【英文标题】:How to remove duplicates from space separated list by Oracle regexp_replace? [duplicate] 【发布时间】:2017-03-08 15:18:48 【问题描述】:

我有一个名为“A B A A C D”的列表。我的预期结果是“A B C D”。到目前为止,我已经从网络上发现了

regexp_replace(l_user ,'([^,]+)(,[ ]*\1)+', '\1');

表达式。但这是用于 , 分隔的列表。为了使其成为空格分隔列表,需要进行哪些修改。无需考虑顺序。

【问题讨论】:

【参考方案1】:

如果我理解得很好,您不仅需要用空格替换“,”,还需要以更智能的方式删除重复项。

如果我修改该表达式以使用空格而不是“,”,我会得到

select regexp_replace('A B A A C D' ,'([^ ]+)( [ ]*\1)+', '\1') from dual

这给了'A B A C D',而不是你需要的。

获得所需结果的方法可能如下,有点复杂:

with string(s) as ( select 'A B A A C D' from dual)    
    select listagg(case when rn = 1 then str end, ' ') within group (order by lev)
    from (
            select str,  row_number() over (partition by str order by 1) rn, lev
            from (
                SELECT trim(regexp_substr(s, '[^ ]+', 1, level)) str,
                       level as lev
                  FROM string
                CONNECT BY instr(s, ' ', 1, level - 1) > 0
                )
         )

我的主要问题是我无法构建一个检查非相邻重复项的正则表达式,所以我需要拆分字符串,检查重复项,然后再次聚合非重复值,保持顺序。

如果您不介意结果字符串中标记的顺序,可以简化:

with string(s) as ( select 'A B A A C D' from dual)
select listagg(str, ' ') within group (order by 1)
from (
        SELECT distinct trim(regexp_substr(s, '[^ ]+', 1, level)) as str
          FROM string
        CONNECT BY instr(s, ' ', 1, level - 1) > 0
     )

【讨论】:

不用等太久。 :-) 但是,唯一的改进在于外部查询 - 仅使用 rn=1 的行。在这种情况下,这是唯一可能的简化。 @mathguy - 我有种嵌套太多的感觉... :) 仍然在想一些正则表达式组合是否可以避免分裂,但希望不大... 虽然长选择嵌套会很受欢迎。我仍然可以在正确的解决方案上牺牲处理时间。谢谢【参考方案2】:

假设您希望将组件字符串保持在它们第一次出现的顺序(而不是按字母顺序重新排序 - 您的示例在这方面选择不当,因为两者都导致相同的结果),问题更多复杂,因为您也必须跟踪订单。然后对于每个字母,您必须只保留第一次出现 - 这是row_number() 有帮助的地方。

with
     inputs ( str ) as ( select 'A B A A C D' from dual)
-- end test data; solution begins below this line
select listagg(token, ' ') within group (order by id) as new_str
from (
       select level as id, regexp_substr(str, '[^ ]+', 1, level) as token,
              row_number() over ( 
                             partition by regexp_substr(str, '[^ ]+', 1, level)
                             order by level ) as rn

       from   inputs
       connect by regexp_substr(str, '[^ ]+', 1, level) is not null
     )
where rn = 1
;

【讨论】:

订单不是问题。如果 'A B A A C D' 是一个变量,如何将它传递到这里 什么样的变量? (或者您的意思是表中列中的值?)如果它是绑定变量,例如:str,只要我有列名str 的地方写:str。注意 - 如果您需要在一个表上执行此操作,并且输入表有不止一行,那么“连接​​依据”查询会稍微复杂一些。 另外,如果结果字符串中标记的顺序不必与初始字符串相关,那么解决方案可以避免子查询-外部查询结构(以及使用row_number()) .【参考方案3】:

Xquery?

select xmlquery('string-join(distinct-values(ora:tokenize(.," ")), " ")' passing  'A B A A C D' returning content) result  from dual

【讨论】:

在一个系统上需要什么来完成这项工作?我刚刚在我的机器上试了一下,显示的输出是(XMLTYPE),而不是A B C D 环绕xmlcast( xmlquery(... ) as varchar2(2000))

以上是关于如何通过 Oracle regexp_replace 从空格分隔列表中删除重复项? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

如何通过 Oracle regexp_replace 中的正则表达式从逗号分隔列表中删除重复项? [复制]

如何在 Oracle 中使用 REGEXP_REPLACE 删除单词

试图了解oracle REGEXP_REPLACE如何工作

如何在 edb 中使用相同的 REGEXP_REPLACE(Oracle sql)

oracle 使用 REGEXP_REPLACE 函数替换子字符

Regexp_replace :从 Oracle 中的“+”分隔字符串中删除重复项 [重复]