【问题标题】:Foreign Key naming scheme外键命名方案
【发布时间】:2010-09-17 00:04:08
【问题描述】:

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

鉴于这些表格:

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

任务有注释,任务归用户所有,用户编写注释。

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

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

【问题讨论】:

  • 读者注意:下面列出的许多最佳实践在 Oracle 中不起作用,因为它的名称限制为 30 个字符。表名或列名可能已经接近 30 个字符,因此将两者组合成一个名称的约定需要截断标准或其他技巧。

标签: database naming-conventions foreign-keys


【解决方案1】:

SQL Server 中的标准约定是:

FK_ForeignKeyTable_PrimaryKeyTable

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

FK_note_task

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

FK_task_user

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

FK_task_user
FK_note_task
FK_note_user

所以你可以看到任务依赖于用户,而笔记依赖于任务和用户。

【讨论】:

  • 如果外键指向第二个表上的候选键而不是主键,那么您可能会使用名称的第三段来限定它。这是一种不寻常的情况,而不是您通常从头开始设计的情况,因此我没有在回复中包含此内容。
  • 您将当前表名包含在键中以保持其独特性。 FK 名称位于 SQL Server 的全局命名空间中,因此您不能将两个名为 FK_PrimaryKeyTable 的 FK 附加到两个不同的外键表。其他数据库服务器的规则可能不同。
  • 好的...我在Oracle 中的每个表都有不同的命名空间,所以我不需要自我引用。
  • 这似乎是常见的用法,但是当有两个外键指向同一个表时人们会怎么做。即message 表有一个from_user_idto_user_id,这两者都会变成fk_message_user。出于这个原因,在我看来最好使用fk_tablename_columnname(在我的示例中为 fk_message_from_user_id),然后尝试使您的列名清楚地显示目标表(即 to_user_id 显然是指用户表)
  • 如果两个表本身都有下划线代表 ex。用户角色和用户地址? fk_user_addresses_user_role 是不是很混乱?
【解决方案2】:

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

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))
        ...

【讨论】:

  • 这绝对是最好的答案。
  • 我刚刚使用非常具体的命名约定创建了 Derby DB,而这里的这个是最易读和可追溯的。谢谢
  • 我猜只使用表名的问题是......两个外键指向同一个目标表......这就是为什么我可能倾向于包含字段名......复杂的主题没有怀疑。
【解决方案3】:

FK_TABLENAME_COLUMNNAME怎么样?

Keep t S尽可能实现S愚蠢。

【讨论】:

  • 因为当你有一个包含很多键和表的巨大数据库并且你在你的软件中更新模式时遇到错误时,即使不进行搜索也很难找到外键的定义位置的数据库创建脚本。
  • @JohnC 如果 FK 列名在列名中有另一个表名,那么不应该很容易分辨吗?它告诉您这两个表和它定义的列名。例如:FK_Animals_OwnerID—Animals 和 Owners 表,在 OwnerID 列上定义
【解决方案4】:

微软关于 SQL Server 的说明:

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

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

从属(子)表中同名列引用独立(父)表的主键时,我省略了列名(s):

FK_ChildTable_ParentTable

当引用其他列时,或者两个表之间的列名不同,或者只是为了明确:

FK_ChildTable_childColumn_ParentTable_parentColumn

【讨论】:

  • +1 我发现,虽然很冗长,但您提供的最后一个示例是最不容易混淆且最直接的。对于名称中带有下划线的表格,我什至会使用@onedaywhen 在他的回答中建议的双下划线。我个人只在交叉引用表中使用下划线。
【解决方案5】:

我通常只是将我的 PK 命名为 id,然后在其他表中命名 FK 时将我的表名和键列名连接起来。我从不关心骆驼大小写,因为一些数据库放弃了大小写敏感性,并且无论如何都简单地返回所有大写或小写名称。无论如何,这就是我的表格版本:

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

请注意,我还以单数形式命名表,因为一行代表我要持久化的对象之一。其中许多约定是个人喜好。我建议选择约定并始终使用它比采用别人的约定更重要。

【讨论】:

  • 嘿——这正是我实际使用的样式(但使用了驼峰式)——我想我会在名称中添加一些额外的描述,以说明它们之间的联系。跨度>
  • 所以至少我们可以阅读彼此的模式;) ... 令人尴尬的是,在缺席几年后无法阅读自己的模式。我们使用 ERWin 来绘制我们的架构图,但拥有文本版本通常很方便,并且拥有约定可以让您轻松找到表和字段。
【解决方案6】:

这可能是过度杀戮,但它对我有用。特别是在处理 VLDB 时,它对我有很大帮助。我使用以下内容:

CONSTRAINT [FK_ChildTableName_ChildColName_ParentTableName_PrimaryKeyColName]

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

CONSTRAINT [FK_ChildTableName_ChildColumnName_ParentTableName_ColumnInUniqueConstaintName]

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

【讨论】:

  • 在 mysql 中,限制为 64 个字符。因此,您的示例是最合适的解决方案,但不能解决所有情况。有时,FK 大于 64 个字符。想象一下您的示例中给出的表和列名称是正确的。你的外号FK_ChildTableName_ChildColumnName_ParentTableName_ColumnInUniqueConstaintName 太长了...
【解决方案7】:

我通常的做法是

FK_ColumnNameOfForeignKey_TableNameOfReference_ColumnNameOfReference

或者换种说法

FK_ChildColumnName_ParentTableName_ParentColumnName

这样我可以命名两个引用同一个表的外键,例如来自users_info 表的history_info tablecolumn actionBy and actionTo

会是这样的

FK_actionBy_usersInfo_name - For actionBy
FK_actionTo_usersInfo_name - For actionTo

请注意:

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

读者注意:下面列出的许多最佳做法都行不通 在 Oracle 中,因为其名称限制为 30 个字符。表名或 列名可能已经接近 30 个字符,因此约定 将两者组合成一个名称需要截断标准或 其他技巧。 ——查尔斯·伯恩斯

【讨论】:

  • 如果你有第三张表的 FK 指向 ParentTableName_ParentColumnName 相同的表,重复的 FK_Name,你的失败
【解决方案8】:

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

所以,对于这里给定的表格:

fk_task_userid_user
fk_note_userid_user

因此,如果您添加一列来跟踪谁最后修改了任务或注释...

fk_task_modifiedby_user
fk_note_modifiedby_user

【讨论】:

    【解决方案9】:

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

    稍后您可以find the FK name you need by running a query

    【讨论】:

    • 我只能解释我的反对票。几乎每个数据库系统都允许系统命名约束,您能想象回过头来并尝试快速找出带有 100 个表的数据库的生产问题,尝试破译 FK__123ee456ff 与什么关系?这很简单,只是一种可怕的做法。当你在这个 FK 上建立索引时,然后呢?系统名称也是?所以当索引 IX_007e373f5963 是 98% 的碎片时,你怎么知道去哪里找出原因?只是不应该这样做。
    【解决方案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 工具通常显示约束适用于什么。不用害怕看起来神秘,因为你可以避免用它来“解密”。

    【讨论】:

    • 这些神秘的标识符是我最初试图摆脱的......我知道 MSSQL 默认为 sourcetable_targettable_uid 或类似的东西......即使约束名称不经常使用,我认为这个想法是为版本合规性提供一个人类可读的命名方案,但也不必执行额外的步骤来获取约束名称。至少我是这么看的。
    猜你喜欢
    • 1970-01-01
    • 2010-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-02
    • 1970-01-01
    • 2023-03-03
    • 1970-01-01
    相关资源
    最近更新 更多