数据库表中ID列的命名

时间:2008-10-16 13:34:43

标签: sql naming-conventions

我想知道人们对数据库表中ID列命名的看法。

如果我有一个名为Invoices的表,其中包含一个标识列的主键,我会将该列调用为InvoiceID,这样我就不会与其他表冲突,而且它显然是什么。

我工作当前他们已经调用了所有ID列ID。

所以他们会做以下事情:

Select  
    i.ID 
,   il.ID 
From
    Invoices i
    Left Join InvoiceLines il
        on i.ID = il.InvoiceID

现在,我在这里看到一些问题:
1.您需要为选择的列添加别名 2. ID = InvoiceID不适合我的大脑
3.如果您没有对表进行别名并且引用了InvoiceID,它显然在哪个表上?

其他人对这个话题的看法是什么?

24 个答案:

答案 0 :(得分:132)

我总是首选ID为TableName + ID为id列,然后是TableName + ID为外键。这样,所有表都具有id字段的相同名称,并且没有冗余描述。这对我来说似乎更简单,因为所有表都具有相同的主键字段名称。

就连接表而不知道哪个Id字段属于哪个表而言,我认为应该编写查询来处理这种情况。在我工作的地方,我们总是优先使用表/表别名在语句中使用的字段。

答案 1 :(得分:45)

最近我家公司对这件事情进行了一次书呆子斗争。 LINQ的出现使得冗余的 tablename + ID 模式在我眼中显得更加愚蠢。我认为大多数合理的人都会说,如果你手写这样的方式,你必须指定表名来区分 FKs 那么它不仅可以节省打字,而且还可以增加您的SQL清晰度只使用ID,因为您可以清楚地看到哪个是 PK ,哪个是 FK

E.g。

FROM Employees e     LEFT JOIN Customers c ON e.ID = c.EmployeeID

不仅告诉我这两个是链接的,而且是 PK ,这是 FK 。然而,在旧式中,你不得不看起来或希望它们被命名为好。

答案 2 :(得分:29)

我们使用的是InvoiceID,而不是ID。它使查询更具可读性 - 当您单独看到ID时,它可能意味着什么,尤其是当您将表别名为i时。

答案 3 :(得分:20)

我同意Keven和其他一些人的观点,表格的PK应该只是Id而外键列出了OtherTable + Id。

但是,我希望补充一个最近对这一论点给予更多重视的理由。

在我目前的职位上,我们正在使用POCO生成的实体框架。使用Id的标准命名约定,PK允许继承具有验证的基础poco类,例如对于共享一组公共列名的表。使用Tablename + Id作为每个表的PK会破坏为这些表使用基类的能力。

只是一些值得思考的东西。

答案 4 :(得分:20)

ID是SQL Antipattern。 见http://www.amazon.com/s/ref=nb_sb_ss_i_1_5?url=search-alias%3Dstripbooks&field-keywords=sql+antipatterns&sprefix=sql+a

如果您有许多ID为ID的表,那么您报告的难度要大得多。它模糊了含义并使复杂查询更难以阅读,并要求您使用别名来区分报表本身。

此外,如果某人愚蠢到在可用的数据库中使用自然联接,您将加入错误的记录。

如果您想使用某些dbs允许的USING语法,则不能使用ID。

如果您使用ID,如果碰巧正在复制连接语法,那么很容易就会出现错误的连接(不要告诉我没有人这样做过!)并且忘记更改连接条件中的别名。

所以你现在有了

select t1.field1, t2.field2, t3.field3
from table1 t1 
join table2 t2 on t1.id = t2.table1id
join table3 t3 on t1.id = t3.table2id

当你意味着

select t1.field1, t2.field2, t3.field3 
from table1 t1 
join table2 t2 on t1.id = t2.table1id
join table3 t3 on t2.id = t3.table2id

如果你使用tablenameID作为id字段,这种意外错误发生的可能性要大得多,而且更容易找到。

答案 5 :(得分:10)

这并不重要,您可能会遇到所有命名约定中的simalar问题。

但重要的是要保持一致,这样每次编写查询时都不必查看表定义。

答案 6 :(得分:10)

我的首选项也是主键的ID和外键的TableNameID。我还想在大多数表中都有一个列“name”,其中我保存了条目的用户可读标识符(即名称:-))。这种结构在应用程序本身提供了极大的灵活性,我可以以相同的方式处理大量表格。这是非常强大的功能。通常,OO软件构建在数据库之上,但是由于db本身不允许,因此无法应用OO工具集。列id和名称仍然不是很好,但这是一个步骤。

  

选择
      i.ID,il.ID来自       发票我       左加入InvoiceLines il           在i.ID = il.InvoiceID

为什么我不能这样做?

Select  
    Invoices.ID 
,   InvoiceLines.ID 
From
    Invoices
    Left Join InvoiceLines
        on Invoices.ID = InvoiceLines.InvoiceID

在我看来,这是非常易读和简单的。将变量命名为i和il通常是一个糟糕的选择。

答案 7 :(得分:7)

我刚开始在一个只使用“ID”的地方工作(在核心表中,在外键中由TableNameID引用),并且已经发现了直接由它引起的两个生产问题。

在一种情况下,查询使用“...其中ID为(SELECT ID FROM OtherTable ...”而不是“...其中ID为(SELECT TransID FROM OtherTable ...”。

任何人都可以诚实地说,如果使用完整,一致的名称,错误的陈述会读到“......其中TransID in(SELECT OtherTableID from OtherTable ......”),那么就不会更容易发现吗?我不知道不这么认为。

重构代码时会出现另一个问题。如果您使用临时表,而以前查询从核心表中删除,则旧代码读取“... dbo.MyFunction(t.ID)...”,如果没有更改,但“t”现在指的是临时表而不是核心表,你甚至没有得到错误 - 只是错误的结果。

如果产生不必要的错误是一个目标(也许有些人没有足够的工作?),那么这种命名约定很棒。否则,一致的命名是可行的方法。

答案 8 :(得分:6)

为简单起见,大多数人都会在表ID上命名列。如果它在另一个表上有一个外键引用,那么在连接的情况下它们明确地称它为InvoiceID(使用你的例子),你是对表的别名,所以显式的inv.ID仍然比inv.InvoiceID简单

答案 9 :(得分:4)

从正式数据字典的角度出发,我将数据元素命名为invoice_ID。通常,数据元素名称在数据字典中将是唯一的,并且理想地在整个过程中具有相同的名称,但是有时可能需要基于上下文的附加限定条件,例如,名为employee_ID的数据元素可以在组织结构图中使用两次,因此分别限定为supervisor_employee_IDsubordinate_employee_ID

显然,命名约定是主观的,是一种风格问题。我发现ISO / IEC 11179指南是一个有用的起点。

对于DBMS,我将表视为entites的集合(除了那些只包含一行的表,例如cofig表,常量表等),例如我的employee_ID是密钥的表格将被命名为Personnel。所以TableNameID惯例直接对我不起作用。

我已经看到大型数据模型上使用的TableName.ID=PK TableNameID=FK样式,并且不得不说我觉得它有点令人困惑:我更喜欢标识符的名称在整个过程中是相同的,即不会根据发生的表更改名称要注意的是,前面提到的样式似乎是在商店中使用,它们向每个表添加IDENTITY(自动增量)列,同时避开国外的自然和复合键键。那些商店往往没有正式的数据字典,也没有数据模型。同样,这只是一个风格问题,而我个人并不赞同。所以最终,它不适合我。

所有这一切,我可以看到一个案例,当表的名称提供了这样做的上下文时,有时会从列名中删除限定符。名为employee_last_name的元素可能只是last_name表中的Personnel。这里的理由是该域名是“人名”,并且更有可能UNION来自其他表的last_name,而不是用作外键另一张桌子中,但又一次......我可能会改变主意,有时你永远无法分辨。事情就是这样:数据建模是部分艺术,部分科学。

答案 10 :(得分:4)

个人更喜欢(如上所述) PK TableID Table.ID >对于 FK 。甚至(请不要拍我)Microsoft Access建议这样做。

但是,我也知道有些生成工具支持PK的TableID,因为它们倾向于链接包含'ID'的所有列名, INCLUDING ID! !!

即使查询设计器在Microsoft SQL Server上执行此操作(对于您创建的每个查询,最终都会删除列ID上所有表上不必要的新创建的关系)

就像我的内部OCD讨厌它一样,我推出 TableID 约定。让我们记住,它被称为数据 BASE ,因为它将成为许多许多应用程序的基础。并且所有技术都应该受益于具有清晰描述模式的良好规范化。

不言而喻,当人们开始使用TableName,TableDescription等时,我会画出我的线条。在我看来,惯例应该做到以下几点:

  • 表名:多元化。防爆。的雇员
  • 表别名:全表名称,单数化。实施例

    SELECT Employee.*, eMail.Address
    FROM Employees AS Employee LEFT JOIN eMails as eMail on Employee.eMailID = eMail.eMailID -- I would sure like it to just have the eMail.ID here.... but oh well
    

<强> [更新]

此外,由于“关系类型”或角色,此主题中有一些关于重复列的有效帖子。例如,如果商店有 EmployeeID ,则告诉我蹲下。所以我有时会做像 Store.EmployeeID_Manager 这样的事情。当然它有点大,但在人们不会发疯,试图找到表ManagerID ,或 EmployeeID 在那里做什么。当查询是在哪里我会简化为:     选择EmployeeID_Manager作为ManagerID

答案 11 :(得分:2)

我的投票是针对表ID的InvoiceID。当它用作外键时我也使用相同的命名约定,并在查询中使用智能别名。

 Select Invoice.InvoiceID, Lines.InvoiceLine, Customer.OrgName
 From Invoices Invoice
 Join InvoiceLines Lines on Lines.InvoiceID = Invoice.InvoiceID
 Join Customers Customer on Customer.CustomerID = Invoice.CustomerID

当然,它比其他一些例子更长。但微笑。这是为了后代,有一天,一些可怜的初级程序员将不得不改变你的杰作。在这个例子中没有歧义,并且随着额外的表被添加到查询中,你会感激冗长。

答案 12 :(得分:2)

我认为只要你保持一致,你就可以使用“ID”。包括表名是很重要的。我建议使用像Erwin这样的建模工具来强制执行命名约定和标准,这样在编写查询时,很容易理解表之间可能存在的关系。

我的意思是第一个声明是,你可以使用像'recno'这样的东西而不是ID。那么这个表将有一个invoice_recno的PK,依此类推。

干杯, 本

答案 13 :(得分:1)

我所做的是为了保持自己的一致性(表中有一个列的主键用作ID)是命名表Table_pk的主键。在任何地方,我都有一个指向该表主键的外键,我称之为PrimaryKeyTable_fk列。这样我就知道如果我的Customer表中有Customer_pk而Order表中有Customer_fk,我知道Order表是指Customer表中的一个条目。

对我而言,这对于我认为更容易阅读的联接尤为重要。

SELECT * 
FROM Customer AS c
    INNER JOIN Order AS c ON c.Customer_pk = o.Customer_fk

答案 14 :(得分:1)

FWIW,我们的新标准(改变,呃,我的意思是“演变”,每个新项目)是:

  • 小写数据库字段名称
  • 大写表名称
  • 使用下划线分隔字段名称中的单词 - 将这些单词转换为代码中的Pascal大小写。
  • pk_前缀表示主键
  • _id后缀表示整数,自动递增ID
  • fk_前缀表示外键(不需要后缀)
  • _VW视图后缀
  • is_ booleans的前缀

因此,名为NAMES的表可能包含字段pk_name_id, first_name, last_name, is_alive,fk_company以及名为LIVING_CUSTOMERS_VW的视图,定义如下:

SELECT first_name, last_name
FROM CONTACT.NAMES
WHERE (is_alive = 'True')

正如其他人所说的那样,只要它是一致的并且没有不必要地混淆你的意思,任何计划都会有效。

答案 15 :(得分:1)

如果您为每个密钥指定一个唯一的名称,例如“invoices.invoice_id”而不是“invoices.id”,那么您可以毫无后顾之忧地使用“自然连接”和“使用”运算符。 E.g。

SELECT * FROM invoices NATURAL JOIN invoice_lines
SELECT * FROM invoices JOIN invoice_lines USING (invoice_id)

而不是

SELECT * from invoices JOIN invoice_lines
    ON invoices.id = invoice_lines.invoice_id

SQL足够冗长而不会让它变得更加冗长。

答案 16 :(得分:1)

对于数据库中的列名,我使用“InvoiceID”。

如果我通过LINQ将字段复制到一个未命名的结构中,我可以将其命名为“ID”,如果它是结构中唯一的ID。

如果该列不打算在外键中使用,那么它只用于唯一标识一行以进行编辑编辑或删除,我将其命名为“PK”。

答案 17 :(得分:0)

我更喜欢DomainName || 'ID'。 (即DomainName + ID)

DomainName通常(但不总是)与TableName相同。

ID本身的问题在于它不会向上扩展。一旦你有大约200个表,每个表都有一个名为ID的第一列,数据开始看起来都很相似。如果你总是使用表名来限定ID,那会有所帮助,但不是那么多。

DomainName&amp; ID可用于命名外键和主键。当foriegn键以它们引用的列命名时,可以是助记符助手。形式上,将外键的名称绑定到它引用的键是没有必要的,因为引用完整性约束将建立引用。但是在阅读查询和更新方面它非常方便。

偶尔,DomainName ||不能使用“ID”,因为同一个表中有两列具有相同的名称。示例:Employees.EmployeeID和Employees.SupervisorID。在这些情况下,我使用RoleName || 'ID',如示例中所示。

最后但并非最不重要的是,我尽可能使用自然键而不是合成键。在某些情况下,自然键不可用或不可信,但有很多情况下自然键是正确的选择。在这些情况下,我让自然键采用它自然具有的名称。这个名字通常甚至没有字母“ID”。示例:OrderNo其中No是“Number”的缩写。

答案 18 :(得分:0)

对于每张桌子,我选择一个树形字母速记(例如Employees =&gt; Emp)

这样,数字自动编号主键变为 nkEmp

它很短,在整个数据库中都是独一无二的,我一眼就知道它的属性。

我在SQL和我使用的所有语言中保留了相同的名称(主要是C#,Javascript,VB6)。

答案 19 :(得分:0)

请参阅Interakt网站的naming conventions,了解一个经过深思熟虑的命名表和列系统。该方法对每个表使用后缀(_prd用于产品表,或_ctg用于类别表),并将其附加到给定表中的每个列。因此,products表的标识列为id_prd,因此在数据库中是唯一的。

他们更进一步帮助理解外键:产品表中引用类别表的外键将是idctg_prd,因此很明显它属于哪个表({{1 } suffix)以及它引用的表(类别)。

优点是不同表中的标识列没有歧义,并且您可以一目了然地通过列名称来查询查询所指的列。

答案 20 :(得分:0)

答案 21 :(得分:0)

我完全同意在ID字段名称中包含表名,这完全是您提供的原因。通常,这是我将包含表名的唯一字段。

答案 22 :(得分:0)

我讨厌普通的id名称。我强烈希望始终使用invoice_id或其变体。我总是知道在需要时哪个表是id的权威表,但这让我感到困惑

SELECT * from Invoice inv, InvoiceLine inv_l where 
inv_l.InvoiceID = inv.ID 
SELECT * from Invoice inv, InvoiceLine inv_l where 
inv_l.ID = inv.InvoiceLineID 
SELECT * from Invoice inv, InvoiceLine inv_l where 
inv_l.ID = inv.InvoiceID 
SELECT * from Invoice inv, InvoiceLine inv_l where 
inv_l.InvoiceLineID = inv.ID 

最糟糕的是你提到的混合,完全令人困惑。我不得不使用一个数据库,几乎总是它是foo_id,除了一个最常用的ID。这完全是地狱。

答案 23 :(得分:-2)

您可以使用以下命名约定。它有它的缺点,但它解决了你的特殊问题。

  1. 为表名使用短(3-4个字符)昵称,即发票 - inv,InvoiceLines - invl
  2. 使用这些昵称命名表格中的列,即inv_idinvl_id
  3. 对于参考列,请使用invl_inv_id作为名称。
  4. 这样你可以说

    SELECT * FROM Invoice LEFT JOIN InvoiceLines ON inv_id = invl_inv_id