2011-01-19 4 views
4

に設定されている場合のSQL固有の制約は、特定の列に特定の値がある場合、列が一意でなければならないという制約をSQLに作成する方法ですか?列がx

例:行は実際には削除されませんが、データベースでは「deleted」とマークされます。そして、「-削除されていない」の行の中に、ValueAはユニークである必要があります:

ID ValueA   ValueB   Deleted 
----------------------------------------------------- 
1  'foo'   10    0 
2  'bar'   20    0 
3  'bar'   30    1 
4  'bar'   40    1 
5  'foo'   50    0 --NOT ALLOWED 

私は、しかし、私はこれを行う方法がわからない、CHECK制約のようなものを考えました。 SQL92と

+0

部分インデックスを許可していないため、これはMySQLでは可能ではないと考えています –

+0

フィルタリングされたインデックスを使用できます。詳細については、[here](http://stackoverflow.com/questions/3997837/unique-constraint-controlled-by-a-bit-column)を参照してください。 –

答えて

4

これができない、あなたが引き金と何かを実装することができすることができる

+0

'制約'に違反しているかどうかだけを確認するトリガーを作成することは可能ですか?私はそれがデータを変更することしかできないと思った... – TheSilentOne

+0

MySQLができること(SQL92からプラスとマイナス)ができないことを示す "standard ansi"についてはわかりませんが、MySQLはできないと述べましたこれは解析するのでCHECKを使ってこれを実装します。 – RichardTheKiwi

0

MySQLはCHECK制約を無視するので、あなたは別のデータベースにかもしれませんが、あなたは、MySQLでこれを行うことはできません。

ここではハックです。 valueA +に対する一意の制約が削除されました。行を削除するときには1だけ使うことはできませんが、1,2,3 ...

少なくともこれはMySQLでサーバー側で実行できますが、ステップが導入されています。削除の行をマーキングするときは、最初にmax(削除済み)を見つけて1を追加し、その値を削除用にマーキングする必要があります。

+0

残念ながら、実際の表では、「削除済み」列は、2つ以上の値を受け入れるステータス列によく似ています。削除されたステータスは1つだけです。削除された行を数えるだけでは実際の選択肢にはなりません。とにかく感謝:) – TheSilentOne

+0

決してそれを行う。削除された列が削除されます。期間、会話の終わり。他のステータスを別の列に入れます。列は自由です。 –

1

デザインを少し変更できますか?

あなたには「もの」のリストがあるようです。各ValueAには、一度に1つのアクティブな「もの」があります。これは、次のようにモデル化することができます。

  1. メインThingiesテーブルからValueAを削除し、削除します。

  2. ValueAとIDの列を持つ新しいテーブルActiveThingiesを作成します。 ValueAを一意または主キーにすることで、このテーブルを保護します。 (1つのIDが1つ以上のValueAを表すことができるかどうかによっても、IDを一意にする必要があります)。

ここで、ActiveThingiesテーブルを使用して、いつでも最新のレコードを制御できます。 "foo"のアクティブな(削除されていない)レコードを変更するには、ActiveThingiesのID列を更新します。

削除されていないアイテムのリストを取得するには、2つのテーブルを結合します。

ただし、このデザインでは、「削除済み」の「もの」のValueAを覚えることができなくなります。これらの値を覚えておく必要がある場合は、ThingiesにValueA列も含める必要があります。

+0

それは良い考えです。 InActiveThingiesテーブルで、私はActiveThingiesと同じ構造を持つことができますので、削除されたもののValueAが必要です。両方のテーブルの情報が必要な場合は、SELECT UNIONを作成できますか? – TheSilentOne

+0

いいえ、私はあなたの意見が不足していると思います。 「Thingies」テーブルのすべてのアイテム_stay_。 ActiveThingiesテーブルはヘルパーに過ぎず、IDとValueAの列に厳密に限定されています。これは、削除されないアイテムを指定するのに役立ちます(削除された列が低いということは素晴らしいアイデアではないためです)。一度に1つの削除されていないActiveAしかないことを確認してください。すべてのデータ列はThingiesに残ります。 –

+0

ストレージを2つの別々のほぼ同じテーブルに分割することもできます。しかし、そのような構造の重複は、たいていは良い考えではありません。 –

0

テーブルを2つのテーブルに分割します.1つはValueAにUNIQUE制約があり、1つはUNIQUE制約にありません。ビュー+トリガを使用して2つのテーブルを結合します。次のようなものがあります。

CREATE TABLE _Active (
    ID  INTEGER, 
    ValueA VARCHAR(255) UNIQUE, 
    ValueB INTEGER 
); 

CREATE TABLE _Deleted (
    ID  INTEGER, 
    ValueA VARCHAR(255), /* NOT unique! */ 
    ValueB INTEGER 
); 

CREATE VIEW Thingies AS 
    SELECT ID, ValueA, ValueB, 0 AS Deleted FROM _Active 
UNION ALL 
    SELECT ID, ValueA, ValueB, 1 AS Deleted FROM _Deleted; 

CREATE TRIGGER _trg_ii_Thingies_Active 
    INSTEAD OF INSERT ON Thingies 
    FOR EACH ROW WHEN NOT NEW.Deleted 
BEGIN 
    INSERT INTO _Active(ID, ValueA, ValueB) 
     VALUES (NEW.ID, NEW.ValueA, NEW.ValueB); 
END; 

CREATE TRIGGER _trg_ii_Thingies_Deleted 
    INSTEAD OF INSERT ON Thingies 
    FOR EACH ROW WHEN NEW.Deleted 
BEGIN 
    INSERT INTO _Deleted(ID, ValueA, ValueB) 
     VALUES (NEW.ID, NEW.ValueA, NEW.ValueB); 
END; 

/* Add triggers for DELETE and UPDATE as appropriate */ 

(私はCREATE TRIGGERの構文についてはわかりませんが、私は何を意味するのか知っています。)

+0

それは良い考えです。 Hoewver、私は、TriggersはMySQLのビューに接続できないのではないかと心配しています。 – TheSilentOne

0

回避策は、この問題があります - 別の列deleted_on

deleted_on timestamp NOT NULL DEFAULT '0000-00-00 00:00:00'

とソフトレコードの挿入を削除する場合

UNIQUE KEY not_deleted (ValueA, deleted_on)

deleted_on ValueAの両方に一意のキーを作るの作成NOW()の値はdeleted_on