2011-01-06 18 views
12

is_defaultという名前のMySQLテーブルにBOOLEANカラムを追加したいと思います。 この列では、is_defaultを1つのレコードだけtrueに設定できます。boolean Mysql列に "unique"制約を作成するにはどうすればよいですか?

mysqlを使用してこの制約を列に追加するにはどうすればよいですか?

ありがとうございます!


UPDATE

それは私が追加する必要が制約されていない場合。このような問題をDBでどのように処理していますか?

答えて

18

これは、単一のデフォルト値の状況をモデル化する最良の方法ではないと思います。

代わりに、私はIsDefault列を残して、1つの行とメインテーブルのプライマリキーを作成する列だけを持つ別のテーブルを作成します。このテーブルでは、デフォルトレコードを識別するPK値を配置します。

この結果、更新時に一時的にデフォルト値を持たない(または一時的にという2つののデフォルト値)という更新の問題が回避されます。

デフォルトテーブルに1行しかないことを確認するためのオプションが多数あります。

+9

デフォルトテーブルに1行しか存在しないようにするためのオプションは何ですか? – benjisail

+0

私はその質問にも答えたいです。 – ryvantage

9

MySQLではこのような制約を設定することはできません。

TRUEとFALSEの代わりにTRUEとNULLの値を使用すると、UNIQUE列に複数のNULL値がある可能性があるため、TRUEとNULLの値が使用されます。これはすべてのデータベースには当てはまりませんが、MySQLでは動作します。

CREATE TABLE table1(b BOOLEAN UNIQUE); 

INSERT INTO table1 (b) VALUES (TRUE); // Succeeds 
INSERT INTO table1 (b) VALUES (TRUE); // Fails: duplicate entry '1' for key 'b' 

INSERT INTO table1 (b) VALUES (FALSE); // Succeeds 
INSERT INTO table1 (b) VALUES (FALSE); // Fails: duplicate entry '0' for key 'b' 

INSERT INTO table1 (b) VALUES (NULL); // Succeeds 
INSERT INTO table1 (b) VALUES (NULL); // Succeeds! 
+0

は、すべての主要なデータベースに適用される解決策はありますか? – benjisail

+0

@benjisail:はい、私はそれを行うための少なくとも1つの方法を考えることができますが、実際にそれを実装する場合は、私はそれを投稿する必要があるかどうかわからないので、醜いハック(私の現在の答えよりも)! –

2

トリガーをチェックアウトします。彼らはバージョン5.0.2で導入されました。 「挿入前」トリガが必要です。 is_default = trueの行がすでに存在する場合は、エラーを発生させます。私は並行性などの問題が何であるか分かりませんが、これで十分です。

8

DBでこのような問題をどのように処理していますか?

一部のDBMSでは、部分インデックスを作成できます。

PostgreSQLでは、これは次のようになります。

 
CREATE UNIQUE INDEX only_one_true 
    ON the_table (is_default) 
    WHERE is_default 

SQL Server 2008には、非常に似た構文を持っています。 Oracleで

それは同様になんとかもう少し複雑だけど:

 
CREATE UNIQUE INDEX only_one_true 
    ON the_table (CASE 
        WHEN is_default = 1 THEN 1 
        ELSE null 
       END) 

Oracleソリューションは、インデックス定義の式をサポートしている任意のDBMSに働くかもしれません。

+1

オラクルのヒントに感謝します! –

1

私はあなたのモデルに問題があるのと同じくらいデータベースに問題はないと思っています。あなたが表現しているデータのタイプについて言及していないので、それを解決するための良い例を考え出すのは難しいですが、XXXTypeまたはテーブルはdefaultXXXIdカラムを保持することができます。このようなことの

思う:青色はそれがデフォルトであるか、何か他のものが指定されたコンテキストで使用された場合色がデフォルトであることを知っている必要があることを知っておくべき?

データをモデル化する方法を変更することは、データベースの互換性を考えるよりも、問題のドメインにとって必ずしも自然ではない方法でデータを表現するために、それについて。

0

チェック制約はMySQLではサポートされていない、これはトリガーを使用したソリューションです。

 
    create table if not exists myTable (
     id int not null auto_increment primary key, 
     is_default bit not null 
    ) engine=innodb; 

    select 'create trigger tbi_myTable'; 
    drop trigger if exists tbi_myTable; 
    delimiter // 
    create trigger tbi_myTable 
     before insert on myTable 
     for each row 
    begin 
     if (select count(1) from myTable where is_default=true) > 0 && NEW.is_default then 
     -- Signal is only in 5.6 and above use another way to raise an error: if less than 5.6 
      SIGNAL SQLSTATE '50000' SET MESSAGE_TEXT = 'Cannot insert into myTable only one row with is_default true is allowed!'; 
     end if; 
    END // 
    delimiter ; 

    insert into myTable (is_default) values (false); 
    insert into myTable (is_default) values (true); 
    insert into myTable (is_default) values (false); 
    insert into myTable (is_default) values (false); 
    -- This will generate an error 
    insert into myTable (is_default) values (true); 
    insert into myTable (is_default) values (false); 


    select * from myTable; 
    -- will give 
    /* 
    id is_default 
    1 false 
    2 true 
    3 false 
    4 false 
    */ 
関連する問題