我被教导不要在Id
我的表的标识列中使用名称,但最近我一直在使用它,因为它简单、简短,并且非常能描述数据的实际内容。
我见过有人建议在Id
表名前加上前缀,但这似乎为编写 SQL 查询的人(或者如果你使用像实体框架这样的 ORM 的程序员)做更多的工作,特别是在较长的表名上,例如CustomerProductId
或者AgencyGroupAssignementId
我们聘请的一位第三方供应商为我们创建了一些东西,实际上命名了他们所有的身份列Ident
,只是为了避免使用Id
. 起初我以为他们这样做是因为Id
是关键字,但当我查看它时,我发现这Id
不是我们正在使用的 SQL Server 2005 中的关键字。
那么为什么人们建议不要将名称Id
用于标识列呢?
编辑:为了澄清,我不是在问要使用哪种命名约定,也不是在询问使用一种命名约定而不是另一种命名约定的参数。我只是想知道为什么不建议使用Id
标识列名称。
我是一个程序员,而不是 dba,对我来说,数据库只是一个存储数据的地方。由于我通常构建小型应用程序,并且通常使用 ORM 进行数据访问,因此标识字段的通用字段名称更易于使用。我想知道这样做我错过了什么,以及是否有任何真正好的理由让我不这样做。
表名前缀有很好的理由。
考虑:
我们希望
DELETE
从TableA
两个表中都存在的记录中提取。很简单,我们将只做一个INNER JOIN
:....我们刚刚消灭了所有
TableA
. 我们无意中将 B 的 ID 与自身进行了比较——每条记录都匹配,每条记录都被删除。如果字段已命名
TableAId
,TableBId
这将是不可能的 (Invalid field name TableAid in TableB
)。就个人而言,我对
id
在表中使用名称没有任何问题,但是用表名(或实体名称,如果TableA
人们PeopleId
也可以正常工作)作为前缀确实是一种更好的做法,以避免意外比较错误的字段并吹有事。JOIN
这也使得在具有大量s的长查询中字段来自何处变得非常明显。主要是为了防止外键成为巨大的痛苦。假设您有两个表:Customer 和 CustomerAddress。两者的主键都是名为 id 的列,它是一个标识 (int) 列。
现在您需要从 CustomerAddress 引用客户 ID。显然,您无法命名列 id,因此您使用 customer_id。
这导致了几个问题。首先,您必须始终记住何时将列称为“id”,何时将其称为“customer_id”。如果你把它搞砸了,它会导致第二个问题。如果您有一个包含十几个连接的大型查询,并且它没有返回任何数据,请玩 Where's Waldo 并找出这个错字:
哎呀,应该是
ON c.id = ca.customer_id
。或者更好的是,描述性地命名您的身份列,因此它可以是ON c.customer_id = ca.customer_id
. 然后,如果您不小心在某处使用了错误的表别名,customer_id 将不会成为该表中的列,并且您将得到一个很好的编译错误,而不是空结果和随后的代码眯眼。当然,在某些情况下这无济于事,例如,如果您需要从一个表到另一个表的多个外键关系,但将所有主键命名为“id”也无济于事。
以下是关于从约定中获得的优势的所有答案的摘要,即不对所有主键使用通用名称:
更少的错误,因为身份字段的名称不同
您不能错误地编写连接
B.Id = B.Id
而不是 的查询A.Id = B.Id
,因为标识字段的名称永远不会完全相同。更清晰的列名。
如果您查看名为 的列
CustomerId
,您会立即知道该列中有哪些数据。如果列名是类似的通用名称Id
,那么您还需要知道表名才能知道该列包含哪些数据。避免不必要的列别名
您现在可以从与, 而不是
SELECT CustomerId, ProductId
连接的查询中写入Customers
Products
SELECT Customer.Id as CustomerId, Products.Id as ProductId
允许
JOIN..USING
语法您可以使用语法连接表
Customer JOIN Products USING (CustomerId)
,而不是Customer JOIN Products ON Customer.Id = Products.Id
关键字更容易在搜索中找到
如果您在大型解决方案中寻找客户的身份字段,搜索
CustomerId
远比搜索有用Id
如果您能想到此命名约定的任何其他优点,请告诉我,我会将其添加到列表中。
是否选择对标识字段使用唯一或相同的列名取决于您,但无论您选择什么,请保持一致:)
要从链接的问题中复制我的答案:
在某些情况下,在每个表上都粘贴“ID”并不是最好的主意:
USING
关键字(如果受支持)。我们经常在 MySQL 中使用它。例如,如果您有
fooTable
with columnfooTableId
和barTable
with foreign keyfooTableId
,那么您的查询可以这样构造:它不仅节省了打字,而且与替代方案相比更具可读性:
在规范化数据库模式以限制冗余之后,将表划分为具有已建立关系(一对一、一对多、多对多)的较小表。在此过程中,原始表中的单个字段可以出现在多个规范化表中。
例如,假设 Author_Nickname 具有唯一约束,博客的数据库在其非规范化形式中可能看起来像这样。
规范化它会产生两个表:
作者:
邮政
这里 Author_Nickname 将是 author 表的主键和 post 表中的外键。即使 Author_Nickname 出现在两个表中,它仍然对应一个信息单元,即。每个列名对应一个字段。
在许多情况下,原始字段不能有唯一约束,因此使用数字人工字段作为主键。这不会改变每个列名仍然代表一个字段的事实。在传统的数据库设计中,各个列名对应于单个字段,即使它们不是键。(例如,人们会使用part.partname和client.clientname而不是part.name和client.name)。这就是存在 the
INNER JOIN ... USING <key>
和NATURAL JOIN
语法的原因。然而,如今,随着 ORM 层在许多语言中很容易获得,数据库通常被设计为面向 OO 语言的持久层,其中在不同类中具有相同作用的变量被称为相同(part.name和client.name,而不是part.partname和client.clientname)。在这种情况下,我倾向于使用“ID”作为主键。
如果“Ident”最终被用在他们的所有表上,使用“Ident”而不是“Id”并不能真正解决任何问题。
Drupal 站点上有一篇关于 SQL 编码约定的好文章,指出了这种情况的良好做法:
从这个角度来看,CustomerProductId 和 AgencyGroupAssignmentId 使用起来很有意义。是的,它非常冗长。你可以缩短它,但最关心的一点是跟随你的开发者是否会理解你的意思。以详细表名开头的 Id 不应该对它们的含义产生歧义。而且(对我来说)这比节省一些击键更重要。
我将列命名为 CustomerID 而不是 ID,所以每当我输入
SQL Prompt 立即提出以下建议
它为我节省了几次击键。然而,我认为命名约定是非常主观的,因此我对某种方式没有强烈的看法。
这与您不会将所有 varchar 字段命名为“UserText”和“UserText1”之类的名称,或者您不会使用“UserDate”和“UserDate1”的原因相同。
通常,如果您在表中有一个身份字段,则它是您的主键。如果两个表中的主键都是 id,您将如何构建具有父表外键的子表?
不是每个人都同意这种方法,但在我的数据库中,我为每个表分配了一个唯一的缩写。该表的 PK 将命名为 PK_[abbrv]ID。如果在任何地方用作 FK,那么我将使用 FK_[abbrv]ID。现在我有零猜测工作来弄清楚表关系是什么。
基本上出于同样的原因,您通常不会将参数命名为 parameter1、parameter2 ...它是准确的,但不是描述性的。如果您看到 TableId,那么您可能可以放心地假设它用于保存 Table 的 pk,无论上下文如何。
至于谁使用了 Ident,他完全没有抓住重点,在 Ident 和 Id 使用 Id 之间进行选择。Ident 比 Id 更令人困惑。
断章取意,可以假定 Id 是某个表的主键(除非 id 是 guid,否则不是非常有用),但 Ident 甚至没有告诉您(或至少是我)。我最终会发现 Ident 是身份的缩写(一种或另一种方式),但我花在弄清楚这一点上的时间会被浪费掉。
使用前缀,以便可以在主键和外键上下文中使用相同的名称,以便您可以执行
natural join
/join ... using
。