我有一个包含一团文本的数据列。例如,"约翰·多伊住在翡翠街"。我想从字符串中删除文本列表。我有一些这样的清单(住,在,街道)。我想选择一个新的数据列,将文本转换为"John Doe Emerald"。
首先,您可以基于replace
函数创建一个AGGREGATE
函数:
CREATE OR REPLACE FUNCTION replace(x text, y text, old_txt text, new_txt text)
RETURNS text LANGUAGE sql IMMUTABLE AS
$$
SELECT replace(COALESCE(x,y), old_txt, new_txt)
$$ ;
DROP AGGREGATE IF EXISTS replace_agg (text, text, text) CASCADE ;
CREATE AGGREGATE replace_agg (text, text, text)
(
sfunc = replace
, stype = text
);
然后你可以在SELECT语句中迭代replace_agg
函数:
SELECT replace_agg (your_table.your_column, k.keyword, '')
FROM (SELECT 'John Doe lives in Emerald Street' as your_column) as your_table
CROSS JOIN (SELECT unnest(array['lives', 'in', 'Street']) as keyword) as k
,结果如下:
'John Doe Emerald'
假设简单的情况:
- 在表和替换字符串中,单词由单个空格字符分隔。
- 没有自然语言中的标点符号。无前后噪声。
- 区分大小写匹配。
- 删除所有匹配项(而不是只有第一个)。
和如下表:
CREATE TABLE strings(id serial PRIMARY KEY, string text);
INSERT INTO strings(string) VALUES
('John Doe lives in Emerald Street')
, ('John Doe lives in Emerald Street as john DOE');
regexp_replace()
一个简短的解决方案:
SELECT *, rtrim(regexp_replace(string, '(John|Doe|Emerald) ?', '', 'g')) FROM strings;
|
分隔正则表达式中的可选分支。
相关:
- 使用PostgreSQL 修剪尾随空格
或者,使用原始替换字符串作为输入:
SELECT *, rtrim(regexp_replace(string, '(' || replace('John Doe Emerald', ' ', '|') || ') ?', '', 'g')) FROM strings;
设置操作正则表达式通常开销很大。这可能更快(最小形式):
SELECT s.id, string_agg(word, ' ') AS string2
FROM strings s, unnest(string_to_array(s.string, ' ')) word
WHERE word <> ALL (string_to_array('John Doe Emerald', ' '))
GROUP BY 1
ORDER BY 1;
避免歧义,并确保保持原顺序:
SELECT s.id, string_agg(word, ' ' ORDER BY ord) AS string2
FROM strings s, unnest(string_to_array(s.string, ' ')) WITH ORDINALITY AS t(word, ord)
WHERE t.word <> ALL (string_to_array('John Doe Emerald', ' '))
GROUP BY 1
ORDER BY 1;
:
- PostgreSQL unnest() with element number
在单独的子查询中ORDER BY
通常更快:
SELECT sub.id, string_agg(sub.word, ' ') AS string2
FROM (
SELECT s.id, t.word
FROM strings s, unnest(string_to_array(s.string, ' ')) WITH ORDINALITY AS t(word, ord)
WHERE t.word <> ALL (string_to_array('John Doe Emerald', ' '))
ORDER BY s.id, t.ord
) sub
GROUP BY 1
ORDER BY 1;
通常更容易与LATERAL
子查询集成:
SELECT s.id, sub.string2
FROM strings s
CROSS JOIN LATERAL (
SELECT string_agg(t.word, ' ' ORDER BY t.ord) AS string2
FROM unnest(string_to_array(s.string, ' ')) WITH ORDINALITY AS t(word, ord)
WHERE t.word <> ALL (string_to_array('John Doe Emerald', ' '))
) sub
ORDER BY 1;
这样,我们就不需要在外层的SELECT
中使用GROUP BY
了。
db<此处小提琴>此处小提琴>