为啥在列名中指定主/外键属性

Posted

技术标签:

【中文标题】为啥在列名中指定主/外键属性【英文标题】:Why specify primary/foreign key attributes in column names为什么在列名中指定主/外键属性 【发布时间】:2008-10-17 22:26:29 【问题描述】:

最近的几个问题讨论了命名列的策略,我很惊讶地发现在列名中嵌入外键和主键的概念的概念。那是

select t1.col_a, t1.col_b, t2.col_z
from t1 inner join t2 on t1.id_foo_pk = t2.id_foo_fk

我必须承认,我从未在任何使用这种方案的数据库系统上工作过,我想知道有什么好处。在我看来,一旦您了解了系统的 N 个主表,您将使用这些表编写多个数量级的请求。

要提高开发效率,您需要了解哪些表是重要表,哪些是简单的支流。您需要将大量列名提交到内存中。其中一项基本任务是将两个表连接在一起。为了减少学习工作量,最简单的做法是确保两个表中的列名相同:

select t1.col_a, t1.col_b, t2.col_z
from t1 inner join t2 on t1.id_foo = t2.id_foo

我认为,作为开发人员,您不需要太多提醒哪些列是主键,哪些是外来的,哪些什么都不是。如果您很好奇,可以很容易地查看架构。当随机查看时

tx inner join ty on tx.id_bar = ty.id_bar

...知道哪个是外键重要吗?外键仅对数据库引擎本身很重要,以使其能够确保引用完整性并在更新和删除期间执行正确的操作。

这里要解决什么问题? (我知道这是一个讨论的邀请,并且可以随意这样做。但与此同时,我在寻找答案,因为我可能真的错过了什么)。

【问题讨论】:

【参考方案1】:

我同意你的看法。将此信息放在列名中有点像早期 Windows 时代蹩脚的匈牙利符号白痴。

【讨论】:

【参考方案2】:

我同意您的观点,即子表中的外键列应与父表中的主键列同名。请注意,这允许如下语法:

SELECT * FROM foo JOIN bar USING (foo_id);

USING 关键字假定两个表中存在同名的列,并且您需要等值连接。很高兴将其用作更详细的简写:

SELECT * FROM foo JOIN bar ON (foo.foo_id = bar.foo_id);

但是请注意,在某些情况下,您不能将外键命名为与其引用的主键相同的名称。例如,在具有自引用的表中:

CREATE TABLE Employees (
  emp_id INT PRIMARY KEY,
  manager_id INT REFERENCES Employees(emp_id)
);

另外,一个表可能有多个指向同一个父表的外键。使用列的名称来描述关系的性质很有用:

CREATE TABLE Bugs (
  ...
  reported_by INT REFERENCES Accounts(account_id),
  assigned_to INT REFERENCES Accounts(account_id),
  ...
);

我不喜欢在列名中包含表的名称。我也避免使用强制性的“id”作为每个表中主键列的名称。

【讨论】:

【参考方案3】:

在我使用 SQL 数据库开发的 20 年里,我一直支持这里提出的大部分想法,我很尴尬地说。他们中的大多数人几乎没有或根本没有提供预期的好处,事后看来,这是一种痛苦。

只要我在架构上花费了几个小时以上,我就会很快熟悉最重要的表及其列。等到几个月后,我的脑子里就差不多有了。

所有这些解释都是为了谁?一个只花几分钟设计的人无论如何都不会做任何严肃的事情。如果你用梵文命名你的专栏,那么打算长期使用它的人会学会它。

忽略复合主键,我不明白为什么像“id”这样简单的东西不能满足主键,而“_id”不能满足外键。

所以一个典型的连接条件变成customer.id = order.customer_id

如果两个表之间存在多个关联,我会倾向于使用关联而不是表名,因此可能是“parent_id”和“child_id”而不是“parent_person_id”等

【讨论】:

【参考方案4】:

我只使用带有 Id 后缀的表名作为主键,例如CustomerId,以及从其他表引用的外键也称为 CustomerId。当您在应用程序中引用时,对象属性中的表格变得很明显,例如Customer.TelephoneNumber、Customer.CustomerId 等。

【讨论】:

为什么 CustomerId 不能是 Customer.Id?那么任何具有 CustomerId 列的表显然都与 Customer 有外键关系。 我知道您可能认为它是多余的,但我认为 Customer.CustomerId = Order.CustomerId 而不是 Customer.Id = Order.CustomerId 看起来更好。【参考方案5】:

我在表的任何外键的前端使用了“fk_”,主要是因为它帮助我在为我的商店的项目开发数据库时保持直截了当。过去没有做过任何数据库工作,这确实帮助了我。事后看来,也许我不需要这样做,但它是在某些列名上附加了三个字符,所以我没有出汗。

作为编写数据库应用程序的新手,我可能做出了一些让经验丰富的数据库开发人员不寒而栗的决定,但我不确定外键是否真的有那么重要。再说一次,我想这是对这个问题的看法不同,我肯定会接受你写的内容并对此进行思考。

祝你好运!

【讨论】:

【参考方案6】:

我同意你的看法——我采取了一种不同的方法,我在许多公司环境中都看到了这种方法:

TableNameFieldName 格式命名列,因此如果我有一个 Customer 表并且 UserName 是我的字段之一,则该字段将称为 CustomerUserName。这意味着,如果我有另一个名为 Invoice 的表,并且客户的用户名是外键,我会称之为 InvoiceCustomerUserName,当我引用它时,我会称之为 Invoice.CustomerUserName,它会立即告诉我它在哪个表中。

此外,此命名有助于您在加入时跟踪列的来源表。

我只在 DBMS 的外键和主键的 ACTUAL 名称中使用 FK_ 和 PK_。

【讨论】:

不会是 Invoice.InvoiceCustomerUserName 吗?这有比类型标签更糟糕的危险......Invoice.UserName = Customer.UserName 对我来说似乎足够清楚。 对不起,这太可怕了。简直惨不忍睹。它看起来像是一种不需要表别名的“聪明”。几乎和我工作的地方一样糟糕,表名带有前缀 T_ 和列 C_(视图和索引也有前缀......) 这只是多余的。进行联接时,您必须始终引用表名。此外,用户名不是一个好的主键(例如,具有 CustomerUserName 的发票比具有 UserName 的发票更清晰,但两者都是错误的)。 ..JOIN user ON invoice.userid = user.userid 很清楚

以上是关于为啥在列名中指定主/外键属性的主要内容,如果未能解决你的问题,请参考以下文章

DJANGO:当主键不是“id”时如何在夹具中指定主键

外键为啥必须是唯一键?为啥至少唯一键才能作为其他表的外键?不唯一为啥不可以?

如何在 SQL Server 的交叉应用联接中指定列名

EF Code First CTP5 - 使用属性名称作为外键的列名

为啥我需要在 Swift 的类中指定变量的类型?

使用自定义列名映射外键