一般的なFKを持つ1つのレコードのみが「プライマリ」フラグを持つことを許可/要求します

StackOverflow https://stackoverflow.com/questions/9326606

  •  27-10-2019
  •  | 
  •  

質問

まず、これがだまされている場合はお詫び申し上げます - 私はそれがあるかもしれないが、私はそれを見つけることができない。

私が会社のテーブルを持っているとします:

 id | company_name
----+--------------
  1 | Someone
  2 | Someone else

...そして連絡先のテーブル:

 id | company_id | contact_name | is_primary
----+------------+--------------+------------
  1 |     1      | Tom          |      1
  2 |     2      | Dick         |      1
  3 |     1      | Harry        |      0
  4 |     1      | Bob          |      0

セットアップすることは可能ですか? contacts そのような方法でテーブル 必要 その1つのレコードがあります is_primary 各コモンに設定されています company_id?

だから私がやろうとしたら:

UPDATE contacts
SET is_primary = 1
WHERE id = 4

...クエリは失敗します Tom (id = 1)プライマリコンタクトとしてすでにフラグが付けられています company_id = 1. 。またはさらに良いことに、クエリが成功するようにトリガーを構築することが可能ですが、 Tom's is_primary 旗は同じ操作によってクリアされますか?

私はチェックすることにあまり気にしません company_id に存在します companies テーブル、私のPHPコードは、この段階に到達する前にこのチェックを既に実行していたでしょう(ただし、同じ操作でこれを行う方法があれば、それはいいと思います)。

私が最初にこれについて考えたとき、私は「それは簡単になるだろうと思った。 company_idis_primary 列「しかし、明らかに、それは私を1つのプライマリと1つの非プリマリー接点に制限するため、それは機能しません - 3番目の連絡先を追加する試みは失敗します。私が必要とする最小限の機能を提供するインデックス - 2番目の主要な連絡先を追加する試みを拒否するか、プライマリコンタクトを持たない会社を離れる試みを拒否します。

私はただ追加できることを知っています primary_contact フィールドへ companies fkを備えたテーブル contacts テーブルですが、乱雑に感じます。私は両方のテーブルが他のテーブルにFKを持っているという考えが好きではありません - 一方のテーブルは、両方のテーブルが互いに依存するのではなく、他のテーブルに依存するべきだと思われます。時間が経つにつれて、何かがうまくいかない可能性があると思います。

総括する:

  • 連絡先テーブルを制限して、特定の1つのレコードが1つだけのレコードを制限するにはどうすればよいですか company_id 持っています is_primary フラグセット?
  • 互いにfksを持っている2つのテーブルが良い/悪いアイデアであるかどうかについて、誰かが考えていますか?
役に立ちましたか?

解決

テーブル間の円形の復活は確かに乱雑です。この(10年前の)記事を参照してください: 設計によるSQL:円形の参照

このような制約を作成する最もクリーンな方法は、別のテーブルを追加することです。

Company_PrimaryContact
----------------------
company_id
contact_id
PRIMARY KEY (company_id)
FOREIGN KEY (company_id, contact_id)
  REFERENCES Contact (company_id, id)

これにはaも必要です UNIQUE 表の制約 Contact の上 (company_id, id)

他のヒント

その1つの設定の前にクエリを実行することができます

UPDATE contacts SET is_primary = 0 WHERE company_id = .....

あるいは

UPDATE contacts
SET is_primary = IF(id=[USERID],1,0)
WHERE company_id = (
    SELECT company_id FROM contacts WHERE id = [USERID]
);

代替品を置くだけです - 個人的には、このタイプの回避策の代わりにFKアプローチに目を向けると思います。

編集 contact.is_primaryフィールドに依存している方法

代替方法、まず最初に連絡先からis_primaryを削除します。次に、「primary_contact_id」intフィールドを企業に追加します。第三に、プライマリコンタクトを変更するときは、Primary_contact_idを変更するだけで、バックグラウンドでトリガーなどを必要とせずに、いつでも1つ以上のプライマリコンタクトが必要になる可能性を防ぎます。

このオプションは、INTフィールドを単純に更新しているため、FKなどに依存することは必要に応じて追加/削除できるため、どのエンジンでも正常に動作しますが、最も簡単ですが、INTフィールド値を変更するだけです

このオプションは、プライマリにフラグを立てている企業から連絡先への1つのリンクを必要とする限り実行可能です

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top