- - PR -
1対1関連のテーブル設計について
| 投稿者 | 投稿内容 | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2008-03-24 18:04
案2で、bigintの代わりにList<Long>をバイナリにしてbyteaで格納しているだけです。
EntityのメンバとしてはList<Long>で格納してます。 | ||||||||||||||||
|
投稿日時: 2008-03-24 18:20
【案1】はDBの制約で保証できない。 【案2】はDBの制約で保障できる。 様に受け取れますが、【案2】も保障できないのでは? 異なるカテゴリのアイテムを注目商品とする場合も考えられます。 案1,案2共に保障できないのであれば、案1がいいと思います。 | ||||||||||||||||
|
投稿日時: 2008-03-24 22:28
案3、ただし複合キーにしてCATEGORY_IDに一意制約。
注目商品が複数登録される仕様に変わったら一意制約をとればいい。 でも、異なるカテゴリのアイテムを注目商品にできないという要件を DBで保証したいなら案1がいいでしょうかね。 | ||||||||||||||||
|
投稿日時: 2008-03-25 03:39
たくさんのご意見ありがとうございます。
実は1対1関連に対する案2と3の使い分けが大きな疑問の1つでして、 案1はほとんど検討対象から外していたので、 案1を支持する方が多かったのは少し意外でした。 indigo-xさんのご指摘通り「ゆるい」仕様しか提示できなかったことによる 影響もあったのかもしれませんが ^^; でも、そのおかげで案1も含めて皆さんの設計ポイントを 色々お聞きすることができて、とても参考になりました。 ■jamaさん ご指摘の通り、案1〜3のいずれのテーブルでも データベースの制約だけで要件を完全に満たすことはできないですね。 見落としてました ^^; ■Anthyhimeさん、unibonさん テーブルが相互に外部参照するというのはおかしなことでも、 アンチパターンでもないのですね。 レコード削除時に参照整合性違反でややことしいことになるのでは? と思ったのですが、問題ないですね。 ■よっしーさん
とてもわかりやすいです ■indigo-xさん 案1に気持ちが傾いてきました ■忠犬さん
注目商品でない商品を複数登録できないように思ったのですが、どうなのでしょうか? ■だっちょさん
正直びっくりしました。 List<Long>からバイナリの変換はどのように行っているのでしょうか? このようなレスポンス改善方法って結構採用されているものなのか、 自分も興味を持ちました。 ■べるさん
なるほど、こういう方法もありますね。 この方法の利点は、仕様変更時のDBへの影響の少なさということでしょうか? ■まとめ (1)今回の仕様では今後、注目商品が複数になることを見越して、 案1を採用しようと思います。 (2)「データベースの機能を使って制約すべき」という考えが強かったのですが、 皆さんのご意見をお聞きしてその考えがあまりにも強すぎていたように感じました (暗黙的な制約は悪ではない)。 (3)よっしーさんにコメント頂いた指針をベースにみなさんのご意見を参考にしつつ、 自分の設計指針を構築していけたらと思いました。 みなさん、ご意見どうもありがとうございました。 [ メッセージ編集済み 編集者: nikori 編集日時 2008-03-25 03:42 ] | ||||||||||||||||
|
投稿日時: 2008-03-26 18:37
例えば、同じカテゴリidに対して、trueとfalseは各々1件しか格納できません。 しかし、nullで格納すれば、重複エラーにはなりません。 つまり、「注目」の場合はtrue、「注目以外」はnullで格納すれば、DBMS側で制約を 設けられます。 | ||||||||||||||||
|
投稿日時: 2008-03-27 12:15
ここら辺、実はRDBMSによってだいぶ実装が異なります。 通常は「NULLとNULLは等しくない」ので、複数レコードがユニークキー列にNULL値を持てるはずなのですが、例えばMS SQL ServerやDB2の一意制約の実装では「NULLとNULLは等しい」ので、最大1レコードしかNULL値を持てません。 Oracleは基本的に「NULLとNULLは等しくない」のですが、マルチカラムユニークキーの一部の列がNULLの場合に限り、「NULLとNULLは等しい」と扱われる場合があります。つまり、 (NULL) != (NULL) ('A', 'B', NULL) = ('A', 'B', NULL) (NULL, NULL, NULL) != (NULL, NULL, NULL) です。 知っている限りでは、MySQLとPostgreSQLはNULLに忠実です。 ('A', 'B', NULL) != ('A', 'B', NULL) 元質問の対象であるHSQLDBについては、残念ながら知りませんが。 [ メッセージ編集済み 編集者: カーニー 編集日時 2008-03-27 12:20 ] | ||||||||||||||||
|
投稿日時: 2008-03-27 13:32
Oracleは一意制約の実装にユニークインデックスを使ってるからですね。キーがNullだけのインデックスは作らないので。 SQLServerは「Nullが重複したらだめ」ですが、Nullは重複してもOKの方が使い勝手が良いと思います。「1レコードだけNullを許す」なんて要件もあまりないでしょうし。 | ||||||||||||||||
|
投稿日時: 2008-03-27 14:38
その意味では、僕が知っている限りにおいて、どのデータベースも一意制約を作成すると、自動的にユニークインデックスが作成されます。 なので、データベースによってユニークインデックスにおけるNULLの扱い方が異なる、と言えます。
僕もRDBMSはOracleから入ったので、そう思うんですがね。 実際のところSQL2003において「必須」とされているのは、「NULL値を許容しない一意制約」だけで、「NULL値を許容する一意制約」は「オプショナル」です。実装する場合のNULL取り扱い方法が定義されているのかどうかは、残念ながら知りません。 またSQL標準においては、一意インデックスはおろか、インデックスそのものについてすら言及されていません。 これはなかなかにややこしい問題なのです。 一番混乱がないのは、NOT NULL列にしか一意制約を定義しない、ということになるのだと思います。 | ||||||||||||||||
