私のt-sqlの先生は、私たちのPK列に "Id"という名前を付けることは、それ以上の説明なしに悪い習慣であると考えられると私たちに言いました。
テーブルのPK列に「Id」という名前を付けることが悪い習慣と見なされるのはなぜですか?
私は出てきてそれを言うつもりです:それは本当に悪い習慣ではありません(そしてそれがたとえそうであったとしても、それはそれではない悪い)。
次のクエリのようにエラーをマスクできる引数( Chad が指摘されている)を作成できます。
SELECT *
FROM cars car
JOIN manufacturer mfg
ON mfg.Id = car.ManufacturerId
JOIN models mod
ON mod.Id = car.ModelId
JOIN colors col
ON mfg.Id = car.ColorId
しかし、これはテーブル名に小さなエイリアスを使用しないことで簡単に軽減できます。
SELECT *
FROM cars
JOIN manufacturer
ON manufacturer.Id = cars.ManufacturerId
JOIN models
ON models.Id = cars.ModelId
JOIN colors
ON manufacturer.Id = cars.ColorId
常に3文字の略語を使用する習慣は、列名id
を使用するよりもずっと悪いようです。 (適切な例:実際にテーブル名cars
をcar
に短縮するのは誰ですか?何が目的ですか?)
重要なのは、一貫していることです。会社でIdを使用していて、一般的に上記のエラーが発生する場合は、完全なテーブル名を使用する習慣をつけてください。会社がId列を禁止している場合は、それを一歩踏み込んで、好きな命名規則を使用してください。
このような問題を検討するのではなく、実際に悪い習慣(複数のネストされた相関サブクエリなど)を学ぶことに集中してください。列に「ID」という名前を付けることの問題は、悪い習慣よりも好みの問題に近いものです。
編集者への注記:このクエリのエラーは意図的であり、ポイントを作成するために使用されています。編集する前に回答全体をお読みください。
外部キーを持つテーブルがある場合、その外部キーに「Id」という名前を付けることはできないためです。 TableIdというテーブル名があります
そして、あなたの結合は次のようになります
SELECT * FROM cars c JOIN manufacturer m ON m.Id = c.ManufacturerId
そして理想的には、条件は両側で同じフィールド名を持つ必要があります
SELECT * FROM cars c JOIN manufacturer m ON m.ManufacturerId = c.ManufacturerId
したがって、IdをManufacturerIdと名付けるのは冗長に見えますが、間違いが明らかになると、結合条件にエラーが発生する可能性が低くなります。
これは簡単に見えますが、いくつかのテーブルを結合すると、間違いを犯す可能性が高くなります。以下のテーブルを見つけてください...
SELECT *
FROM cars car
JOIN manufacturer mfg
ON mfg.Id = car.ManufacturerId
JOIN models mod
ON mod.Id = car.ModelId
JOIN colors col
ON mfg.Id = car.ColorId
一方、適切な名前を付けると、エラーが発生します...
SELECT *
FROM cars car
JOIN manufacturer mfg
ON mfg.ManufacturerId = car.ManufacturerId
JOIN models mod
ON mod.ModelId = car.ModelId
JOIN colors col
ON mfg.ManufacturerId = car.ColorId
Idに名前を付けるもう1つの理由は、複数のテーブルから情報を照会するときに、Id列の名前を変更して区別できるようにする必要があるためです。
SELECT manufacturer.Id as 'ManufacturerId'
,cars.Id as 'CarId'
--etc
FROM cars
JOIN manufacturer
ON manufacturer.Id = cars.Id
名前が正確であれば、これはそれほど問題ではありません
RubyのActiveRecordライブラリとGroovyのGORMは、デフォルトで代理キーに「id」を使用します。私はこの練習が好きです。各列名にテーブル名を複製することは冗長であり、書き込みが面倒で、読み取りが面倒です。
「名前」や「Id」などの共通またはキー列名の前には、TableNameを付ける必要があります。
あいまいさをなくし、検索が容易になり、両方の「Id」値が必要な場合に列のエイリアスがはるかに少なくなります。
使用頻度が低いか、監査列または非キー(LastUpdatedDateTimeなど)は関係ありません
このスレッドは無効ですが、Id
を使用するIMOではなくを追加することは悪い習慣です。 Id
列は特別です。 the主キーです。どのテーブルにも任意の数の外部キーを含めることができますが、プライマリキーとなることができるキーは1つだけです。すべての主キーがId
と呼ばれるデータベースでは、テーブルを見るとすぐに、どの列が主キーであるかが正確にわかります。
私を信じてください。今月、私は毎日たくさんの大きなデータベース(Salesforce)で作業していて、スキーマについて言えることはすべてのテーブルにId
という主キーがあるということです。 PKはId
と呼ばれているため、主キーを外部キーに結合することについて混乱することは絶対にありません。人々が言及していないもう1つのことは、テーブルがTable_ThatDoesGood_stuff__c
のようなばかげた長い名前を持つ可能性があることです。アーキテクトがそのテーブルを考えた朝に二日酔いがあったので、その名前は十分に悪いですが、主キーTable_ThatDoesGood_stuff__cId
を呼び出さないのは悪い習慣だと教えています(SQL列名が含まれていないことを思い出してください)一般的な大文字と小文字が区別されます)。
正直なところ、コンピュータプログラミングを教えるほとんどの人の問題は、彼らが何年もプロダクションコードのラインを書いておらず、実際に働いているソフトウェアエンジニアが実際に何をしているのかわからないことです。仕事を始めるまで待ってから、自分が良いアイデアだと思うかどうかを決めてください。
ブーム、質問は答えました。
さて、先生に言ってくださいSO悪いデータベース設計を実践してください。
私はそれを悪い習慣とは考えていません。いつものように、一貫性は王様です。
私はそれはすべて文脈についてだと思います。テーブル自体のコンテキストでは、「id」はまさに期待するものを意味します。それ以外の場合は同一(または表示)である可能性のある他のものに対して一意に識別するのに役立つラベルです。
結合のコンテキストでは、自分とチームが読みやすいように結合を作成するのはユーザーの責任です。言い回しやネーミングが悪いと物事を難しく見せるのと同じように、エイリアスやコメントを効果的に使用して、意味のあるクエリを作成することも同様に可能です。
同様に、Java「Foo」と呼ばれるクラスには、「Foo」という接頭辞のプロパティがありません。テーブルIDにテーブル名の接頭辞を付ける必要はありません。通常は、 コンテキスト内参照されているIDは何ですか。
テーブルで自然な結合を実行するのは難しく(そして混乱します)、そのため、ええ、それは非常に悪いことではありません。
Natural Joinは、SQL Lore(つまり、リレーショナル代数)の古代のアーティファクトであり、次のいずれかを見たことがあるかもしれません。つまり、Natrual Joinは、DBMSがそれを実装するのに永遠にかかるように思われたとしても、新しい手間のかかるSQLアイデアではありません。今日ではその存在。
まあ、すべての主キーのIDに名前を付けると、自然な結合の容易さと単純さが失われます。 select * from dudes natural join cars
書く必要がありますselect * from dudes inner join cars where cars.dudeid = dudes.id
またはselect * from dudes inner join cars where dudes.carid = cars.id
。自然な結合を行うことができれば、関係が実際に何であるかを無視することができます。これはかなり素晴らしいと思います。
すべてのテーブルに「ID」を付けるのが最善の方法ではない場合があります。サポートされている場合は、USING
キーワードです。 MySQLでよく使用されます。
たとえば、fooTable
に列fooTableId
があり、barTable
に外部キーfooTableId
がある場合、クエリは次のように構成できます。
SELECT fooTableId, fooField1, barField2 FROM fooTable INNER JOIN barTable USING (fooTableId)
入力を節約するだけでなく、他の方法に比べてはるかに読みやすくなっています。
SELECT fooTable.Id, fooField1, barField2 FROM fooTable INNER JOIN barTable ON (fooTable.Id = barTable.foTableId)
先生に聞いてみませんか?
これについて考えてください。すべてのテーブルのPK列にID
という名前が付いていると、それらを外部キーとして使用することが悪夢になります。
列名は意味的に重要である必要があります。 ID
は総称です。
IDは次の理由で不良です:
多くのレポートクエリを実行する場合、両方を表示するには、常に列にエイリアスを設定する必要があります。したがって、最初に適切に名前を付けることができると、時間の無駄になります。これらの複雑なクエリは、不必要な作業を行うという追加の負担がなければ、非常に困難です(何百行ものクエリを作成します)。
コードエラーが発生する可能性があります。自然結合の使用を許可するデータベースを使用する場合(これを使用する必要があるとは思わないが、機能が利用可能な場合は誰かがそれらを使用する)、それを使用する開発者を取得すると、間違ったものに参加することになります。
結合をコピーして複雑なクエリを作成する場合、エイリアスを必要なものに変更することを忘れがちで、不正な結合が発生します。各IDがそれが含まれているテーブルに基づいて名前が付けられている場合、通常は構文エラーが発生します。また、pPK名とFK名が一致する場合は、複雑なクエリでの結合が正しくない場合も簡単に見つけることができます。
Idを主キーフィールドとして使用する方法は、IDがすべてのテーブルに追加される方法につながります。多くのテーブルには、レコードを一意に識別する一意の情報が既に含まれています。すべてのテーブルに追加するidフィールドではなく、THATを主キーとして使用します。これは、リレーショナルデータベースの基盤の1つです。
そして、それがidの使用が悪い習慣である理由です:idはしばしば単なる自動増加の情報ではありません。
次の表を検討してください。
PK id | Countryid | Countryname
1 | 840 | United States
2 | 528 | the Netherlands
このテーブルの何が問題なのは、ユーザーが別の行を追加できることです:国コード840の米国。これは、リレーショナル整合性を壊しました。もちろん、個々の列に一意性を適用することも、すでに利用可能な主キーを使用することもできます。
PK Countryid | Countryname
840 | United States
528 | the Netherlands
こうすることで、すでに持っている情報を主キーとして使用できます。これは、リレーショナルデータベース設計の中心です。
テーブルの主キーの列名として "id"を使用しないことの最も重要な理由、つまり一貫性とあいまいさの低減について、いくつかの回答があります。
しかし、私にとって重要な利点は、メンテナンスプログラマ、特に元の開発に関与していなかったプログラマによって実現されました。 PersonテーブルのIDに「PersonID」という名前を使用し、その名前を一貫して外部キーとして使用した場合、スキーマに対してクエリを記述して、「PersonID」を推測する必要なしに、PersonIDがあるテーブルを見つけることは簡単です。外部キーの場合に使用される名前です。正しいか間違っているかにかかわらず、すべてのプロジェクトで外部キーの関係が常に適用されるわけではありません。
1つのテーブルが同じテーブルへの2つの外部キーを必要とするEdgeケースがありますが、そのような場合は、元のキー名を列のサフィックス名として置くため、ワイルドカード一致%PersonIDで簡単に見つけることができますそれらのインスタンスも同様です。
はい、これの多くは、「id」を持ち、それを常に「tableNameID」として使用することを知っているという標準によって達成できますが、そのためには、プラクティスが実施されていることを知っていることと、元の開発者に依存してless直感的な標準的な練習。
長い列名を書き出すには追加のキーストロークが必要だと指摘する人もいますが、コードの記述はプログラムのアクティブライフのごく一部にすぎないと私は推測します。開発者のキーストロークを保存することが目的の場合は、コメントを記述しないでください。
何百ものテーブルを持つ大規模なプロジェクトを何年も維持してきた人として、テーブル全体でキーの名前に一貫性を持たせることを強くお勧めします。
私は常に使用するフレームワーク(Ruby on Rails、CakePHP)の規則であるため、すべてのテーブルのプライマリ列名として「id」を常に使用しているため、常にオーバーライドする必要はありません。
それは私にとって学問的な理由に勝るものではありません。
IDは十分に一般的で、誰も混乱させることはないと思います。あなたはいつもテーブルを知りたいと思うでしょう。テーブル/エイリアスを含めずにフィールド名を製品コードに入れることは悪い習慣です。アドホッククエリをすばやく入力できるかどうかについて過度に心配している場合は、自分で判断してください。
IDが予約語であるSQLデータベースを開発する人がいないことを願っています。
CREATE TABLE CAR (ID);
フィールド名、主キー、および1から始まる自動インクリメントをすべて1つのニースの小さな2文字パッケージで処理します。ああ、私はそれをCARSと呼んでいたでしょうが、キーストロークを節約するつもりで、CARというテーブルには1つしかないと思う人がいるとしたらどうでしょう。
この質問は何度も打たれましたが、私も私の意見を付け加えたいと思いました。
Idを使用して、それが各テーブルの識別子であることを意味します。そのため、テーブルに結合して主キーが必要になると、自動的に主キーに結合します。
Idフィールドは、署名なしの自動インクリメントです(つまり、値を設定する必要がなく、負にすることはできません)。
外部キーの場合、tablenameidを使用します(これもスタイルの問題です)。ただし、結合する主キーはテーブルのidフィールドであるため、一貫性があるため、常に簡単にクエリをチェックできます
iDも短くて甘い
追加の規則-すべてのテーブル名と列名に小文字を使用するので、大文字小文字による問題は見つかりません
私はここの人々がほぼすべての側面をカバーしていることを見つけましたが、「ID」は「識別子」としてではなく、「識別子」として読むべきではないことを追加したいと思います。 (ここでは間違った表現を使用している可能性があります。もし間違っていた場合は修正してください)
それは、多かれ少なかれ、人々がテーブルデータを読み取る方法と、コードを記述する方法です。私個人としては、これが最も頻繁に見られる最も一般的な方法であり、プログラマーが完全なリファレンスをtable.id
、ユニオンまたは結合を行う必要がない場合でも。例えば:
SELECT cars.color, cars.model FROM cars WHERE cars.id = <some_var>
そうすれば、「番号が付けられた車の色とモデルを教えて」と英語に翻訳できます。 「番号で識別されるその車の色とモデルを教えて」ではありません。 IDは自動車を表すものではなく、自動車のインデックス、シリアル番号のみです。配列から3番目の要素を取得する場合と同様です。
つまり、私が追加したかったことを要約すると、それは好みの問題であり、SQLの記述された読み取り方法が最も人気があるということです。
ただし、IDが実際に説明する文字列である場合(はるかにまれな例)など、これが使用されない場合もあります。例えば id = "RedFordMustang1970"
または同様のもの。少なくともこのアイデアを理解するために、これについて説明できたらと思います。
考慮すべきもう1つの点は、主キー名が外部キー名と異なる場合、特定のサードパーティツールを使用できないことです。
たとえば、スキーマをVisioなどのツールにロードして、正確なERDを生成させることはできません。