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

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

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

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

【问题讨论】:

    标签: sql regex oracle


    【解决方案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))
    猜你喜欢
    • 2016-10-26
    • 2014-12-27
    • 1970-01-01
    • 2018-08-07
    • 2018-05-03
    • 2023-03-03
    • 1970-01-01
    • 2019-04-05
    • 1970-01-01
    相关资源
    最近更新 更多