あなたの質問に対する直接的な回答ではありませんが、実際のデータベースでこの種の制約を適用する方法に興味があるかもしれません...
フライトには最大 2 人のパイロットを乗せることができるとしましょう。2 つの "0..N から 0..1" の関係を簡単に作成できます。
そして、正確に2 人のパイロットが必要な場合は、PILOT1_ID と PILOT2_ID を NOT NULL にします (そして、CHECK によってそれらが異なることを確認します)。
ただし、すでに指摘したように、これはカーディナリティが大きくなるとすぐに扱いにくくなるため、別の手法が必要です。客室乗務員の数を 15 人に制限する必要があるとしましょう。次のようにできます...
...ジャンクション テーブルに次の制約があります。
CHECK (POSITION BETWEEN 1 AND 15)
U1
上の図で示されているように、{FLIGHT_ID, POSITION} には UNIQUE 制約があることに注意してください。
基本的に、私たちはフライトごとに特定の位置にアテンダントを配置しています。2 人のアテンダントが同じフライトで同じポジションを占有することはできません ( のおかげですU1
)。フライトごとに正確に 15 のポジションがあるため、フライトごとに 15 人を超えるアテンダントは存在できません。
残念ながら、すべてのポジションを強制的に埋める良い方法はないため、フライトごとにアテンダントが 15 人未満になる可能性があります。それが重要な場合は、アプリケーション コードから強制する必要があります。
- - 編集 - -
(次の INSERT に使用する) 空いている位置を探すには、それが 2 つの既に埋められた位置の間の「穴」であっても、次のようにすることができます (1
目的の FLIGHT_ID に置き換えます)。
SELECT DISTINCT *
FROM (
SELECT POSITION + 1 FREE_POSITION
FROM FLIGHT_ATTENDANT
WHERE FLIGHT_ID = 1
UNION ALL
SELECT POSITION - 1 FREE_POSITION
FROM FLIGHT_ATTENDANT
WHERE FLIGHT_ID = 1
)
WHERE
FREE_POSITION NOT IN (
SELECT POSITION
FROM FLIGHT_ATTENDANT
WHERE FLIGHT_ID = 1
)
ORDER BY FREE_POSITION;
このクエリの結果は次のようになります。
- 行が返されない可能性があり、すべての位置が空いていることを示しているため、有効な範囲内のいずれかを選択してください。
- 行が返される可能性があり、その最初と最後が有効な範囲外である可能性があるため、そうである場合は無視してください。残りの行の 1 つを使用します。残りの行がない場合、これはすべての位置が埋まっていることを示しています。
これは、Oracle でのSQL Fiddle の実際の例ですが、同じ手法をどの DBMS にも適用できるはずです。これらの種類のクエリを実行するためのより洗練された DBMS 固有の方法があります (特に、一部だけでなくすべての空き位置が必要な場合)、この「一般的な」ソリューションでさえ、ほとんどの実用的な目的には十分すぎるはずです...