两列组合的双向唯一键约束

Bi-directional unique key constraint for combination of two columns

我在 MySQL 中有以下 table 列。

id
user_primary_email
user_secondary_email

我想使列 user_primary_emailuser_secondary_email 的组合独一无二,我可以使用 UNIQUE KEY unique_key_name (user_primary_email, user_secondary_email)

来实现

上面添加的唯一键约束将帮助我实现以下场景,或者更确切地说,只需向单个列本身添加一个唯一键即可。

user_primary_email = 'xyz@gmail.com' AND user_secondary_email = 'pqr@gmail.com'
user_primary_email = 'xyz@gmail.com' AND user_secondary_email = 'pqr@gmail.com' //This will not be allowed to enter due to unique key constraint

现在我面临的问题是同一个组合不应该被允许以相反的方式添加,如下所述。

user_primary_email = 'pqr@gmail.com' AND user_secondary_email = 'xyz@gmail.com' //This should not be allowed to add since already same email id combination added once

id    |   user_primary_email   |   user_secondary_email
-------------------------------------------------------
1     |   xyz@gmail.com        |   pqr@gmail.com
-------------------------------------------------------
2     |   pqr@gmail.com        |   xyz@gmail.com       
-------------------------------------------------------

在上述情况下,在插入 row id 2 期间,它应该抛出错误,因为电子邮件 id 组合已在 row id 1[=30 中使用=].

任何帮助都会很棒。

对此没有直接支持,但您可以使用变通方法创建双向键:您需要在两列的有序版本上使用唯一键。

幸运的是,您可以很轻松地做到这一点。 MySQL 5.7.6+ 支持为它们生成列和唯一索引,您可以使用它们对两个值进行排序并强制执行唯一性。

create table testBiDirKey (
  a varchar(100), 
  b varchar(100),
  a_ordered varchar(100) as (least(a, b)) STORED,
  b_ordered varchar(100) as (greatest(a, b)) STORED,
  unique key unqBi_test_ab (a_ordered, b_ordered)
);

insert into testBiDirKey(a,b) values('a', 'b');
insert into testBiDirKey(a,b) values('b', 'a');
Error Code: 1062. Duplicate entry 'a-b' for key 'unqBi_test_ab'

这会将 null 完全视为您当前的普通唯一密钥,因此

insert into testBiDirKey(a,b) values('a', null);
insert into testBiDirKey(a,b) values('a', null);
insert into testBiDirKey(a,b) values(null, 'a');

都允许。如果需要,您可以添加 coalesce(x,'') 以仅允许一个空值(null'')。如果您在添加它们之前验证您的值(例如,如果它们不包含 ,),您可以将两列合并为一个,用 , 连接 - 尽管除了只有 1 个附加列。

对于 5.7.8+,您不再需要 STORED 关键字就可以在索引中使用这些列。如果存储值(使用磁盘space)或在需要时计算(默认),该关键字会起作用。

在 MySQL 5.7.6 之前,您可以使用触发器(在 updateinsert 上)用这些值更新两列,同样的逻辑适用,它是只是多一点代码。

在任何 MariaDB 中:

CREATE TABLE `t` (
  `id` int(11) NOT NULL,
  `user_primary_email` varchar(64) DEFAULT NULL,
  `user_secondary_email` varchar(64) DEFAULT NULL,
  `mycheck` varchar(128) AS (IF(user_primary_email<user_secondary_email,CONCAT(user_primary_email,user_secondary_email),CONCAT(user_secondary_email,user_primary_email))) PERSISTENT,
  PRIMARY KEY (`id`),
  UNIQUE KEY `mycheck` (`mycheck`)
);

MariaDB [test]> insert into t values (1,'a','b',null);
Query OK, 1 row affected (0.03 sec)

MariaDB [test]> insert into t values (2,'b','a',null);
ERROR 1062 (23000): Duplicate entry 'ab' for key 'mycheck'