【发布时间】:2017-03-08 15:18:48
【问题描述】:
我有一个名为“A B A A C D”的列表。我的预期结果是“A B C D”。到目前为止,我已经从网络上发现了
regexp_replace(l_user ,'([^,]+)(,[ ]*\1)+', '\1');
表达式。但这是用于 , 分隔的列表。为了使其成为空格分隔列表,需要进行哪些修改。无需考虑顺序。
【问题讨论】:
我有一个名为“A B A A C D”的列表。我的预期结果是“A B C D”。到目前为止,我已经从网络上发现了
regexp_replace(l_user ,'([^,]+)(,[ ]*\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
)
【讨论】:
假设您希望将组件字符串保持在它们第一次出现的顺序(而不是按字母顺序重新排序 - 您的示例在这方面选择不当,因为两者都导致相同的结果),问题更多复杂,因为您也必须跟踪订单。然后对于每个字母,您必须只保留第一次出现 - 这是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
;
【讨论】:
:str,只要我有列名str 的地方写:str。注意 - 如果您需要在一个表上执行此操作,并且输入表有不止一行,那么“连接依据”查询会稍微复杂一些。
row_number()) .
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))