外键命名方案

Foreign Key naming scheme

提问人:nickf 提问时间:10/14/2008 最后编辑:chills42nickf 更新时间:4/11/2020 访问量:150472

问:

我刚刚开始第一次使用外键,我想知道是否有标准的命名方案可用于它们?

给定这些表格:

task (id, userid, title)
note (id, taskid, userid, note);
user (id, name)

其中,任务具有注释,任务归用户所有,用户创作注释。

在这种情况下,如何命名这三个外键?或者,这到底重要吗

更新:这个问题是关于外键名称,而不是字段名称!

数据库 命名约 定外键

评论

10赞 Charles Burns 11/30/2014
读者须知:下面列出的许多最佳实践在 Oracle 中不起作用,因为它的名称限制为 30 个字符。表名或列名可能已经接近 30 个字符,因此将两者合并为一个名称的约定需要截断标准或其他技巧。
0赞 philipxy 7/8/2019
数据库表中 ID 列的命名可能重复

答:

21赞 EvilTeach 10/14/2008 #1

怎么样 ?FK_TABLENAME_COLUMNNAME

Keep It S 尽可能实现 Stupid。

评论

28赞 JohnC 4/11/2012
因为当你有一个包含大量键和表的大型数据库,并且在软件的模式更新期间出现错误时,如果不搜索数据库创建脚本,就很难找到外键的定义位置。
3赞 David Sherret 6/7/2016
@JohnC如果 FK 列名在列名中有其他表名,那么不是很容易分辨吗?它告诉您两个表以及它所定义的列名。例如: - Animals and Owners 表,在 OwnerID 列上定义FK_Animals_OwnerID
0赞 EvilTeach 7/5/2022
我通常希望错误消息包含 FK 名称。从那里,它是一个简单的查询查找以查找详细信息。
10赞 Steve Moyer 10/14/2008 #2

我通常只留下我的 PK 名称 id,然后在命名其他表中的 FK 时连接我的表名和键列名。我从不为驼峰大小写而烦恼,因为有些数据库会丢弃区分大小写,无论如何都只返回所有大写或小写名称。无论如何,这是我的表格版本的样子:

task (id, userid, title);
note (id, taskid, userid, note);
user (id, name);

请注意,我还用单数来命名我的表,因为一行表示我正在保留的对象之一。其中许多约定是个人喜好。我建议选择一个约定并始终使用它比采用别人的约定更重要。

评论

0赞 nickf 10/14/2008
呵呵 - 这是我实际使用的确切样式(但使用 camelCase)- 我想我会在名称中添加一些额外的描述,以说明它们的联系。
0赞 Steve Moyer 10/14/2008
所以至少我们可以读取彼此的模式;...令人尴尬的是,在缺席几年后无法阅读自己的内容。我们使用 ERWin 来绘制我们的模式,但拥有文本版本通常很方便,并且有一个约定可以让您轻松找到表和字段。
217赞 Greg Beech 10/14/2008 #3

SQL Server 中的标准约定是:

FK_ForeignKeyTable_PrimaryKeyTable

因此,例如,笔记和任务之间的键是:

FK_note_task

任务和用户之间的关键是:

FK_task_user

这使您可以“一目了然”地查看密钥中涉及哪些表,因此可以轻松查看特定表(第一个命名的表)依赖于哪些表(第二个表已命名)。在此方案中,完整的密钥集为:

FK_task_user
FK_note_task
FK_note_user

因此,您可以看到任务依赖于用户,而注释依赖于任务和用户。

评论

1赞 Greg Beech 10/14/2008
如果外键指向第二个表上的候选键而不是主键,则可能会使用名称的第三个段来限定此值。这是一个不寻常的情况,而且不是你通常从头开始设计的情况,所以我没有在回应中包括这一点。
5赞 Greg Beech 10/14/2008
您可以在键中包含当前表名以保持其不同性。FK 名称位于 SQL Server 的全局命名空间中,因此不能将两个名为 FK_PrimaryKeyTable 的 FK 附加到两个不同的外键表。对于其他数据库服务器,规则可能有所不同。
0赞 Steve Moyer 10/14/2008
好。。。我在 Oracle 中的每个表都有不同的命名空间,因此我不需要自我引用。
39赞 Code Commander 1/12/2013
这似乎是常见的用途,但是当有两个外键指向同一个表时,人们会怎么做。即 表有一个,这两个都将成为 .在我看来,出于这个原因,最好使用(在我的示例中fk_message_from_user_id),然后尝试使您的列名清楚地了解目标表(即to_user_id明确指的是用户表)messagefrom_user_idto_user_idfk_message_userfk_tablename_columnname
1赞 Govinda Sakhare 6/18/2015
如果表格本身都有 Ex. user_role 和 user_addresses 的下划线怎么办?fk_user_addresses_user_role不令人困惑?
54赞 onedaywhen 10/14/2008 #4

我使用两个下划线字符作为分隔符,即

fk__ForeignKeyTable__PrimaryKeyTable 

这是因为表名本身偶尔会包含下划线字符。这通常遵循约束的命名约定,因为数据元素的名称通常包含下划线字符,例如

CREATE TABLE NaturalPersons (
   ...
   person_death_date DATETIME, 
   person_death_reason VARCHAR(30) 
      CONSTRAINT person_death_reason__not_zero_length
         CHECK (DATALENGTH(person_death_reason) > 0), 
   CONSTRAINT person_death_date__person_death_reason__interaction
      CHECK ((person_death_date IS NULL AND person_death_reason IS NULL)
              OR (person_death_date IS NOT NULL AND person_death_reason IS NOT NULL))
        ...

评论

4赞 Frederik Krautwald 4/30/2015
这绝对是最好的答案。
1赞 Anddo 10/12/2019
我刚刚创建了具有非常具体命名约定的 Derby DB,这里的这个是最可读和可追溯的。谢谢
1赞 spencer741 2/6/2021
我想只使用表名的事情是......两个指向同一目标表的外键...这就是为什么我可能倾向于包含字段名称的原因......毫无疑问,主题很复杂。
0赞 Chad Kieffer 3/27/2014 #5

根据此处的答案和注释,包含 FK 表、FK 字段和 PK 表 (FK_FKTbl_FKCol_PKTbl) 的命名约定应避免 FK 约束名称冲突。

因此,对于此处给定的表:

fk_task_userid_user
fk_note_userid_user

因此,如果您添加一列来跟踪上次修改任务或注释的人......

fk_task_modifiedby_user
fk_note_modifiedby_user
16赞 bvj 7/14/2014 #6

Microsoft 关于 SQL Server 的说明:

外键约束不必只链接到 PRIMARY 另一个表中的 KEY 约束;它也可以定义为引用 另一个表中 UNIQUE 约束的列。

因此,我将使用描述依赖关系的术语,而不是传统的主要/外国关系术语。

当通过依赖(子)表中类似名称的列引用独立(父)表的 PRIMARY KEY 时,我省略了列名:

FK_ChildTable_ParentTable

引用其他列时,或者列名在两个表之间有所不同,或者只是为了显式:

FK_ChildTable_childColumn_ParentTable_parentColumn

评论

2赞 spencer741 2/6/2021
+1 我发现,虽然很冗长,但你提供的最后一个例子是最不容易混淆和最直接的。我什至会像@onedaywhen在他的回答中建议的那样使用双下划线来处理名称中带有下划线的表格。我个人只在交叉引用表中使用下划线。
-2赞 user12345 8/16/2014 #7

如果您不经常引用 FK 并使用 MySQL(和 InnoDB),那么您可以让 MySQL 为您命名 FK。

稍后,可以通过运行查询来查找所需的 FK 名称

评论

4赞 SSISPissesMeOff 2/18/2016
我只能解释我的反对票。几乎每个数据库系统都允许系统命名约束,您能想象在生产问题期间尝试快速找出 100 个表的数据库,甚至试图破译FK__123ee456ff与什么关系?这很简单,简单地说是一种可怕的做法。当你在这个FK上建立一个索引时,然后呢?系统名称也一样?因此,当索引IX_007e373f5963 98% 是零散的时,您如何知道去哪里寻找原因?它只是不应该这样做。
3赞 Cary Bondoc 1/28/2016 #8

我通常的做法是

FK_ColumnNameOfForeignKey_TableNameOfReference_ColumnNameOfReference

或者换句话说

FK_ChildColumnName_ParentTableName_ParentColumnName

这样,我就可以命名两个引用同一表的外键,例如 with from 表history_info tablecolumn actionBy and actionTousers_info

它会像

FK_actionBy_usersInfo_name - For actionBy
FK_actionTo_usersInfo_name - For actionTo

请注意:

我没有包含子表名称,因为这对我来说似乎是常识,我在子表中,所以我可以很容易地假设子表的名称。它的总字符数为 26 个字符,非常符合 Charles Burns 在此处的评论中所说的 oracle 的 30 个字符限制

读者须知:下面列出的许多最佳实践都不起作用 在 Oracle 中,因为它的名称限制为 30 个字符。表名或 列名可能已经接近 30 个字符,因此约定 将两者合并为一个名称需要截断标准或 其他技巧。——查尔斯·伯恩斯

评论

1赞 Tony Dong 6/13/2017
如果您有第 3 个表,则 FK 指向同一表ParentTableName_ParentColumnName重复FK_Name,则该表将失败
6赞 SSISPissesMeOff 2/18/2016 #9

这可能有点矫枉过正,但它对我有用。当我处理VLDB时,它对我有很大帮助。我使用以下内容:

CONSTRAINT [FK_ChildTableName_ChildColName_ParentTableName_PrimaryKeyColName]

当然,如果由于某种原因您没有引用主键,则必须引用唯一约束中包含的列,在本例中:

CONSTRAINT [FK_ChildTableName_ChildColumnName_ParentTableName_ColumnInUniqueConstaintName]

可以很长吗,是的。它是否有助于保持报告信息清晰,或者让我快速了解潜在问题是在生产警报期间 100% 很想知道人们对这种命名约定的想法。

评论

1赞 Andrei 7/27/2021
在 mysql 中,限制为 64 个字符。所以,你的例子 这是最合适的解决方案,但不能解决所有情况。有时,FK 大于 64 个字符。试想一下,示例中给出的表和列名称是正确的。你的FK名字太长了...FK_ChildTableName_ChildColumnName_ParentTableName_ColumnInUniqueConstaintName
-4赞 coldserenity 6/6/2018 #10

尝试使用大写的版本 4 UUID,第一个八位字节替换为 FK 和“_”(下划线)而不是“-”(破折号)。

例如

  • FK_4VPO_K4S2_A6M1_RQLEYLT1VQYV
  • FK_1786_45A6_A17C_F158C0FB343E
  • FK_45A5_4CFA_84B0_E18906927B53

理由如下

  • 严格的生成算法 => 个统一的名称;
  • 密钥长度小于 30 个字符,这是 Oracle 中的命名长度限制(12c 之前);
  • 如果您的实体名称发生了变化,则不需要像基于实体名称的方法那样重命名 FK(如果 DB 支持表重命名运算符);
  • 人们很少使用外键约束的名称。例如,.DB 工具通常显示约束适用的内容。不用害怕神秘的外观,因为你可以避免用它来“解密”。

评论

1赞 spencer741 2/6/2021
这些神秘的标识符是我最初试图摆脱的......我知道MSSQL默认为或类似性质的东西......尽管约束名称不经常使用,但我认为这个想法是有一个人类可读的命名方案来实现版本合规性,但也不必执行额外的步骤来获取约束名称。至少我是这么看的。sourcetable_targettable_uid