複数のテーブルの主キーを参照する外部キー?


91

データベースemployeesの下に2つのテーブル、つまりemployees_ceとemployees_snが必要です。

どちらにも固有の主キー列があります。

控除と呼ばれる別のテーブルがあり、その外部キー列は、employees_ceとemployees_snの主キーを参照する必要があります。これは可能ですか?

例えば

employees_ce
--------------
empid   name
khce1   prince

employees_sn
----------------
empid   name
khsn1   princess

これは可能ですか?

deductions
--------------
id      name
khce1   gold
khsn1   silver

回答:


98

私はあなたのシナリオを正しく理解していると仮定すると、これは私が権利と呼ぶものですこれを行う方法:

データベースの上位レベルの説明から始めてください!あなたには従業員がいて、従業員は "ce"従業員と "sn"従業員になることができます(それらは何であっても)。オブジェクト指向の用語では、「従業員」というクラスがあり、「ce従業員」と「sn従業員」という2つのサブクラスがあります。

その後、3つの表に、この高いレベルの記述を翻訳:employeesemployees_ceおよびemployees_sn

  • employees(id, name)
  • employees_ce(id, ce-specific stuff)
  • employees_sn(id, sn-specific stuff)

すべての従業員は従業員であるため(duh!)、すべての従業員はemployeesテーブルに行を持ちます。「ce」の従業員もemployees_ceテーブルに行があり、「sn」の従業員もemployees_snテーブルに行があります。そのままのemployees_ce.idへの外部キーです。employees.idemployees_sn.id

あらゆる種類の従業員(ceまたはsn)を参照するには、employees表を参照してください。つまり、問題が発生した外部キ​​ーはそのテーブルを参照する必要があります。


17
ceとsnを相互に排他的にするにはどうすればよいですか?従業員は同時にceとsnになることはできないため、データベースに反映することをお勧めします。私は今この問題を抱えています。
ロルフ

複数の列キーが前のコメントの問題を解決するのに役立つと思います...今すぐ調べてください。
Rolf、

12
ベーステーブルと派生テーブルに型を格納することで、従業員を強制的に1つのテーブル(および正しいテーブル)に入れることができます。主キーID、(id、type)の一意のキー、子テーブルの外部キーを(id、type)にし、正しい型のみを持つように各子テーブルにCHECK制約を設定します。または、データベースがグローバルチェック制約を実行している場合(速度に大きなペナルティがない場合)、もちろんNOT EXISTSチェックを実行できます。
derobert

完全な説明と実装の詳細については、この回答を確認しください。
PerformanceDBA

特定のIDを持つ従業員が「se」または「sn」であることを知る方法
mhrsalehi

22

おそらく2つの外部キー制約を追加できますが(正直なところ、私は試したことはありません)、両方のテーブルに親行が存在すると主張します。

代わりに、2つの従業員サブタイプのスーパータイプを作成し、代わりにそこに外部キーを指定する必要があります。(もちろん、2つのタイプの従業員を分割する十分な理由があると仮定します)。

                 employee       
employees_ce     ————————       employees_sn
————————————     type           ————————————
empid —————————> empid <——————— empid
name               /|\          name
                    |  
                    |  
      deductions    |  
      ——————————    |  
      empid ————————+  
      name

type従業員テーブルではceまたはになりsnます。


複数の外部キーを追加しようとしましたが、機能しましたが、レコードを追加しているときに、Java derbyが両方の外部キー制約に違反していることを通知しています!

私はPostgreSQLで試してみましたが、そこで機能します。両方のテーブルに親レコードはありましたか?
derobert 2009年

あなたが言うつもりの親記録、empid?

確かに、問題は「控除」表から「従業員」表に移されています。タイプに基づいて、潜在的に異なるエンティティをどのように参照しますか?
gawpertron 2011年

1
@gawpertron:まあ、empidはすべてのタイプで一意です。「type」フィールドを使用して、参照する必要があるサブテーブルを確認できます。あるいはLEFT JOIN、十分に数が少ない場合は、それらすべてを使用します。「employee」ベーステーブルを使用していない場合、主キーを宣言できませんでした(それがtableAまたはtableBを参照しているためです)。今それができます。分割の知恵employees_ceemployees_sn仮定され、その仮定が記載されています。
derobert、2011年

19

実際、私は自分でこれを行います。他の3つのテーブルのレコードのコメントを含む「コメント」というテーブルがあります。どちらのソリューションも、実際に必要なすべてを処理するわけではありません。あなたの場合、これを行うでしょう:

解決策1:

  1. 各テーブルで異なるデフォルト値を持つtinyintフィールドをemployees_ceとemployees_snに追加します(このフィールドは「テーブル識別子」を表すので、tid_ceとtid_snと呼びます)

  2. テーブルのPKとテーブルIDフィールドを使用して、各テーブルに一意のインデックスを作成します。

  3. tinyintフィールドを 'Deductions'テーブルに追加して、外部キーの後半(テーブルID)を格納します。

  4. 'Deductions'テーブルに2つの外部キーを作成します(一方のキーが有効になるか、もう一方のキーが有効になるため、参照整合性を強制することはできませんが、両方はできません:

    ALTER TABLE [dbo].[Deductions]  WITH NOCHECK ADD  CONSTRAINT [FK_Deductions_employees_ce] FOREIGN KEY([id], [fk_tid])
    REFERENCES [dbo].[employees_ce] ([empid], [tid])
    NOT FOR REPLICATION 
    GO
    ALTER TABLE [dbo].[Deductions] NOCHECK CONSTRAINT [FK_600_WorkComments_employees_ce]
    GO
    ALTER TABLE [dbo].[Deductions]  WITH NOCHECK ADD  CONSTRAINT [FK_Deductions_employees_sn] FOREIGN KEY([id], [fk_tid])
    REFERENCES [dbo].[employees_sn] ([empid], [tid])
    NOT FOR REPLICATION 
    GO
    ALTER TABLE [dbo].[Deductions] NOCHECK CONSTRAINT [FK_600_WorkComments_employees_sn]
    GO
    
    employees_ce
    --------------
    empid    name     tid
    khce1   prince    1
    
    employees_sn
    ----------------
    empid    name     tid 
    khsn1   princess  2
    
    deductions
    ----------------------
    id      tid       name  
    khce1   1         gold
    khsn1   2         silver         
    ** id + tid creates a unique index **

ソリューション2: このソリューションにより、参照整合性を維持できます。1.「控除」テーブルに2番目の外部キーフィールドを作成し、両方の外部キーにNull値を許可し、通常の外部キーを作成します。

    employees_ce
    --------------
    empid   name
    khce1   prince 

    employees_sn
    ----------------
    empid   name     
    khsn1   princess 

    deductions
    ----------------------
    idce    idsn      name  
    khce1   *NULL*    gold
    *NULL*  khsn1     silver         

整合性は、列がnullでない場合にのみチェックされるため、参照整合性を維持できます。


6

私はこれが長い停滞しているトピックであることを知っていますが、誰かがここで検索した場合に備えて、私が複数テ​​ーブルの外部キーを処理する方法を説明します。この手法では、DBAが強制するカスケード操作がないためDELETE、コード内などで対処するようにしてください。

Table 1 Fruit
pk_fruitid, name
1, apple
2, pear

Table 2 Meat
Pk_meatid, name
1, beef
2, chicken

Table 3 Entity's
PK_entityid, anme
1, fruit
2, meat
3, desert

Table 4 Basket (Table using fk_s)
PK_basketid, fk_entityid, pseudo_entityrow
1, 2, 2 (Chicken - entity denotes meat table, pseudokey denotes row in indictaed table)
2, 1, 1 (Apple)
3, 1, 2 (pear)
4, 3, 1 (cheesecake)

SO Opの例は次のようになります

deductions
--------------
type    id      name
1      khce1   gold
2      khsn1   silver

types
---------------------
1 employees_ce
2 employees_sn

1

技術的に可能です。おそらく、控除ではemployees_ceを参照し、employees_snを参照します。しかし、なぜemployees_snとemployees_ceをマージしないのですか?テーブルが2つある理由はわかりません。1対多の関係はありません。そして(この例ではなく)多くの列。

1つの列に対して2つの参照を行う場合、従業員は両方のテーブルにエントリを持っている必要があります。


1

はい、可能です。3番目のテーブルには2つのFKを定義する必要があります。1つのテーブルの必須フィールドを指す各FK(つまり、外部テーブルごとに1 FK)。


0

なんらかの理由で2つの従業員タイプ用の2つのテーブルが必要であると想定して、vmarquezの答えを拡張します。

スキーマ:

employees_ce (id, name)
employees_sn (id, name)
deductions (id, parentId, parentType, name)

控除のデータ:

deductions table
id      parentId      parentType      name
1       1             ce              gold
2       1             sn              silver
3       2             sn              wood
...

これにより、控除にスキーマ内の他のテーブルをポイントさせることができます。この種類の関係は、データベースレベルの制約、IIRCではサポートされていないため、アプリが制約を適切に管理していることを確認する必要があります(同じデータベースにアクセスする複数の異なるアプリ/サービスがある場合は、面倒になります)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.