我使用mysql创建了一个表。 表的列是sequence,email,date_created和date_canceled。 primary是序列,我试图为电子邮件和date_canceled创建一个唯一索引 - 所以当电子邮件处于活动状态(从未被取消 - 意味着date_canceled为NULL)时,不会插入另一个有效的电子邮件或发生这种情况。
我知道它可以用oracle db完成,但是mysql唯一索引允许NULL。
任何建议如何处理? 谢谢!
答案 0 :(得分:1)
我对您的问题的理解是,您希望每个用户随时都有一封与之关联的有效电子邮件,同时保留用户的历史记录。以前的邮件。
解决方案1
从MySQL 5.7.5开始,您可以通过创建生成的列,然后对其进行唯一约束来完成此操作; http://mysqlserverteam.com/generated-columns-in-mysql-5-7-5/。 例如
create table UniqueActiveEmailDemo
(
sequence bigint not null auto_increment primary key
, userId bigint not null
, email nvarchar(1024) not null
, date_created timestamp default now()
, date_cancelled datetime
, single_active_mail_per_user bigint as (if(date_cancelled is null, userId, null))
);
alter table UniqueActiveEmailDemo
add unique UK_UniqueActiveEmailDemo_SingleActiveMailPerUser
(single_active_mail_per_user);
因为MySQL在唯一约束中允许多个空值,在取消记录的情况下,生成列具有空值;所以你可以拥有任意数量的记录。但是,如果记录未被取消,则生成的列将返回用户的ID;这取决于唯一约束,因此如果另一个具有相同用户ID的活动记录,则唯一约束将引发异常。
解决方案2
Sql Fiddle:http://sqlfiddle.com/#!9/b54dce/2
然而,与早期版本一起使用的更干净的方法是简单地防止date_cancelled可以为空;相反,对于尚未取消的任何项目,在远期将其设置为固定值,然后将user_id和date_cancelled的组合设为null;例如
create table UniqueActiveEmailDemo
(
sequence bigint not null auto_increment primary key
, userId bigint not null
, email nvarchar(1024) not null
, date_created timestamp default now()
, date_cancelled datetime not null default '9999-12-31 23:59:59'
);
ALTER TABLE UniqueActiveEmailDemo
ADD UNIQUE UK_UniqueActiveEmailDemo_SingleActiveMailPerUser
(userId, date_cancelled);
9999-12-31 23:59:59
视为空值;即任何记录都有该值是活跃的。active_from
上添加where now() between date_active and date_cancelled
日期和过滤器来解决上述问题;但是,您需要添加更多检查以确保同一用户的活动窗口不重叠;这使事情变得更加复杂。 , date_cancelled datetime not null default '9999-12-31 23:59:59'
check (date_cancelled = '9999-12-31 23:59:59' or date_cancelled <= now())
答案 1 :(得分:0)
BDB存储引擎会将NULL
视为唯一值,只允许一个NULL
值。
如果允许
NULL
值的列具有唯一索引,则只有一个 允许NULL
值。这与其他存储引擎不同, 允许在唯一索引中使用多个NULL
值。
如果您不想更改存储引擎以获得此行为,那么您的其他选项是更改表结构以存储活动电子邮件并取消不同表中的电子邮件...创建触发器强制执行此行为...或为active
电子邮件分配魔术日期值,并且不再允许此列中的NULL
值。