可延迟、不区分大小写的唯一约束

Posted

技术标签:

【中文标题】可延迟、不区分大小写的唯一约束【英文标题】:Deferrable, case-insensitive unique constraint 【发布时间】:2013-05-30 03:25:30 【问题描述】:

在 PostgreSQL 中是否可以在字符列上创建可延迟的唯一约束,但不区分大小写?

让我们假设以下基本表格:

CREATE TABLE sample_table ( 
   my_column VARCHAR(100)
);

如果不需要可延迟约束,那么就很简单,用函数创建唯一索引,例如:

CREATE UNIQUE INDEX my_unique_index ON sample_table(UPPER(my_column));

延迟约束检查需要显式创建约束,例如:

ALTER TABLE sample_table 
 ADD CONSTRAINT my_unique_constraint UNIQUE(my_column)
 DEFERRABLE INITIALLY IMMEDIATE;

不幸的是,不可能在唯一约束中使用任意函数。

一种可能的解决方法是创建与my_column 内容相同但大写的附加列,在每次更新/插入后通过触发器进行更新,然后在此人工列上创建可延迟的唯一约束。然而,这听起来像一个非常丑陋的 hack。

或者,应该可以使用CREATE CONSTRAINT TRIGGER 并手动检查不区分大小写的唯一性(当然仍然需要常规索引)。对于如此简单(我想也很流行)的要求,这听起来有点过于复杂了。

有没有更简单和/或更优雅的方法来解决这个限制?

【问题讨论】:

你的 Postgres 版本? 目前是 9.1。但是,如果在较新的版本上有一个不错的解决方案,我会非常乐意阅读它:) 检查EXCLUDE 约束。它们可以设置为不区分大小写的UNIQUE +1 非常有趣的问题! @Igor 谢谢,这很有趣——我不知道EXCLUDE 的限制(可能没有花足够的时间处理 9.x 文档)。我发现它在其他情况下也非常有用。 【参考方案1】:

您可以通过使用由同名附加模块提供的特殊类型citext 来规避限制。引用手册:

citext 模块提供了不区分大小写的字符串类型, 文案。本质上,它在比较值时在内部调用 lower。 否则,它的行为几乎与text 完全相同。

它完全解决了您的情况。每个数据库运行一次:

CREATE EXTENSION citext;

那么你可以:

CREATE TABLE sample_table ( 
   my_column citext
  ,CONSTRAINT my_unique_constraint UNIQUE(my_column)
   DEFERRABLE INITIALLY IMMEDIATE
);

【讨论】:

太好了,这正是我在这种情况下想要的(仍然希望有一些解决方案允许在约束中发挥作用;))。对于 Ubuntu 用户 - citextpostgresql-contrib 包中。 我不应该添加扩展来使字符串类型不区分大小写...... postgress 应该提供更好的解决方案 @Leonel:您的意见得到了适当的注意。不过,不确定它如何转化为对我的回答的反对。如果您有特定的问题要解决,请考虑发布问题,有多种情况可以在不安装扩展程序citext 的情况下解决。但是安装它并没有错,这实际上只是CREATE EXTENSION citext; 的问题。该模块是发行版的一部分,由同一个团队维护和发布,并进行了彻底的测试。它不在核心版本中的唯一原因是大多数人不需要它。它是“Postgres”,顺便说一句,是 PostgreSQL 的缩写。 您对citextunique 约束一起使用时的实际性能开销有何看法?因为它似乎在内部调用了 C str_tolower():***.com/questions/31133603/…。

以上是关于可延迟、不区分大小写的唯一约束的主要内容,如果未能解决你的问题,请参考以下文章

oracle - 唯一约束 ORA-00001 与区分大小写的记录

您如何向用户公开区分大小写?

django orm总结--解决查询结果不区分大小写问题

如何使字段不区分大小写且唯一?

Mongo唯一索引不区分大小写

Mongoose 模式:验证唯一字段,不区分大小写