2

これはしばらくの間私を悩ませてきました。次のような属性を持つテーブルを考えてみてください{ID, Value, Australia, India, France, Germany}。ここIDで、は主キー、Valueはテキスト、たとえばcar-modelであり、のような各属性の下AustraliaIndiaは、その値に対応して製造された車の数です。

直感的に私はこれを正しい方法で表現することを知っています{ID, Value, Cars-Manufactured, Country} が、データベースの正規化に関してこれが正しい理由を誰かに教えてもらえますか?最初のテーブルが満たさない正規化はどれですか。または、最初のテーブルも正しいですか?

4

3 に答える 3

4

違反するルールは「繰り返しグループなし」です。これは、第一正規形の規則の1つです。

各国の列は繰り返しグループです。各列の下のデータは同じデータであり、異なるコンテキストに適用できます。その国で製造された車の数のように、そこに価値が1つしかない場合、これは明白ではないかもしれませんし、議論の余地があるかもしれません。ただし、製造数と販売数など、国ごとに2つの情報が必要であるとします。これで、テーブルにペアの列のセットが追加されました:Australia_manufactured、Australia_sold、India_manufactured、India_sold、France_manufactured、France_soldなど。2つの列のセットが複数回繰り返されています。

誰かが尋ねることができます、複数の異なるフィールドと繰り返しグループの違いは何ですか?「India_manufactured、Australia_manufactured、France_manufactured」は「number_manufactured、price、description」とどのように異なりますか?違いは、最初のケースでは、値のセマンティックな意味は同じであり、異なるのはコンテキスト、アプリケーションだけであるということです。2番目のケースでは、意味的な意味が異なります。つまり、些細な「最大値を見つける」などを超えてデータを処理するクエリやプログラムを想像するのは難しいです。今日はnumber_manufacturedを処理して実行し、明日はまったく同じ処理を実行します。セールスプライス。しかし、今日はインドで、明日はドイツで走ることは容易に想像できます。

もちろん、あいまいな場合もあります。そのため、データベース設計者は多額の支払いを受けます。:-)

さて、それがルールです。ルールには実用的な価値がありますか?

シナリオA、1つのテーブルを考えてみましょう。

model (model_id, description, india_manufactured, australia_manufactured, france_manufactured)

シナリオB、2つのテーブル:

model (model_id, description)
production (model_id, country_code, manufactured)

シナリオAがうまくいかない理由はいくつかあります。これが最大のものです:

シナリオBを使用すると、クエリがはるかに簡単になります。プログラムやクエリに国をハードコーディングする必要はありません。国コードをパラメーターとして受け入れ、その国で製造された各モデルの数を返すクエリを記述します。シナリオBでは、単純です。

select description, manufactured 
from model join production on model.model_id=production.model_id
where production.country_code=@country

簡単。次に、シナリオAで実行します。次のようなものです。

select description,
  case when @country_code='IN' then india_manufactured
  when @country_code='AU' then australia_manufactured
  when @country_code='FR' then france_manufactured
  else null
  end as manufactured
from model

または、すべての国で合計を生成したいとします。シナリオB:

select description, sum(manufactured)
from model
join production on model.model_id=production.model_id

シナリオA:

select description, india_manufactured+australia_manufactured+france_manufactured
from model

(nullを許可する必要がある場合は、より複雑になる可能性があります。)

システム全体で、このようなクエリが多数発生する可能性があります。実生活では、多くの場合、これよりもはるかに複雑で、そのような厄介なcase句が複数あるか、複数の列をジャグリングします。ここで、別の国を追加するとします。シナリオBでは、これはゼロエフォートです。好きな国をすべて追加および削除でき、クエリは変更されません。ただし、シナリオAでは、すべてのクエリを見つけて変更する必要があります。1つ見逃しても、コンパイルエラーなどは発生しません。不思議なことに間違った結果が出ます。

ちなみに、一部の国だけを処理したい場合もあるでしょう。たとえば、国によってはVATがあり、ない国もあります。シナリオBでは、このファクトの列を追加してテストします。これは、「country.country_code=production.country_codeとcountry.vat=1で国に参加する」だけです。シナリオAでは、プログラマーはほぼ確実に、各クエリで特定の国のリストをハードコーディングすることになります。その後、誰かが後でやって来て、クエリXがインドとフランスを処理し、クエリYがフランスとドイツを処理し、クエリZがドイツとシンガポールを処理するのを見て、彼は理由がわからないかもしれません。彼が知っている場合でも、リストはすべてのクエリでハードコーディングされているため、更新するたびに、データを変更するのではなく、コードを変更して、すべてのクエリを更新する必要があります。

4か国のうち3か国のみを処理するクエリに遭遇したとします。

ああ、ちなみに、

これが間違いであるかどうか、クエリを作成するときに誰かが国の1つを忘れたのか、新しい国が追加されたときにこのクエリを見逃したのかをどのように知ることができますか。または、この国が除外された理由があるかどうか。

于 2012-12-30T06:36:01.300 に答える
0

INSERT DELETE2番目のアプローチは、データの観点からより明確になり、UPDATE異常を回避できるため、より適切です。はい、2番目のアプローチでは、数の点でより多くのデータが得られます。

基本的に、DBを設計する場合、通常のアプローチは次のようになります。3NF.

于 2012-12-30T03:22:29.387 に答える
0
Table COUNTRYANDCARS [MODEL (PK), AUSTRALIA, INDIA, FRANCE, GERMANY]

理想的には、固定された国しかない場合は、上記のアプローチが正しいです。

Table CARPRODUCTION [MODEL (PK), COUNTRY (PK), COUNT]

これはすべての人に会うでしょう。

于 2012-12-30T04:56:57.393 に答える