3

我使用用户的 mysql 创建了一个表。该表的列是序列、电子邮件、日期创建和日期取消。主要是序列,我试图为电子邮件和 date_canceled 创建一个唯一索引 - 所以当电子邮件处于活动状态时(从未取消 - 意味着 date_canceled 为 NULL),不会插入另一封活动电子邮件或发生这种情况。

我知道它可以用 oracle db 完成,但使用 mysql 唯一索引允许 NULL。

任何建议如何处理?谢谢!

4

2 回答 2

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 小提琴:http ://sqlfiddle.com/#!9/b54dce/2

然而,一种也适用于早期版本的更简洁的方法是简单地防止 date_cancelled 可以为空;而是在遥远的将来为尚未取消的任何项目将其设置为固定值,然后让 user_id 和 date_cancelled 的组合为空;例如

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;但是,您需要添加更多检查以确保同一用户的活动窗口不会重叠;这使事情进一步复杂化。
  • 添加检查约束将防止未来值;但遗憾的是它们目前没有在 MySQL 中使用(尽管是有效的语句)。http://dev.mysql.com/doc/refman/5.7/en/create-table.html

, 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())

于 2016-04-14T20:28:16.553 回答
0

BDB 存储引擎将NULL视为唯一值,只允许单个NULL值。

从文档

如果允许NULL值的列具有唯一索引,则只允许单个 NULL值。这与其他存储引擎不同,后者允许NULL唯一索引中的多个值。

如果您不想更改存储引擎以获取此行为,您的其他选择是更改表结构以将活动电子邮件和已取消电子邮件存储在不同的表中...创建触发器以强制执行此行为... 或为active电子邮件分配一个神奇的日期值,并且不再允许NULL此列中的值。

于 2013-03-22T18:09:17.437 回答