【问题标题】:naming the id field of a table properly正确命名表的 id 字段
【发布时间】:2010-12-23 21:09:20
【问题描述】:

我目前正在阅读 Joe Celko 撰写的《SQL 编程风格》一书。

在第一章的“开发标准化后缀”段落中,他为 id 列声明:

“_id”=标识符。它是独一无二的 架构并引用一个实体 它出现在架构中的任何位置。 从不用户 ">table_name<_id>

几页后他说

不要使用下划线作为第一个 或名称中的最后一个字母。它看起来 就像名字少了另一个 组件。

他不赞成将“id”作为列名。

所以我想知道你们如何命名 id 列?

我知道大多数人可能会认为这个问题的意义何在,但我正在寻求标准化我的数据模型,尽可能遵循行业标准和 ISO 标准。

【问题讨论】:

  • 我假设您的意思是替换 id ?我通常使用引用该表的东西,例如我将拥有 userID 的“用户”表。
  • 前缀的反义词是后缀。
  • @HLGEM 那么不清楚的地方是什么?我不知道他在暗示什么

标签: sql database database-design data-modeling


【解决方案1】:

我也不赞成使用“Id”作为列名,尽管它已经非常普遍。 “EmployeeId”比“Id”长,但更具描述性。它还允许外键通常与它所引用的列具有相同的名称。当对数据库的控制权从一个人转移到另一个人时,这非常有用。

上述情况有一个例外。同一个表中可能有两个外键都引用同一个键。也可以有一个自反外键,它引用它出现的同一个表的不同行中的键。

让我举一个反身键的例子。您有一个员工表,键为 EmployeeId。您还有一个名为 SupervisorId 的列,它记录了一个主管和几个下属之间的关系。在这种情况下,外键的名称是角色,而不是实体。

作为替代方案,可以使用用户定义的域来记录两列引用同一事物的事实。同样,当必须将数据的基本含义传达给新人时,这是最有用的。

在符号内部使用下划线作为内部视觉分隔符是一个完全可分离的问题。 Camelcasing 已经变得比下划线更普遍,甚至有些系统不允许下划线作为符号组成部分。

最重要的是,保持一致。如果您使用任意、反复无常和自相矛盾的命名约定,您最终甚至会迷惑自己。

【讨论】:

  • 通常当我遇到你所说的异常情况时,我会使用 personId、supervisorPersonId 之类的东西。这样我就有了我需要加入的 id 的确切名称,但带有前缀限定符使其更加独特。
【解决方案2】:

我认为这是一个很好的问题。做你认为好的事情,并且每次都这样做。那你就没事了。

我使用 tablename + 'id' 模型:UserId、PersonId 等。

【讨论】:

  • 我用的是同款。非常方便,因为您始终知道 id 字段的名称,并且永远不会在 join 中感到困惑。对于 FK,我使用相同的名称,因此订单表中的 CustomerId 也被命名为 CustomerId。这种方法在超过 1000 个表和一些相当复杂的查询的应用程序中仍然可以正常工作,并且仍然可以很好地为我服务。
【解决方案3】:

我不会分享我对命名标准的看法,而是尝试回答您的问题;)

我认为 Celko 的意思是学生表中的 student_ID 是一种代码味道,即设计师的风格可能是总是向他们创建的每个表添加一个 ID 列,可能是一个自动增量列在物理模型中(即使在逻辑模型中没有这样的列),目的是使用这些 ID 列作为外键。换句话说,Celko 不希望您总是使用代理键,而是希望您在适当的情况下使用自然键。

如果您继续阅读第 1.2.5 节 (p14-15) 并遵循他的表名规则,您会发现为什么表名 + _ID 不太可能出现:

如果我找不到行业标准 (姓名),我会寻找一个集体 或类名... 例外:使用 如果表实际上是单数名称 里面只有一行。

因此,例如,如果您有一个包含学生数据的表,则它可能被称为“学生”而不是“学生”,但更有可能是“注册”(或类似名称)。并且只包含一行的表不太可能需要 _ID 列。

我想有些名词的复数与单数相同,所以 Sheep_ID 可能是可以接受的(当然,只有在没有行业标准的绵羊标识符的情况下!)

还要考虑规则 1.3.2。 (p19) 避免名称因地而异,例如同一个域在学生表中称为 ID,在其他表中称为 student_ID。整个架构中不可能只有一个名为 _ID 的元素!

【讨论】:

    【解决方案4】:

    对于表 ID,我总是使用表名 + ID。

    这样做的原因是为了避免在 1 对 1 映射时查询中的列名不明确

    有时我会快速写下sql来测试

    Select
      * 
    FROM table1
    Inner join table2 on table1ID = table2ID
    

    如果我没有在 ID 列中使用表名,那么这会引发错误(迫使我在表上使用别名)

    Select
      * 
    FROM table1
    Inner join table2 on ID = ID
    

    还有另一个使用表名的好理由,一般测试查询以查看存在哪些数据,使用“*”来选择列。如果您执行连接并选择 *,有时很难理解哪个 ID 来自哪个表,特别是如果您从 2 个以上的表返回大量列

    【讨论】:

    • 仅使用 ID 时我的心痛是相同的名称被赋予具有完全不同含义的列。如果 7 个不同的表中的 7 个列的意思不同,你会称它们为“PRICE”吗?您不想称它们为“WHOLESALE_PRICE”、“EXTENDED_PRICE”、“SUGGESTED_RETAIL_PRICE”吗?将 PK 和 FK 命名为相同(如果可能)意味着可以很容易地找到缺少的约束。如果存在 PK 列并且另一个表中存在同名列,则某些 ERD 工具会推断出约束。他们不连接来推断出这样的。
    • @Stephanie ...我认为你误解了我的回答。我完全同意
    • 是的,编辑帮助解释了你想要连接的意思!感谢您的澄清。
    【解决方案5】:

    我一直提倡全球唯一的 TABLENAME_ID。在这一点上,我强烈建议表名能够充分描述其上下文,因此在进行外部引用时,它们的应用永远不会有任何歧义。

    【讨论】:

      【解决方案6】:

      ID 作为列名很难维护,在我看来更容易导致连接错误。

      假设您总是使用 ID 作为每个表中的列名。

      现在假设您需要加入其中六个表。作为一个典型的人,您复制第一个连接并更改表名。如果您错过了一个,并且您使用了 id,您将得到一个运行并给出错误答案的查询。如果你使用 tablenameId 你会得到一个语法错误。示例见以下代码:

      create table #test1 (id int identity, test varchar(10))
      create table #test2 (id int identity, test varchar(10))
      create table #test3 (id int identity, test varchar(10))
      
      insert #test1
      values ('hi')
      insert #test1
      values ('hello')
      insert #test2
      values ('hi there')
      insert #test3
      values ('hello')
      insert #test3
      values ('hi')
      select * 
      from #test1 t1
      join #test2 t2
          on t1.id = t2.id
      join #test3  t3
          on t1.id = t2.id    
      select * 
      from #test1 t1
      join #test2 t2
          on t1.id = t2.id
      join #test3  t3
          on t1.id = t3.id        
      
      Drop table #test1
      drop table #test2
      drop table #test3   
      Go
      
      create table #test1 (t1id int identity, test varchar(10))
      create table #test2 (t2id int identity, test varchar(10))
      create table #test3 (t3id int identity, test varchar(10))   
      
      
          insert #test1
          values ('hi')
          insert #test1
          values ('hello')
          insert #test2
          values ('hi there')
          insert #test3
          values ('hello')
          insert #test3
          values ('hi')
      
      select * 
      from #test1 t1
      join #test2 t2
          on t1.t1id = t2.t2id
      join #test3 t3
          on t1.t1id = t3.t3id    
      
      select * 
      from #test1 t1
      join #test2 t2
          on t1.t1id = t2.t2id
      join #test3 t3
          on t1.t1id = t2.t3id    
      
          Drop table #test1
          drop table #test2
          drop table #test3   
      

      使用 tablenameId 的另一件事是,当您在复杂的报告查询中需要多个表的实际 id 时,您不必创建别名来查看哪个 id 来自哪里(并使报告应用程序满意因为他们中的大多数都坚持报告的唯一字段名)。

      【讨论】:

        【解决方案7】:

        哇,我本来打算写“我总是使用 TablenameID,但世界上其他人都不同意我的观点”。不过,看来这里的每个人都同意我的观点。

        当然,当我在表中使用代理整数 ID 时。如果有一个自然主键,我会使用它。

        【讨论】:

          【解决方案8】:

          在我的数据库中:

          对于外键ID,我使用外表名+“Id”的单数形式。我使用大写字母 I,小写 d,因为这是 FX cop 根深蒂固的标准。

          对于自动递增的身份,我经常使用“SequenceId”

          在我的数据层中:

          我使用对象名称+“Id”,遵循“Id”的最佳实践标准

          【讨论】:

            猜你喜欢
            • 2023-01-16
            • 2010-09-20
            • 2012-09-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多