类似字符的唯一约束违规
Posted
技术标签:
【中文标题】类似字符的唯一约束违规【英文标题】:Unique constraint violation on similar characters 【发布时间】:2018-07-11 22:12:48 【问题描述】:我对 MariaDB 中的主键有疑问(我希望 mysql 也一样)。我正在构建一个 Django 应用程序,其中一些重要的表由 Django 使用以下 SQL 创建:
CREATE TABLE table_name
(
term VARCHAR(64) NOT NULL PRIMARY KEY,
enabled TINYINT(1) NOT NULL,
added DATE NOT NULL,
verified DATE NOT NULL
) ENGINE = InnoDB;
如果我在此表中插入两行,其中term
第一行是ó
,另一行是o
,我会收到错误[23000][1062] Duplicate entry 'o' for key 'PRIMARY'
。其他类似的字母也会发生相同的行为,例如 e
和 é
。
我真的觉得这种行为很奇怪,因为 SQLite 没有问题。
所以现在的问题是:如何让数据库引擎将它们视为不同的值?
额外问题:我可以期待 PostgreSQL 的相同行为吗?
我已经在 SQL 中尝试过这个,而不仅仅是 Django。
【问题讨论】:
【参考方案1】:好吧,碰巧,我在写这个问题时自己回答了这个问题。我意识到我没有尝试过字符集utf8mb4
和排序规则utf8mb4_bin
的组合,我记得_bin
排序规则在二进制级别比较字符,没有任何规则使相似字符看起来相似。所以用
CREATE DATABASE [database_name] CHARACTER SET = 'utf8mb4' COLLATE = 'utf8mb4_bin';
成功了。或者我可以用
创建每个表CREATE TABLE [table_name] CHARACTER SET = 'utf8mb4' COLLATE = 'utf8mb4_bin';
,但是在数据库中设置它是这里唯一可行的选择,因为 Django 负责创建表。
更新:
关于奖励问题,简短的回答是:不。
详情见下方nick-barnes评论。
更新 2:
Microsoft SQL Server(在 SQL Server 2017 CU3 上测试)使用排序规则来比较字符串是否相等,因此需要使用二进制排序规则(例如 Latin1_General_BIN
)来解决此服务器上的这个问题。
【讨论】:
Postgres 在测试字符串是否相等时总是使用二进制比较,因此不会混淆o
是否等于ó
(在主键列中或其他任何地方) .排序顺序一直存在不一致,因为排序规则被委托给主机操作系统,但在 Postgres 10 中处理了这一问题,并包含了ICU support。
答案已更新,我已通过测试验证了该行为。感谢您的洞察力。
MySQL:更改DATABASE
或TABLE
的设置仅分别更改新添加的表或列的默认值。你需要ALTER TABLE ... MODIFY COLUMN ...
以上是关于类似字符的唯一约束违规的主要内容,如果未能解决你的问题,请参考以下文章