データベースの列にラベルを付ける効果的な方法は何ですか?


30

データベースの列に次のようにラベルを付けていました。

user_id
user_name
user_password_hash

2つのテーブルを結合する際の競合を避けるために、テーブルをエイリアスする方法についてさらに学んだので、これをやめました。

データベースの列にラベルを付ける効果的な方法は何ですか?どうして?


どのデータベースですか?Oracleでのラベルの付け方は、名前が一致する場合に結合のベースとなる列を自動的に選択する機能があるため、他のほとんどのデータベースとは異なります。
ジョー

@Joe、まあ、私は常にMySQLとSQLite3を使用しましたが、他のほとんどのデータベースに適用されるはずです。
トーマスO

@joeは、Oracleが違うことに気づきませんでした。リンクをお願いできますか?
bernd_k

@bernd_k:私の答えにいくつかのリンクを追加しました
ジョー

回答:


33

あなたの場合、プレフィックスユーザーは冗長です。私たち(担当の開発者)はこれがテーブルユーザーであることを知っているので、なぜuser_すべてのフィールドの前にプレフィックスを追加するのですか?

私があなたに提案することは、より自然なアプローチでそれをすることです。

人の特性は何ですか:姓、名、生年月日、国籍など...

車の特徴は何ですか:モデル、年、色、エネルギーなど

カラムにはできるだけ自然な名前を付ける必要があります。これにより、スキーマは、すべての人にとって、そしてあなたとあなたの後に来るスキーマにとって、より明確になります。これはメンテナンスフェーズとも呼ばれ、メンテナンスを簡単にするためにできることはすべて、努力する価値があります。


1
はい、人々がそうするとき、それは私を激怒させます。また、テーブルをすべてtbl_whateverで呼び出す場合。
ガイウス

これは「クラスワード」の概念にも関連しており、コミュニティでクラスワードが適切である場合と適切でない場合の議論があるようです。(クラスワードは、データの明確なカテゴリまたは分類を特定し、データ名で記述されるデータのタイプを記述し、データ要素に関連付けられたデータの主要な分類を記述します。)
Jon Schoning

17

Spredzyのコメントに加えて、主キーに同じラベル(ID)を付けるので、クエリをその場で作成するときに、「Was it countryID」を検索する代わりに(u.ID = c.ID) 、country_ID、countries_ID、countriesID 、? "


5
DBAがいくつかのテーブルでIDを使用し、他のテーブルでIDを使用することを決定したデータベースで作業をしたことがあります。
トビー

6
通常、tablename.tablename_idを使用します。例:car.car_id; person.person_id。テーブルの単数名。
グラスント

@glasntスマートな決定。
ガリック

1
これは実際には非常に悪い考えであり、SQL USING句を使用する機能を失います(仕様に反します)。
エヴァンキャロル

9

Spredzyの優れた答えに対するDavid Hallの補遺に、私はこれ以上同意できませんでした。シンプルで自然な方法です。テーブルに自然に名前を付ければ、テーブルの混乱は問題になりません。

users.idとcars.idを使用できる場合、users.user_idとcars.car_idを使用する意味はありません。


7

データベーススキーマでは、すべての列にテーブル間で一意の名前を付ける必要があると主張します。その理由はいくつかあります。

  • モデリングの観点から:属性のスープから始め、それをテーブルに正規化します。時間が経つにつれて、非正規化または正規化をさらに行ったり、ビューやマテリアライズドビューを導入したり、新しいテーブルを導入したりする場合があります。すべての列名が一意であれば、これは問題になりません。

  • 次の結合構文を使用できますa JOIN b USING (a_id) JOIN c USING (a_id)。非常に便利で、次の点にも役立ちます。

  • 多数の結合を使用してクエリを実行するか、を使用してマテリアライズドビューを作成SELECT *すると、競合は発生しません(まあ、めったにないかもしれません)。参加を考えてみてperson.nameproduct.namecountry.name、などUrgh。

  • 一般に、大きなクエリがある場合、idどこで何を意味するかを追跡するのは困難です。


たとえば、従業員名とサイト名の列にどのように名前を付けますか?名前ラベル列の冗長性をどのように回避しますか?
Spredzy

@Spredzy:私はただ冗長性を持って行きます。
ピーターアイゼントラウト

1
これらの懸念に対する答え:エイリアス。
すべての取引のジョン

7

例を見てみましょう。次のようになります。

USERS
----
id
username,
password
registration_date

テーブル名は大文字で使用します。これにより、テーブルを簡単に識別できます。名前を付けたばかりの列は、それぞれが表すものです。数字を使用したり、プレフィックスやサフィックスを含めないようにしています。これにより、クエリが非常に単純で簡単になります。

ところで、私はあなたが好きなスタイルを見つけて、それに固執するべきだと思います。頻繁に変更すると、メッセンジャーDBスキーマができてしまいます。


「好きなスタイルを見つけてそれを使い続ける」ための+1。一貫性は、特定の標準に厳密に準拠するよりも優れています(ただし、まだ標準を選択していない場合は、一部の標準が他の標準より優れています)。
ジョンオブオールトレード

5

他のものと同様に、列の一部としてテーブル名を含めないことをお勧めします。ほぼ同じ列名を持つすべてのテーブルが何百もある場合を除き、IDというタイトルの列を持つテーブルが複数ある場合は、必ずテーブル名をプレフィックスとして付けます。

私は最近、開発者の1人が主キーと外部キーの列の先頭にpkとfkを付けることを好む会社を退職しました。これにより、列がpkfk(通常は2つの列に基づく複合主キーで、そのうちの1つの列が別のテーブルへの外部キーであった)で始まる一部の憎悪につながります。


4
それはfk_clusterとしてカウントされますか?
カジ

5

私は、各列名がテーブル名から派生したプレフィックスで始まる環境で働いています。それは私の発明ではありませんが、それでかなり満足しています。

理想的には、列名はデータベース内のすべてのテーブルで一意です。

いくつかの観察:

  • selectステートメントでテーブルが複数回結合される場合、テーブルエイリアスのみが必要です。
  • 列名はテーブル名に適合させる必要があるため、コードスニペットをコピーする際にいくつかの障害を防ぎます。
  • 外部キー列がどのテーブルを指すかを示すのに役立ちます

一般的な考え方:最も重要なのは、各命名規則の一貫性です:-単数と複数(列ではなくテーブルに適用)-主キーと外部キーを識別します(データベースの構造とコンテンツを構築します)-一貫性がある場合あなたは文字列と同じ文字列の短いバリアントを保存します-フラグ、ステータスなどと一貫性があります


3

Spredzyの答えには同意しますが、好みの問題として、under_scoreの代わりにcamelCaseを使用することを追加します。

firstName、lastNameなど。


2
-1。CamelCaseはすべてのデータベースシステムで機能せず、データベースシステムを指定しなかったためです。たとえば、OracleでCamelCaseを使用するのは悪いニュースです(二重引用符を使用して作成する必要がありますが、それ以降は、アクセスする全員がフープをジャンプしてアクセス/使用する必要があります)。なんて悪夢だ。
ScottCher

@ScottCher-Oracleで機能しないことは知りませんでしたが、私はOracle DBAではありません。列名は、最初に問題のDBSによって設定されたルールに準拠する必要があると考えられます。
トビー

3

Oracleの場合、列に「id」、「name」、または一般的な名前を付けないでください。

問題は、古いバージョンではデフォルト Oracleは類似の列名に基づいてテーブルを結合しようとするため、すべての名前を適切に付けた場合、テーブル間のデフォルトの結合句も指定してしまうことです。

ただし、Oracleを使用していない場合でも、複数のテーブルに表示される名前を選択しないことで、2つのテーブルで選択を行うたびにエイリアスを作成する必要がなくなります。

SELECT
  instrument.name as instrument_name,
  instrument.abbr as instrument_abbr,
  source.name     as source_name,
  source.abbr     as source_abbr,
  ...
FROM ...

したがって、複数テーブルの選択が標準である場合、列名を長くすると入力が節約されます。(一度に1つのテーブルのみを使用している場合...本当にリレーショナルデータベースが必要ですか?)

...タイピングを保存すると、Oracleの別の問題が発生します-少なくとも8i(Oracle SQL Tuning and Data Modelingコースを受講したときの現在のバージョン)では、実行計画のキャッシングは、最初の非常に多くの文字にのみ基づいていますクエリ(正確な値を覚えていない... 1024?)、したがって、where句の最後で何かによってのみ変化するクエリ、および抽出する列の本当に長いリストがある場合、実行計画を正しくキャッシュできないため、パフォーマンスが低下する可能性があります。

オラクルは、彼らが良いテーブルとカラム名であると主張するものを選択するためのガイドを持っていました。これは基本的に5〜8文字までの文字を削除するためのガイドですが、私はあまり気にしませんでした。

...

それ以外は次のようになります:

  • 列は常に単数形です(表は常に複数形です)
  • 大文字と小文字が区別されるものがある場合に備えて、すべての名前は小文字です
  • 上記の結果として、キャメルケースの代わりにアンダースコアを使用してください。

更新:Oracleの結合動作に慣れていない人は、Oracle SQLのマスター化に関する最後の例を参照してください。

何が起こった?その理由は、supplier_idのほかに、これら2つのテーブルに共通の名前を持つ別の列のペアがあるという事実にあります。その列は名前です。したがって、サプライヤテーブルとパーツテーブルの間の自然な結合を要求すると、2つのテーブルのsupplier_id列を等しくするだけでなく、2つのテーブルの名前列も同様に結合されます。サプライヤ名は同じサプライヤの部品名と同じではないため、クエリによって行は返されません。

「古い結合構文」(8i以前)では、「NATURAL JOIN」がデフォルトの結合動作でしたが、結合条件を指定しない場合でもそれは変わらないと思います。9iで「NATURAL JOIN」が正式なオプションになった後、一般的な推奨事項は使用しないことでした。これは、列の名前の付け方がおかしくなる可能性があるためです。


4
2番目の段落で「自然結合」を参照していますか?その場合は、SHUDDER ...可能な限り、データベースシステムでテーブルを結合する方法を指定する必要があります。データベースに任せて決定すると、予期しない/一貫性のない結果が生じる可能性があります。さらに、Natural Joinは2つのテーブル間の結合に制限されているため、使いやすさが比較的制限されています。
-ScottCher

2
NATURAL JOINがデフォルトになったことはありません。明示的な結合が行われない場合は、デカルト結合が行われます(つまり、テーブルの各行が他のテーブルの各行に結合されます)。ANSI結合(FROM句で指定された結合)がサポートされる前に、WHERE句で結合を行う必要がありました。
ゲイリー

1
自然結合の場合は-1。関係のないスキーマの変更が結合を壊したり、さらに悪いことに、エラーを引き起こさずにそれらを変更したりすると、あなたは苦痛の世界に入ります。子について考えてください。常に結合フィールドを指定してください。
すべての取引のジョン

2
@ScottCher:「決定するのはデータベースに任せる」-最初に、おそらく「データベース」ではなく「DBMS」を意味します。第二に、OracleにはAIや擬人化メカニズムがありません。むしろ、NATURAL JOIN決定論的です。
いつか

1
@Joe cross joinは、そうであり、常に「デフォルト」です。Oracleはしていない場合を除き、列名にマッチしていないnatural join明示的に使用された
ジャック・ダグラス

1
  1. 二重引用符を使用しないでください。二重引用符を使用する"と、データベースのネイティブの大文字と小文字の折りたたみがオーバーライドされるためです。SQL仕様では、すべての識別子を大文字に変換する必要があります。PostgreSQLなどの一部のデータベースは、それらを小文字に変換します。何も引用されていない場合は、すべてのデータベースで機能し、仕様またはrdbms固有のデフォルトに折りたたむことができます。
  2. under_score(_)を使用します。これは、上記のとおり-camelCaseを使用しないでください。
  3. 使用{entity}_idIDS(およびそれらのIDを指している外部キー)のために。USING句を使用できるからです。結合条件で使用されるグローバルに一意のキー名は、仕様で確立された規則です。

    SELECT *
    FROM employee
    INNER JOIN department
      USING (department_id);
    
      -- compare to
      ON employee.department_id = department.department_id;

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