3

ユーザーのmysqlを使用してテーブルを作成しました。テーブルの列は、sequence、email、date_created、date_canceled です。プライマリはシーケンスであり、電子メールとdate_canceledの一意のインデックスを作成しようとしています-したがって、電子メールがアクティブな場合(キャンセルされたことがない-date_canceledがNULLであることを意味します)、別のアクティブな電子メールが挿入されたり、このような状況が発生したりすることはありません.

Oracle dbで実行できることはわかっていますが、mysqlの一意のインデックスではNULLが許可されています。

これを処理する方法はありますか?ありがとう!

4

2 に答える 2

1

あなたの質問に対する私の理解では、各ユーザーがいつでも 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())

于 2016-04-14T20:28:16.553 に答える
0

BDB ストレージ エンジンはNULL一意の値として扱い、単一のNULL値のみを許可します。

ドキュメントから

値を許可する列にNULL一意のインデックスがある場合、単一の NULL値のみが許可されます。NULLこれは、一意のインデックスで複数の値を許可する他のストレージ エンジンとは異なります。

この動作を取得するためにストレージ エンジンを変更したくない場合は、テーブル構造を変更して、アクティブな電子メールとキャンセルされた電子メールを別のテーブルに保存することもできます...この動作を強制するトリガーを作成します... または、電子メールにマジック デートの値を割り当て、この列に値をactive許可しなくなります。NULL

于 2013-03-22T18:09:17.437 に答える