あなたの質問に対する私の理解では、各ユーザーがいつでも 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 は一意の制約で複数の null を許可するため、レコードがキャンセルされるため、生成列には null 値が含まれます。そのため、これらのレコードを好きなだけ持つことができます。ただし、レコードがキャンセルされていない場合、生成された列はユーザーの ID を返します。これは一意の制約の対象となるため、同じユーザー ID を持つ別のアクティブなレコードがある場合、一意の制約によって例外がスローされます。
解決策 2
SQL フィドル: http://sqlfiddle.com/#!9/b54dce/2
ただし、以前のバージョンでも機能するよりクリーンな方法は、単純に date_cancelled が null 可能になるのを防ぐことです。代わりに、まだキャンセルされていないアイテムの遠い将来の固定値に設定し、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);
- ここでの違いの 1 つは、同じユーザーの 2 つのレコードを同じ日にキャンセルできないことです。しかし、実際には、とにかくそれを取得することはないと思います。
- また、将来取得するレコードを持つことができることも意味します。この問題を回避する
9999-12-31 23:59:59
には、null 値として扱うことができます。つまり、その値を持つレコードはすべてアクティブです。
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())