関係データベースを使用していて、3NF が必要な場合 (英語で 3NF と呼びますか?)、1:1 の関係を 1 つのテーブルにまとめます。しかし、配給が 1:0/1 (/ または意味) の場合はどうなるでしょうか?
次に、テーブルの空白を避けるためにそれらを分離したままにしますか? この場合、それらを離すことは有効な 3NF ですか?
関係データベースを使用していて、3NF が必要な場合 (英語で 3NF と呼びますか?)、1:1 の関係を 1 つのテーブルにまとめます。しかし、配給が 1:0/1 (/ または意味) の場合はどうなるでしょうか?
次に、テーブルの空白を避けるためにそれらを分離したままにしますか? この場合、それらを離すことは有効な 3NF ですか?
あなたの質問と@paxdialboの回答に対するその後のコメントに基づいて、NULLを避けながらオプションの属性を保存するためのソリューションが必要であると理解しています。これを実現するには、第 6 正規形(6NF) モデルまたはエンティティ属性値(EAV) モデルの 2 つの方法があります。
これには、属性に固有のテーブルの作成が含まれます。
create table attributeName (
id
value
)
は外部id
キーであり、value
その属性を取得します (例: 社会保障番号)。特定のキーのレコードがないことは、存在しないことを示します。
ご想像のとおり、第 6 正規形はテーブルの増殖につながる可能性があります。EAV モデルは、次のような複数の属性に対して同様のモデルを使用して解決します。
create table integerAttribute (
name
id
value
)
列はname
属性 (「SocialSecurity」など) を識別しますが、より洗練された実装はname
列ではなくname
、別のメタデータ テーブルに格納され、外部キーを介して参照されます。datetimeAttribute
いずれにせよ、このアプローチは、さまざまなデータ型 (つまり、、など)に対して他のテーブルを用意することを意味しますvarcharAttribute
。
実際に考えるべき問題は、処理しているオプションの属性の数です。比較的少ない場合、最も簡単な解決策は、実際にはオプションの NULLable 列をメイン テーブルに追加することです。6NF と EAV は、複雑さとパフォーマンスに関する重大な問題を追加します。これらのアプローチのいずれかを使用する場合、多くの場合、エンティティ全体をメイン テーブルの CLOB にシリアル化して共通読み取り (主キーによる) を簡素化し、複数の LEFT 結合を回避して完全にハイドレートされたエンティティを取得します。
第 3 正規形は基本的に、属性 (または列) がキー、キー全体、およびキー以外の何にも依存しないことを意味します (助けてください、Codd)。
存在する属性または存在しない属性がある場合、その属性自体は引き続きルールに従う可能性があります。
そのような場合は、単純に属性をメイン テーブルに保持し、NULL 可能にして、それらが行に適しているかどうかを示します。
(不自然な) 例SocialSecurityNumber
として、主キーとして属性を使用することができます (ここでこれが良いアイデアなのか、それとも質問とは関係がないため代理キーを使用する必要があるのかについては議論しません)。 .
BankAccount
さらに、あなたが賃金を支払うための明確な属性を持っていて、税金をかわす目的で複数の銀行口座に賃金を分配できるような良い雇用主ではないことを仮定してください:-)
現在、誰かの銀行口座は、選択したキーに完全に依存していますが、誰もがキーを所有しているわけではありません (現金で支払われている可能性があります)。言い換えれば、1:0/1
あなたが言うように古典的なケースです。
その場合、テーブル内の銀行口座番号を null 可能にするだけです。
paxdiablo であなたのコメントに基づいています。. .
いくつかの SQL を見てみましょう。列にもっと適切な名前を付けることもできましたが、意図的にそうしませんでした。私は怠惰ではありませんでした。私には正当な理由がありました。外部述語は、ユーザーがテーブルの内容を解釈する方法です。
-- External predicate: Human is identified by
-- Social Security Account Number [ssan]
-- and has full name [full_name]
-- and result of last HIV test [hiv_status]
-- and has checking account [bank_account]
-- and was born at exactly [birth_date].
--
create table human (
ssan char(9) primary key,
full_name varchar(35) not null,
hiv_status char(3) not null default 'Unk'
CHECK (hiv_status in ('Unk', 'Pos', 'Neg')),
bank_account varchar(20),
birth_date timestamp not null
);
-- External predicate: Human athlete identified by
-- Social Security Account Number [ssan]
-- has current doping status [doping_status]
create table athlete (
ssan char(9) not null primary key references human (ssan),
doping_status char(3) not null default 'Unk'
CHECK (doping_status in ('Unk', 'Pos', 'Neg'))
);
-- External predicate: Human dictator identified by
-- Social Security Account Number [ssan]
-- has estimated benevolence of [benevolence_score].
create table dictator (
ssan char(9) not null primary key references human (ssan),
benevolence_score integer not null default 3
CHECK (benevolence_score between 1 and 5) -- 1 is least, 5 is most benevolent
);
これらの 3 つのテーブルはすべて 5NF にあります。(つまり、彼らも 3NF にいるということです。)
あなたが言った
リレーショナルデータベースには「IS A」関係はありません
その識別子は人間の識別子であるため、アスリートは「IS A」人間です。この場合、その主キーは外部キーであり、references human (ssan)
. データベース設計者は通常、「IS A」と「HAS A」の関係について語ることはありません。述語の方が正確で表現力があるからです。この 2 つのステートメントを比較すると、違いがわかります。
その最後のものは、意図的に少し耳障りです。birth_date 列をタイムスタンプとして定義しました。日付と時刻の両方に対応しています。これは、外部述語が列名からある程度独立していることを示しています。(ここでは、述語と列名の間の疎結合があまり良い考えではないことも示しています。)
あなたが言った
しかし今、あなたは純粋な人間を手に入れることができませんが、人間の子供だけです
「純粋な人間」の意味がよくわかりません。単純にすべての人間を取得できます
SELECT * FROM human;
人間が運動選手か独裁者 (または何でも) でない限り、人間を持つことはできないという意味なら、それは間違いです。特定の SSAN のアスリートに行がない場合、その SSAN によって識別される人間はアスリートではありません。特定の SSAN の独裁者に行がない場合、その SSAN によって識別される人間は独裁者ではありません。