主键/外键命名约定


95

在我们的开发小组中,我们对主键和外键的命名约定进行了激烈的辩论。我们小组基本上有两种思想流派:

1:

Primary Table (Employee)   
Primary Key is called ID

Foreign table (Event)  
Foreign key is called EmployeeID

要么

2:

Primary Table (Employee)  
Primary Key is called EmployeeID

Foreign table (Event)  
Foreign key is called EmployeeID

我不希望在任何列中重复表的名称(因此,我更喜欢上面的选项1)。从概念上讲,它与其他语言中的许多推荐做法是一致的,在这种情况下,不要在对象的属性名称中使用对象的名称。我认为命名外键EmployeeID(或Employee_ID可能更好)可以告诉读者这是表的IDEmployee

其他一些人则更喜欢选项2,在该选项中,您将主键命名为表名,以使整个数据库中的列名相同。我明白了这一点,但是现在您无法从视觉上区分主键和外键。

另外,我认为将表名包含在列名中是多余的,因为如果您将表视为实体,而将列视为该实体的属性或属性,则将其视为的ID属性,而Employee不是EmployeeID员工的属性。我不走了问我的同事他什么PersonAge或者PersonGender是。我问他他的年龄是多少。

因此,就像我说的那样,这是一场激烈的辩论,我们将继续对此进行讨论。我有兴趣获得一些新观点。



1
我阅读了10多个类似的问题,最后发现这里的前3个答案很好:stackoverflow.com/a/465146/781695
用户

附带说明:选择2将允许您“自然加入”。哎呀,为什么不选择添加“ Employee.ID作为EmployeeID”在选项1中仍然这样做。但是更好的做法似乎是使用“ ON Employee.ID = Event.EmployeeID”进行“加入”。
狮子座

在这两种情况下,您都将不得不在一个或多个查询中使用别名(或“ table_name.column_name”),因为在这两种情况下,您都是在重复列名。
Please_Dont_Bully_Me_SO_Lords '18

Answers:


52

没关系。我从来没有遇到过选择1和选择2真正有区别的系统。

杰夫·阿特伍德(Jeff Atwood)在该主题上发表了一篇不错的文章。基本上,人们最激烈地辩论和争论那些不能被证明是错误的话题。或者从另一个角度来看,那些只能通过基于前人站立论据的耐力风格耐力来赢得的主题。

选择一个,告诉他们专注于实际上影响您的代码的问题。

编辑:如果您想玩得开心,请让他们详细说明为什么他们的方法对递归表引用更优越。


26
+1,常识...还有更多重要的事情要争论..因此,按我的方式做(选择2)
Charles Bretana 09年

5
而且,对于自引用DRI,当有多个以上的FK可以自引用同一PK时,您必须违反这两个“标准”,因为两个FK列不能命名为相同的名称,例如EmployeeTable与EmployeeId PK,SupervisorId FK,MentorId Fk,PartnerId FK等...
Charles Bretana 09年

75

如果两列在两个表中都具有相同的名称(惯例2),则可以在SQL中使用USING语法来节省一些键入内容和一些样板噪声:

SELECT name, address, amount
  FROM employees JOIN payroll USING (employee_id)

支持约定2的另一个论点是,这是关系模型的设计方式。

每列的重要性通过用相应域的名称标记来部分传达。


4
实际上,SQL语法和语义为应该如何使用它提供了很好的线索。例如,使用USING语法意味着具有相同域的列应具有相同的名称,NULL = NULL-> NULL表示NULL是“未知”而不是“不适用”,而ON UPDATE CASCADE意味着键只需要唯一,而不是不变的。
史蒂芬·休伊格

6
更妙的是,它允许这样的:SELECT name, address, amount FROM employees NATURAL JOIN payroll
一天,2012年

5
我不会在已部署的代码中使用自然联接,因为在添加架构的情况下它很脆弱。但是对于交互式查询,它很棒。
史蒂芬·胡维格

3
+1,但总会有例外。例如,如果您在工资单中有两列都是员工的外键(例如,一个引用指向要付款的人,第二个引用具有预算权限的经理)。但是我们不能同时命名两个外键employee_id
Bill Karwin

1
“ using”关键字是MySql特定的。不幸的是,它在T-SQL中不起作用。
birdus

12

我认为这取决于您如何将应用程序组合在一起。如果您使用ORM或设计表来表示对象,那么选项1可能适合您。

我喜欢将数据库编码为自己的层。我控制一切,该应用程序仅调用存储过程。具有完整列名的结果集非常好,尤其是当有许多表联接并且返回了许多列时。对于这种类型的应用程序,我喜欢选项2。我非常喜欢看到联接上的列名匹配。我曾经在旧系统上工作,而旧系统却不匹配,这是一场噩梦,


4
+1表示必须找出列名称不匹配的联接
Raj More

4
在“旧系统”上,长8个字符的长名称的障碍比这大得多。我愿意大步走出去,推测拥有名为ID的PK并不是造成您正在处理的旧系统中噩梦的主要原因。在软件开发中,尤其是在数据库中,也经常使用“吸纳旧系统”。我通常会根据人们在10年前发布的数据库系统上的经验来证明人们对任何给定的实践A都是合理的。
罗素Steen

2
当今的最先进应用将在几年之内成为废品。您甚至可以重写接口,或在其他平台上使用数据,但是您的数据(包括列名)将需要经受时间的考验。
KM。

2
因此,即使他们只有8个字符,二十年前的人们还是应该以某种方式使用今天有意义的列名?数据存储格式在过去20年中发生了巨大变化,并且在接下来的20年中将再次发生变化。没有任何方法可以证明您的偏好会比列出的其他方法更好地经受住时间的考验。随着我们存储和处理数据的能力的提高,当人们进行20年的讨论时,“列名”本身可能就是“废话”。表是不完美地代表数据关系的人为构造……
罗素·斯蒂恩

1
感谢您的理性回应。
罗素Steen

3

两种约定在所有情况下均不起作用,那么为什么要全部采用?使用常识...

例如,对于自引用表,当有多个以上的FK列可对同一表的PK进行自引用时,您将违反两个“标准”,因为两个FK列不能命名为相同的…… ,具有EmployeeId PK,SupervisorId FK,MentorId Fk,PartnerId FK的EmployeeTable ...


1
+1为实际技术目标答案
DVK,2009年

一个好的,适用的答案,但是关于Dems答案的论点没有讲到重点。
JYelton 2010年

3

我同意,他们之间几乎没有选择。对我而言,关于任何一个标准的更重要的事情是“标准”部分。

如果人们开始“做自己的事”,他们应该被他们的地狱所str住。恕我直言 :)


3
+1表示认识到一致性比“正确”更为重要(在这种情况下)
拉塞尔·斯蒂恩

-1,用于尝试应用“愚蠢的一致性”。古老的中国谚语说:“愚蠢的一致性是简单思想的妖精”。
Charles Bretana

@charles:在一个由不同的人维护彼此的代码的世界中,通常在编写者离开并且文档已过时或不存在时,这并不是愚蠢的一致性。我很高兴我不与您合作...
MatBailie

@Dems,无意冒犯,但这是愚蠢的,有两个原因。1)在常见的情况下,很容易理解,会违反任何标准。(请参阅示例和2的答案),因为至少在这个问题上,标准只会增加很少的价值,除了使喜欢标准的人感到更自在...
Charles Bretana 2010年

1
您可能会说“ ID”更一致-因为只要在“汽车”表或“汽车”表中引入英语语言“ carID”?“ sheep”表或“ sheeps”中的“ sheepID”-事情开始变得不一致。如果您坚持使用“ ID”和单一表名-这不仅是一致的,而且在许多ORM中都发挥出色/也需要较少的配置(例如Dapper Contrib)
niico

3

您考虑过以下内容吗?

Primary Table (Employee)   
Primary Key is PK_Employee

Foreign table (Event)  
Foreign key is called FK_Employee

3
当人们投反对票并且不提出理由时,我无法忍受。这是一个完全有效的答案,无论它是否对某些人来说是可口的,都是一个不同的问题,但这是主观的,不需要投反对票。
杰里米

1
感谢您指出了这一点。我也对您使用此格式的原因感兴趣。而且我非常肯定会有很好的理由……
Wouter

这是最好的出路,因为如果您table_name.column_name没有重复的名称,则不必在查询中使用,也不必为列名使用别名...
Please_Dont_Bully_Me_SO_Lords

1
这可以被认为是匈牙利符号的一种形式。因此,考虑赞成和反对的论点。
弗雷德

2

我们在工作的地方使用的约定与A非常接近,除了我们以复数形式(即“员工”)命名表,并在表名和列名之间使用下划线。这样做的好处是,引用一列可以是“ employees _ id”或“ employees.id”,具体取决于您要如何访问它。如果您需要指定该列来自哪个表,则“ employees.employees _ id”绝对是多余的。


我还不确定我是否喜欢复数的表名。通过使用单数,查询看起来更好(“ employee.name”而不是“ employees.name”)。即使在联接中,将单个记录联接到另一个表时,其读取效果也会更好。但是,在考虑表而不是查询时,复数表名似乎更准确。我会坚持使用单数形式,因为这是我们使用的方式,但是我认为这也是正确的做法(尽管同样,很多人不同意)
MatBailie

是的 我想这更多是个人喜好和/或您惯常看到的内容。
贾里特·米拉德

2

如果您正在查看应用程序代码,而不仅仅是数据库查询,那么对我来说,有些事情似乎很清楚:

  1. 表定义通常直接映射到描述一个对象的类,因此它们应该是单数。为了描述对象的集合,我通常在单数名称后附加“ Array”或“ List”或“ Collection”,因为比使用复数更清楚地表明它不仅是一个集合,而且还表示哪种集合它是。在该视图中,我看到的表名称不是集合的名称,而是集合的对象类型的名称。不编写应用程序代码的DBA可能会错过这一点。

  2. 我处理的数据通常将“ ID”用于非密钥识别目的。为了消除键“ ID”和非键“ ID”之间的混淆,对于主键名,我们使用“ Key”(即它的名字,不是吗?),以表名或缩写为表名。该前缀(我仅将其保留给主键)使键名唯一,这尤其重要,因为我们使用的变量名与数据库列名相同,并且大多数类都有一个父级,由父键。这也需要确保它不是保留关键字,仅“ Key”就是保留关键字。为了便于保持键变量名称的一致性,并提供执行自然连接的程序,外键的名称与表中的主键相同。我遇到了不止一次的程序,这些程序使用自然联接可以更好地工作。关于这一点,我承认我使用的自引用表存在问题。在这种情况下,我将外键命名规则作为例外。例如,我将ManagerKey用作Employee表中的外键指向该表中的另一条记录。


许多对象关系映射器(ORM)(例如Entity Framework)都允许您将表映射到具有不同名称的类。这使您可以拥有一个名为“ User”的类和一个名为“ Users”的表。
弗雷德

2

我喜欢约定#2-在研究此主题时,在发布自己的问题之前发现了这个问题,我遇到了以下问题:

我从具有大量列的表中选择*,并将其连接到同样具有大量列的第二个表中。这两个表都有一个“ id”列作为主键,这意味着我必须专门挑选每一列(据我所知),以使这两个值在结果中唯一,即:

SELECT table1.id AS parent_id, table2.id AS child_id

虽然使用约定#2手段我仍然会在具有相同名称的结果某些列,我现在可以指定 ID我需要(父母或子女),正如史蒂芬Huwig建议,该USING语句简化的东西进一步。


2
SELECT *无论如何,(大多数)生产查询都是不可以的,因此选择命名标准并不是很多原因。
P Daddy

1
不能不同意:您能提供一个链接到为什么这样的原因吗?我不喜欢必须在查询中保留80列的名称的想法。
JYelton

目前无法找到链接(很难用Google搜索“ *”),但我将概述以下要点:(1)对表的更改可能会对您的应用程序产生负面影响,(2)可能是(3)明确指定实际需要的数据可以使您的代码更易于理解。这些观点可能会扩展,并且有一些例外(如我所暗示),但这在这里不合适。如果您将此问题发布为一个新问题,我(和其他人)将很乐于进一步阐述。
P Daddy

2
我可以那样做。我意识到性能的好处,但是在编辑代码时必须考虑时间上的花费。我一直在寻找改善应用程序与数据库之间交互的方法。谢谢。
JYelton

1
我不确定SELECT *大多数生产查询是否都可以。如果它显着提高了开发速度,并使代码更加简洁和易读-使您可以专注于更重要的事情-为什么不SELECT *呢?它在很大程度上取决于每种情况的情况,并且是许多因素之间的权衡。一个规则很少适合所有情况。
niico

2

我一直使用userId在一个表上将用作PK,在另一个表上将userId用作FK。我正在认真考虑使用userIdPKuserIdFK作为名称来彼此标识。在查看表时,它将帮助我快速识别PK和FK,并且看起来当使用PHP / SQL访问数据时,它将清除代码,从而更易于理解。特别是当其他人查看我的代码时。


1

我使用约定#2。我现在正在使用旧式数据模型,在该模型中我不知道给定表中的含义。冗长的地方有什么害处?


1

如何命名外键

角色编号

其中角色是引用实体相对于当前表的角色。这解决了递归引用和对同一表的多个fks的问题。

在许多情况下将与引用的表名称相同。在这种情况下,它与您的建议之一相同。

无论如何,长期争论是一个坏主意


0

“在“员工INNER JOIN订单ON order.employee_id = employee.id”中,是否需要其他资格?

不需要额外的资格认证,因为我所说的资格认证已经存在。

“业务用户引用订单ID或雇员ID的原因是为了提供上下文,但是在dabase级别,您已经具有上下文,因为您正在引用表”。

祈祷,告诉我,如果该列被命名为“ ID”,那么该“引用表”是如何精确完成的,除非完全按照我所说的方式对ID列的引用进行限定?

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.