我想知道人们对数据库表中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,它显然在哪个表上?
其他人对这个话题的看法是什么?
答案 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_ID
和subordinate_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,我们的新标准(改变,呃,我的意思是“演变”,每个新项目)是:
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)
您可以使用以下命名约定。它有它的缺点,但它解决了你的特殊问题。
inv
,InvoiceLines - invl
inv_id
,invl_id
invl_inv_id
作为名称。这样你可以说
SELECT * FROM Invoice LEFT JOIN InvoiceLines ON inv_id = invl_inv_id