0

我有一个 SQL 查询,其中包含

REGEXP_REPLACE(LISTAGG(foo.name, ',') WITHIN GROUP (ORDER BY foo.name), '([^,]+)(,\1)+', '\1') AS bar

在其SELECT. LISTAGG将 foo.name 列的值与 ',' 作为分隔符连接,同时REGEXP_REPLACE替换重复项。

当我更改LISTAGG“,”(逗号后跟空格字符)用作分隔符时,我必须如何调整REGEXP_REPLACE

编辑:

当改变REGEXP_REPLACE'([^,]+)(, \1)+'似乎工作,我得到

CITRONENSÄURE、KALIUMSORBAT、PEKTIN

但是当更改为时REGEXP_REPLACE'^([^,]+)(, \1)+$'我仍然有重复项:

CITRONENSÄURE、CITRONENSÄURE、CITRONENSÄURE、CITRONENSÄURE、CITRONENSÄURE、KALIUMSORBAT、KALIUMSORBAT、KALIUMSORBAT、KALIUMSORBAT、KALIUMSORBAT、PEKTIN、PEKTIN、PEKTIN、PEKTIN、PEKTIN

那么,'([^,]+)(, \1)+'不管有没有^和,是正确的$吗?

4

1 回答 1

1

正是你所做的LISTAGG,在逗号后添加一个空格

'([^,]+)(, \1)+'

尽管您应该确保它与整个字符串匹配,锚定在字符串的开头 ( ^) 和结尾 ( $)。

'^([^,]+)(, \1)+$'


编辑:
至于正则表达式语法,要回答问题中的编辑,如果要删除同一行中的重复项,则必须确保它与整个值匹配。例如,'([^,]+)(, \1)+'将匹配'fo[o], [o]ther'. 所以我们也会匹配尾随的逗号(或字符串的结尾)。

([^,]+), (\1(, |$))+

此表达式比您尝试使用的表达式安全得多。但是,在少数情况下它可能会失败。

SQL:

select regexp_replace(
    listagg("name", ', ') within group (order by "name")
    ,'([^,]+), (\1(, |$))+', '\1\3')
as "bar"
from foo;

SQLfiddle 中的 DEMO



什么时候能失败?
该表达式不是 100% 安全的,因为第一个单词没有锚定,因此它可以匹配一个值的中间。例如,它将WORD从列表中删除:

'AWORD, WORD, XXX'  ==>  'AWORD, XXX'
  ====--^^^^--

我认为没有办法避免这种情况,因为 Oracle 实现了 POSIX ERE,并且不支持环视、单词边界或\G断言。此外,这不是删除重复值的正确方法。如果桌子真的很长,你最终会在ORA-01489: result of string concatenation is too long.

我建议在这种情况下使用GROUP BYor DISTINCT。您可以在这篇文章中了解它:SQL/mysql - Select distinct/UNIQUE but return all columns? .

于 2015-09-23T07:29:14.180 回答