如何在 postgres 的文本列上添加唯一约束(忽略特殊字符)?
How to add an unique constraint (ignoring special characters) on a text column in postgres?
如何在 Postgres 中的文本列上添加唯一约束(忽略特殊字符)?
CREATE TABLE my_table(
SomeTextColumn citext
CONSTRAINT person_u_1 UNIQUE (SomeTextColumn)
);
在上面的 table 中,我试图添加一个唯一性约束,该约束将通过忽略传入数据中的特殊字符来寻找唯一性
For example:
1. HelloWorld --> Gets inserted successfully
2. Hello World --> Should fail with duplicate constraint
2. Hello%$^&*W^%orld --> Should fail with duplicate constraint
您可以创建一个 unique
索引来执行检查:
create unique index t_txt_unique on t(regexp_replace(txt, '\W', '', 'g'));
正则表达式从字符串中删除所有非单词字符,仅保留字母数字字符和下划线 _
。您可以根据需要将字符class调整为
create table t (id int, txt citext);
create unique index t_txt_unique on t(regexp_replace(txt, '\W', '', 'g'));
insert into t values(1, 'HelloWorld');
-- ok
insert into t values(1, 'Hello World');
-- ERROR: duplicate key value violates unique constraint "t_txt_unique"
-- DETAIL: Key (regexp_replace(txt, '\W'::text, ''::text, 'g'::text))=(HelloWorld) already exists.
insert into t values(1, 'Hello%$^&*W^%orld');
-- ERROR: duplicate key value violates unique constraint "t_txt_unique"
-- DETAIL: Key (regexp_replace(txt, '\W'::text, ''::text, 'g'::text))=(HelloWorld) already exists.
insert into t values(1, 'Hello Mars');
-- ok
这个问题比较老,但我认为一些额外的注释可能会有用...
- TEXT 的唯一性总是有问题,因为文本区分大小写(不仅在 PostgreSQL 中)。
您可以获得重复项,因为“HelloWorld”与“HELLOWORLD”不同。因此,如果您在数据库的文本字段上创建 UNIQUE INDEX,您可能希望添加 UPPER 函数:
CREATE UNIQUE INDEX t_txt_unique ON t(REGEXP_REPLACE(UPPER(txt), '\W', '', 'g'));
- 您可能希望使用以下 REGEXP_REPLACE 选项仅保留字符 0-9 和 A-Z(删除变音符号):
CREATE UNIQUE INDEX t_txt_unique ON t(REGEXP_REPLACE(UPPER(txt), '[^0-9A-Z]', '', 'g'));
- 如果您想将变音符号保留为通用字符(Ü --> U、Ä --> A 等),您可以加入 UNACCENT 函数(https://www.postgresql.org/docs/current/unaccent.html - 这是您需要的扩展添加到 PostgreSQL 但我也可能会帮助您搜索一些东西 - 请记住,只有超级用户或其他管理员用户可能 able/allowed 添加扩展):
CREATE EXTENSION IF NOT EXISTS unaccent WITH SCHEMA public;
CREATE UNIQUE INDEX t_txt_unique ON t(REGEXP_REPLACE(UPPER(UNACCENT(txt)), '[^0-9A-Z]', '', 'g'));
SQL-代码
--
-- Check REGEXP_REPLACE to remove unwanted characters.
-- Test-String: '^°!"§$%&/()=?`+#äöüÜÖÄ',.-_:;@ABµC123abc123'
--
SELECT '^°!"§$%&/()=?`+#äöüÜÖÄ'',.-_:;@ABµC123abc123' AS original_text
,REGEXP_REPLACE( UPPER( '^°!"§$%&/()=?`+#äöüÜÖÄ'',.-_:;@ABµC123abc123' ), '\W', '', 'g') AS replace_word
,REGEXP_REPLACE( UPPER( '^°!"§$%&/()=?`+#äöüÜÖÄ'',.-_:;@ABµC123abc123' ), '[^0-9A-Z]', '', 'g') AS replace_upper_keep_num_a_to_z
,REGEXP_REPLACE( UPPER(UNACCENT( '^°!"§$%&/()=?`+#äöüÜÖÄ'',.-_:;@ABµC123abc123' )), '[^0-9A-Z]', '', 'g') AS replace_keep_num_a_to_z_umlaut
;
上面SQL代码的结果为HTMLtable
最终结果中的降价 table 太复杂了(预览有效)。
<table border="1"><tr BGCOLOR="#CCCCFF"><th>original_text</th><th>replace_word</th><th>replace_upper_keep_num_a_to_z</th><th>replace_keep_num_a_to_z_umlaut</th></tr>
<tr><td>^°!"§$%&/()=?`+#äöüÜÖÄ',.-_:;@<>ABµC123abc123</td><td>ÄÖÜÜÖÄ_AB?C123ABC123</td><td>ABC123ABC123</td><td>AOUUOAABC123ABC123</td></tr>
</table>
您可能已经注意到,第二列中的字符“µ”已使用“\W”替换转换为大写 'M',这有点奇怪。
如何在 Postgres 中的文本列上添加唯一约束(忽略特殊字符)?
CREATE TABLE my_table(
SomeTextColumn citext
CONSTRAINT person_u_1 UNIQUE (SomeTextColumn)
);
在上面的 table 中,我试图添加一个唯一性约束,该约束将通过忽略传入数据中的特殊字符来寻找唯一性
For example:
1. HelloWorld --> Gets inserted successfully
2. Hello World --> Should fail with duplicate constraint
2. Hello%$^&*W^%orld --> Should fail with duplicate constraint
您可以创建一个 unique
索引来执行检查:
create unique index t_txt_unique on t(regexp_replace(txt, '\W', '', 'g'));
正则表达式从字符串中删除所有非单词字符,仅保留字母数字字符和下划线 _
。您可以根据需要将字符class调整为
create table t (id int, txt citext);
create unique index t_txt_unique on t(regexp_replace(txt, '\W', '', 'g'));
insert into t values(1, 'HelloWorld');
-- ok
insert into t values(1, 'Hello World');
-- ERROR: duplicate key value violates unique constraint "t_txt_unique"
-- DETAIL: Key (regexp_replace(txt, '\W'::text, ''::text, 'g'::text))=(HelloWorld) already exists.
insert into t values(1, 'Hello%$^&*W^%orld');
-- ERROR: duplicate key value violates unique constraint "t_txt_unique"
-- DETAIL: Key (regexp_replace(txt, '\W'::text, ''::text, 'g'::text))=(HelloWorld) already exists.
insert into t values(1, 'Hello Mars');
-- ok
这个问题比较老,但我认为一些额外的注释可能会有用...
- TEXT 的唯一性总是有问题,因为文本区分大小写(不仅在 PostgreSQL 中)。
您可以获得重复项,因为“HelloWorld”与“HELLOWORLD”不同。因此,如果您在数据库的文本字段上创建 UNIQUE INDEX,您可能希望添加 UPPER 函数:
CREATE UNIQUE INDEX t_txt_unique ON t(REGEXP_REPLACE(UPPER(txt), '\W', '', 'g'));
- 您可能希望使用以下 REGEXP_REPLACE 选项仅保留字符 0-9 和 A-Z(删除变音符号):
CREATE UNIQUE INDEX t_txt_unique ON t(REGEXP_REPLACE(UPPER(txt), '[^0-9A-Z]', '', 'g'));
- 如果您想将变音符号保留为通用字符(Ü --> U、Ä --> A 等),您可以加入 UNACCENT 函数(https://www.postgresql.org/docs/current/unaccent.html - 这是您需要的扩展添加到 PostgreSQL 但我也可能会帮助您搜索一些东西 - 请记住,只有超级用户或其他管理员用户可能 able/allowed 添加扩展):
CREATE EXTENSION IF NOT EXISTS unaccent WITH SCHEMA public;
CREATE UNIQUE INDEX t_txt_unique ON t(REGEXP_REPLACE(UPPER(UNACCENT(txt)), '[^0-9A-Z]', '', 'g'));
SQL-代码
-- -- Check REGEXP_REPLACE to remove unwanted characters. -- Test-String: '^°!"§$%&/()=?`+#äöüÜÖÄ',.-_:;@ABµC123abc123' -- SELECT '^°!"§$%&/()=?`+#äöüÜÖÄ'',.-_:;@ABµC123abc123' AS original_text ,REGEXP_REPLACE( UPPER( '^°!"§$%&/()=?`+#äöüÜÖÄ'',.-_:;@ABµC123abc123' ), '\W', '', 'g') AS replace_word ,REGEXP_REPLACE( UPPER( '^°!"§$%&/()=?`+#äöüÜÖÄ'',.-_:;@ABµC123abc123' ), '[^0-9A-Z]', '', 'g') AS replace_upper_keep_num_a_to_z ,REGEXP_REPLACE( UPPER(UNACCENT( '^°!"§$%&/()=?`+#äöüÜÖÄ'',.-_:;@ABµC123abc123' )), '[^0-9A-Z]', '', 'g') AS replace_keep_num_a_to_z_umlaut ;
上面SQL代码的结果为HTMLtable 最终结果中的降价 table 太复杂了(预览有效)。
<table border="1"><tr BGCOLOR="#CCCCFF"><th>original_text</th><th>replace_word</th><th>replace_upper_keep_num_a_to_z</th><th>replace_keep_num_a_to_z_umlaut</th></tr>
<tr><td>^°!"§$%&/()=?`+#äöüÜÖÄ',.-_:;@<>ABµC123abc123</td><td>ÄÖÜÜÖÄ_AB?C123ABC123</td><td>ABC123ABC123</td><td>AOUUOAABC123ABC123</td></tr>
</table>
您可能已经注意到,第二列中的字符“µ”已使用“\W”替换转换为大写 'M',这有点奇怪。