Naming of ID columns in database tables

I was wondering peoples opinions on the naming of ID columns in database tables.

If I have a table called Invoices with a primary key of an identity column I would call that column InvoiceID so that I would not conflict with other tables and it's obvious what it is.

Where I am workind current they have called all ID columns ID.

So they would do the following:

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

Now, I see a few problems here:
1. You would need to alias the columns on the select
2. ID = InvoiceID does not fit in my brain
3. If you did not alias the tables and referred to InvoiceID is it obvious what table it is on?

What are other peoples thoughts on the topic?

58298 次浏览

We use InvoiceID, not ID. It makes queries more readable -- when you see ID alone it could mean anything, especially when you alias the table to i.

我确实讨厌那个简单的 ID 名字。我强烈希望始终使用发票 _ 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

What's worst of all is the mix you mention, totally confusing. I've had to work with a database where almost always it was foo_id except in one of the most used ids. That was total hell.

为了简单起见,大多数人将列命名为表 ID。如果它在另一个表上有一个外键引用,那么在连接的情况下,它们显式地称之为 InvoiceID (使用您的示例) ,您无论如何都要对该表使用别名,因此显式的 inv.ID 仍然比 inv 简单。发票

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

你可以使用下面的变数命名原则,它有它的缺点,但它能解决你的特殊问题。

  1. Use short (3-4 characters) nicknames for the table names, i.e. Invoice - inv, InvoiceLines - invl
  2. 使用这些昵称为表中的列命名,即 inv_idinvl_id
  3. 对于引用列,名称使用 invl_inv_id

你可以这样说

SELECT * FROM Invoice LEFT JOIN InvoiceLines ON inv_id = invl_inv_id

这其实并不重要,在所有命名约定中都可能遇到类似的问题。

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

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

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

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

I always prefered ID to TableName + ID for the id column and then TableName + ID for a foreign key. That way all tables have a the same name for the id field and there isn't a redundant description. This seems simpler to me because all the tables have the same primary key field name.

至于连接表和不知道哪个 Id 字段属于哪个表,我认为应该编写查询来处理这种情况。在我工作的地方,我们总是使用带有 table/table 别名的语句中的字段作为首选项。

如果您为每个键赋予一个惟一的名称,例如,“ invices. 發票 _ id”代替了“ invices.id”,那么您就可以毫不犹豫地使用“自然 join”和“ using”操作符。例如。

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 已经足够冗长了,不需要让它变得更加冗长。

我认为你可以用任何东西作为“ ID”,只要你始终如一。包含表名对于。我建议使用 Erwin 这样的建模工具来强制执行命名约定和标准,这样在编写查询时就可以很容易地理解表之间可能存在的关系。

我所说的第一个语句的意思是,您可以使用类似于“ recno”的其他语句来代替 ID。因此,这个表的 PK 应该是环形发票 _ recno,以此类推。

干杯, 本

Theres been a nerd fight about this very thing in my company of late. The advent of LINQ has made the redundant 表名 + ID pattern even more obviously silly in my eyes. I think most reasonable people will say that if you're hand writing your SQL in such a manner as that you have to specify table names to differentiate FK then it's not only a savings on typing, but it adds clarity to your SQL to use just the ID in that you can clearly see which is the PK and which is the FK.

例如。

员工 e 左加入客户 c ON e.ID = c. EmployeeID

不仅告诉我这两个是相连的,而且告诉我哪个是 < em > PK ,哪个是 FK。而在旧的风格,你被迫要么看或希望他们被命名好。

我认为 InvoiceID 应该用于表 ID。当它被用作外键时,我也使用相同的变数命名原则,并在查询中使用智能化别名。

 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

当然,它比其他一些例子要长。但要微笑。这是为了子孙后代,总有一天,某个可怜的初级程序员将不得不改变你的杰作。在这个示例中,没有模棱两可的地方,并且随着向查询添加额外的表,您将会感激冗长的内容。

Coming at this from the perspective of a formal data dictionary, I would name the data element invoice_ID. Generally, a data element name will be unique in the data dictionary and ideally will have the same name throughout, though sometimes additional qualifying terms may be required based on context e.g. the data element named employee_ID could be used twice in the org chart and therefore qualified as supervisor_employee_ID and subordinate_employee_ID respectively.

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

对于 DBMS,我把表看作是实体的集合(除了那些只包含一行的表,例如 cofig 表、常量表等) ,例如 employee_ID为键的表将被命名为 Personnel。所以 TableNameID公约直接对我不起作用。

我见过在大型数据模型中使用的 TableName.ID=PK TableNameID=FK样式,不得不说我觉得它有点令人困惑: 我更喜欢标识符的名称在整个过程中保持不变,即不会根据它出现在哪个表中而改变名称。值得注意的是,前面提到的样式似乎在商店中使用,这些商店向 每个表中添加 IDENTITY(自动增量)列,同时避免使用外键中的自然键和复合键。这些商店往往没有正式的数据字典,也不从数据模型构建。再说一次,这只是一个风格问题,我个人并不赞同这个问题。所以归根结底,这不适合我。

All that said, I can see a case for sometimes dropping the qualifier from the column name when the table's name provides a context for doing so e.g. the element named employee_last_name may become simply last_name in the Personnel table. The rationale here is that the domain is 'people's last names' and is more likely to be UNIONed with last_name columns 来自 other tables rather than be used as a foreign key 进去 another table, but then again... I might just change my mind, sometimes you can never tell. That's the thing: data modelling is part art, part science.

我更喜欢 DomainName | | ‘ ID’(即 DomainName + ID)

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

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

DomainName & ID 可以用来命名外键和主键。当外键以它们引用的列命名时,可以起到助记符的作用。在形式上,不需要将外键的名称与其引用的键绑定,因为参照完整性约束将确定引用。但是在读取查询和更新时,它非常方便。

有时不能使用 DomainName | | ‘ ID’,因为同一个表中有两列具有相同的名称。例子: 雇员。雇员身份证及雇员。主管 ID。在这些情况下,我使用 RoleName | | ‘ ID’,如示例所示。

最后但同样重要的是,我尽可能使用自然键而不是合成键。有些情况下,自然键不可用或不值得信任,但有很多情况下,自然键是正确的选择。在这些情况下,我让自然键采用它自然会有的名称。这个名字通常都没有字母‘ ID’在里面。示例: OrderNo,其中 No 是“ Number”的缩写。

对于每个表,我选择一个树形字母速记(例如,Employes= > Emp)

这样,数字自动编号主键就变成了 nkEmp

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

我在 SQL 和所有我使用的语言(大部分是 C # ,Javascript,VB6)中使用相同的名称。

参见 Interakt 站点的 命名约定,了解一个经过深思熟虑的表和列命名系统。该方法使用每个表的后缀(产品表为 _prd,类别表为 _ctg) ,并将后缀追加到给定表中的每一列。因此 products 表的 Identity 列应该是 id_prd,因此在数据库中是唯一的。

They go one step further to help with understanding the foreign keys: The foreign key in the product table that refers to the category table would be idctg_prd so that it is obvious to which table it belong (_prd suffix) and to which table it refers (category).

优点是不同表中的标识列没有歧义,并且可以通过列名一目了然地判断查询引用的是哪些列。

为了保持一致性(表中只有一个列主键用作 ID) ,我所做的就是将表 Table_pk的主键命名为。只要有外键指向表的主键,我就调用列 PrimaryKeyTable_fk。这样我就知道,如果在 Customer 表中有一个 Customer_pk,在 Order 表中有一个 Customer_fk,我就知道 Order 表指的是 Customer 表中的一个条目。

To me, this makes sense especially for joins where I think it reads easier.

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

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

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

因此,名为 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')

正如其他人所说的那样,只要方案是一致的,并且不会不必要地混淆你的意思,那么任何方案都是可行的。

I just started working in a place that uses only "ID" (in the core tables, referenced by TableNameID in foreign keys), and have already found TWO production problems directly caused by it.

In one case the query used "... where ID in (SELECT ID FROM OtherTable ..." instead of "... where ID in (SELECT TransID FROM OtherTable ...".

如果使用完整的、一致的名称,而错误的语句会读成“ ... ... 其中 TransID 在(SELECT OtherTableID from OtherTable... ...”,那么有谁能诚实地说这不会更容易发现吗?我不这么认为。

另一个问题发生在重构代码时。如果您使用临时表,而之前的查询离开了核心表,那么旧的代码读取“ ... dbo.Myfunction (t.ID) ...”,如果这没有改变,但“ t”现在指的是一个临时表而不是核心表,您甚至不会得到一个错误-只是错误的结果。

如果产生不必要的错误是一个目标(也许有些人没有足够的工作?)那么这种变数命名原则真是太棒了。否则,一致的命名就是正确的选择。

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

选择
i.ID , il.ID From 发票 左加入发票行 在 i.ID = il. InvoiceID 上

为什么我不能这么做?

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

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

ID 是 SQL 反模式。 参见 href = “ http://www.amazon.com/s/ref = nb _ sb _ ss _ i _ 1 _ 5? url = search-alias% 3D stripbooks & amp; field-keywords = sql + antipattern & amp; sprefix = sql + a”rel = “ norefrer”> 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

when you meant

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 字段,则发生这种偶然错误的可能性要小得多,而且更容易发现。

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

然而,我想补充一个最近更加重视这一论点的理由。

在我目前的职位上,我们正在使用使用 POCO 生成的实体框架。使用 Id 的标准变数命名原则,PK 允许通过验证继承一个基础 poco 类,比如共享一组通用列名的表。使用 Tablename + Id 作为每个表的 PK 会破坏为这些表使用基类的能力。

只是一些思考的食物。

I personally prefer (as it has been stated above) the 桌子,身份证 for the PK and 表格 ID for the FK. Even (please don't shoot me) Microsoft Access recommends this.

然而,我还知道一个事实,一些生成工具偏爱用于 PK 的 TableID,因为它们倾向于链接单词 包括身份证! ! !中包含 'ID'的所有列名

即使是查询设计 Microsoft SQL Server 也是这样做的(对于每个创建的查询,最终都会在列 ID 上的所有表上删除所有不必要的新创建的关系)

因此,尽管我内心的强迫症很讨厌它,我还是遵循 表格 ID惯例。让我们记住,它被称为数据 基地,因为它将成为未来许多应用程序的基础。所有的技术都应该受益于一个描述清晰的规范化模式。

It goes without saying that I DO draw my line when people start using TableName, TableDescription and such. In My opinion, conventions should do the following:

  • Table name: Pluralized. Ex. 雇员
  • 表别名: 完整表名称,单数。

    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
    

[Update]

Also, there are some valid posts in this thread about duplicated columns due of the "kind of relationship" or role. Example, if a Store has an EmployeeID, that tells me squat. So I sometimes do something like Store.EmployeeID_Manager. Sure it's a bit larger but at leas people won't go crazy trying to find table ManagerID, or what EmployeeID is doing there. When querying is WHERE I would simplify it as: SELECT EmployeeID_Manager as ManagerID FROM Store

关于这个问题已经有很多答案了,但是我想补充两个我在上面没有看到的主要问题:

  • 客户来找你寻求支持。

很多时候,客户或用户,甚至其他部门的开发人员遇到了困难,他们联系我们说他们在操作方面遇到了问题。我们问他们对什么唱片有意见。现在,他们在屏幕上看到的数据,例如一个包含客户名称、订单数量、目的地等的网格是许多表的集合。他们说 ID83出了点问题。如果只是叫做“ id”,就没办法知道它是什么 id,是哪个表。

Namely, a row of data does not give any indication which table it is from. Unless you happen to know the schema of your database well, which is rarely the case on complex systems or non-greenfield systems you've been told to take over, you don't know what id=83 means even if you have more data like name, address, etc (which might not even be in the same table!).

这个 id 可能来自网格,也可能来自 API 中的错误,或者错误的查询将错误消息转储到屏幕或日志文件中。

通常,开发人员只是将“ ID”转储到一个列中,然后忘记它,而且 DBs 通常有许多类似的表,比如 Invoice、 InvoiceGrouping、 InvoicePlan 以及它们中任何一个的 ID。无奈之下,您查看代码以确定它是哪一个,并且看到他们在模型中也将其称为 Id,因此必须深入研究页面的模型是如何构造的。我已经数不清有多少次我必须这样做才能知道 Id 是什么。太多了。有时候你还需要挖掘一个 SPROC,它只返回“ Id”作为头部。噩梦。

  • 日志文件在明确哪里出错的情况下更容易处理

通常 SQL 会给出非常糟糕的错误消息。“无法插入 ID 为83的项目,列将被截断”或类似的东西很难调试。错误消息通常没有多大帮助,但是通常被破坏的记录会模糊地尝试通过输出主键名和值来告诉您哪条记录被破坏了。如果是“身份证”那就一点用都没有了。

这只是其他答案中没有提到的两件事。

我也认为很多评论是“如果你用 X 的方式编程,那么这不是问题”,我认为上面的观点(以及关于这个问题的其他观点)是有效的,特别是因为人们编程的方式,因为他们没有时间,精力,预算和远见来编程完美的日志和错误处理,或者改变根深蒂固的快速 SQL 和代码编写习惯。