SQL 查询中的正则表达式
RegEx in SQL Query
我有一个 SQL 包含
的查询
REGEXP_REPLACE(LISTAGG(foo.name, ',') WITHIN GROUP (ORDER BY foo.name), '([^,]+)(,)+', '') AS bar
在其SELECT
中。 LISTAGG
用“,”作为分隔符连接 foo.name 列的值,而 REGEXP_REPLACE
替换重复值。
当我更改 LISTAGG
以便使用“,”(逗号后跟一个空白字符)作为分隔符时,我该如何调整 REGEXP_REPLACE
?
编辑:
将 REGEXP_REPLACE
更改为 '([^,]+)(, )+'
似乎有效,我得到
CITRONENSÄURE, KALIUMSORBAT, PEKTIN
但是当将 REGEXP_REPLACE
更改为 '^([^,]+)(, )+$'
时,我仍然有重复项:
CITRONENSÄURE, CITRONENSÄURE, CITRONENSÄURE, CITRONENSÄURE, CITRONENSÄURE, KALIUMSORBAT, KALIUMSORBAT, KALIUMSORBAT, KALIUMSORBAT, KALIUMSORBAT, PEKTIN, PEKTIN, PEKTIN, PEKTIN, PEKTIN
所以,'([^,]+)(, )+'
是正确的吗,不管没有 ^
和 $
?
正是您在 LISTAGG
中所做的,在逗号
后添加一个 space
'([^,]+)(, )+'
虽然你应该确保它匹配整个字符串,锚定在字符串的开头 (^
) 和结尾 ($
).
'^([^,]+)(, )+$'
编辑:
至于正则表达式语法,要回答问题中的编辑,如果要删除同一行中的重复项,则必须确保它与整个值匹配。例如,'([^,]+)(, )+'
将匹配 'fo[o], [o]ther'
。所以我们也会匹配尾随的逗号(或字符串结尾)。
([^,]+), ((, |$))+
此表达式比您尝试使用的表达式安全得多。但是,在某些情况下它可能会失败。
SQL:
select regexp_replace(
listagg("name", ', ') within group (order by "name")
,'([^,]+), ((, |$))+', '')
as "bar"
from foo;
什么时候会失败?
该表达式不是 100% 安全的,因为第一个单词没有锚定,因此它可以在值的中间匹配。例如,它将从列表中删除 WORD
:
'AWORD, WORD, XXX' ==> 'AWORD, XXX'
====--^^^^--
我认为没有办法避免这种情况,因为 Oracle 实现了 POSIX ERE,并且不支持环视、字边界和 \G
断言。此外,这不是删除重复值的正确方法。对于非常长的表格,您最终会得到 ORA-01489: result of string concatenation is too long
。
对于这种情况,我建议使用 GROUP BY
或 DISTINCT
。您可以在这篇文章中阅读:SQL/mysql - Select distinct/UNIQUE but return all columns?.
我有一个 SQL 包含
的查询REGEXP_REPLACE(LISTAGG(foo.name, ',') WITHIN GROUP (ORDER BY foo.name), '([^,]+)(,)+', '') AS bar
在其SELECT
中。 LISTAGG
用“,”作为分隔符连接 foo.name 列的值,而 REGEXP_REPLACE
替换重复值。
当我更改 LISTAGG
以便使用“,”(逗号后跟一个空白字符)作为分隔符时,我该如何调整 REGEXP_REPLACE
?
编辑:
将 REGEXP_REPLACE
更改为 '([^,]+)(, )+'
似乎有效,我得到
CITRONENSÄURE, KALIUMSORBAT, PEKTIN
但是当将 REGEXP_REPLACE
更改为 '^([^,]+)(, )+$'
时,我仍然有重复项:
CITRONENSÄURE, CITRONENSÄURE, CITRONENSÄURE, CITRONENSÄURE, CITRONENSÄURE, KALIUMSORBAT, KALIUMSORBAT, KALIUMSORBAT, KALIUMSORBAT, KALIUMSORBAT, PEKTIN, PEKTIN, PEKTIN, PEKTIN, PEKTIN
所以,'([^,]+)(, )+'
是正确的吗,不管没有 ^
和 $
?
正是您在 LISTAGG
中所做的,在逗号
'([^,]+)(, )+'
虽然你应该确保它匹配整个字符串,锚定在字符串的开头 (^
) 和结尾 ($
).
'^([^,]+)(, )+$'
编辑:
至于正则表达式语法,要回答问题中的编辑,如果要删除同一行中的重复项,则必须确保它与整个值匹配。例如,'([^,]+)(, )+'
将匹配 'fo[o], [o]ther'
。所以我们也会匹配尾随的逗号(或字符串结尾)。
([^,]+), ((, |$))+
此表达式比您尝试使用的表达式安全得多。但是,在某些情况下它可能会失败。
SQL:
select regexp_replace(
listagg("name", ', ') within group (order by "name")
,'([^,]+), ((, |$))+', '')
as "bar"
from foo;
什么时候会失败?
该表达式不是 100% 安全的,因为第一个单词没有锚定,因此它可以在值的中间匹配。例如,它将从列表中删除 WORD
:
'AWORD, WORD, XXX' ==> 'AWORD, XXX'
====--^^^^--
我认为没有办法避免这种情况,因为 Oracle 实现了 POSIX ERE,并且不支持环视、字边界和 \G
断言。此外,这不是删除重复值的正确方法。对于非常长的表格,您最终会得到 ORA-01489: result of string concatenation is too long
。
对于这种情况,我建议使用 GROUP BY
或 DISTINCT
。您可以在这篇文章中阅读:SQL/mysql - Select distinct/UNIQUE but return all columns?.