在数据库表中命名ID列

我想知道人们对数据库表中ID列命名的意见。

如果我有一个名为发票的表与标识列的主键我会调用该列InvoiceID,以便我不会与其他表冲突,这是显而易见的是什么。

我现在在哪里工作,他们已经调用了所有的ID列ID。

所以他们会这样做:

Select i.ID , il.ID From Invoices i Left Join InvoiceLines il on i.ID = il.InvoiceID 

现在,我在这里看到一些问题:
1.您需要在select列上别名
2. ID = InvoiceID不适合我的大脑
3.如果你没有别名的表,并提到InvoiceID它是明显的是什么表?

其他民族对这个​​话题的看法是什么?

ID是一个SQL反模式。 请参阅http://www.amazon.com/s/ref=nb_sb_ss_i_1_5?url=search-alias%3Dstripbooks&field-keywords=sql+antipatterns&sprefix=sql+a

如果你有许多ID为ID的表格,那么你的报告就更难了。 它掩盖了含义,使得复杂的查询更难以阅读,并要求您使用别名来区分报告本身。

此外,如果有人愚蠢地使用数据库中的自然连接,您将join错误的logging。

如果您想使用某些dbs允许的USING语法,那么如果使用ID,则不能使用。

如果你使用了ID,如果你碰巧正在复制连接语法(不要告诉我没有人这样做!),并且忘记在连接条件中改变别名,那么你可以很容易地以错误的连接结束。

所以你现在有

 select t1.field1, t2.field2, t3.field3 from table1 t1 join table2 t2 on t1.id = t2.table1id join table3 t3 on t1.id = t3.table2id 

当你的意思

 select t1.field1, t2.field2, t3.field3 from table1 t1 join table2 t2 on t1.id = t2.table1id join table3 t3 on t2.id = t3.table2id 

如果使用tablenameID作为id字段,这种偶然错误发生的可能性就小得多,而且更容易find。

我总是首选ID为TableName + ID为id列,然后TableName + ID为外键。 这样,所有的表都有一个与ID字段相同的名称,并没有多余的描述。 这对我来说似乎更简单,因为所有的表都有相同的主键字段名称。

至于连接表,不知道哪个Id字段属于哪个表,在我看来,应该写的查询来处理这种情况。 在我工作的地方,我们总是在表格/表格别名中声明我们使用的字段。

在我的公司里,这是一件关于这件事的书呆子。 LINQ的出现使得冗余表名+ ID模式在我眼中显得更加愚蠢。 我认为最合理的人会说,如果你手工编写你的SQL的方式必须指定表名来区分FK,那么这不仅节省了键入,而且增加了SQL的清晰度,身份证在那你可以清楚地看到哪个是PK和哪个是FK。

即。 LEFT JOIN客户在Employee.ID = Customer.EmployeeID

不仅告诉我,这两个链接,但是哪个是PK,哪个是FK

而在旧的风格,你不得不看或希望他们命名好。

我们使用InvoiceID ,而不是ID 。 它使查询更具可读性 – 当您单独看到ID时,这可能意味着什么,特别是当您将表格别名为i

我同意Keven和其他几个人在这里表的PK应该简单地是Id和外键列出OtherTable + ID。

不过,我想补充一个最近更加重视这个论点的理由。

在我目前的位置,我们正在使用entity framework使用POCO世代。 使用Id的标准命名约定,PK允许通过validation来inheritance基础poco类,并且对于共享一组常用列名的表来说也是如此。 使用Tablename + Id作为这些表中的每个表的PK将破坏为这些表使用基类的能力。

只是一些思想的食物。

这并不重要,在所有的命名规则中你都可能会遇到一些西米尔问题。

但重要的是保持一致,所以每次编写查询时都不必查看表定义。

我的首选项也是主键的ID和外键的TableNameID。 我也喜欢在大多数表格中有一个“名字”列,在这些表格中我保存了条目的用户可读标识符(即名称:-))。 这个结构在应用程序本身中提供了很大的灵活性,我可以用同样的方法大量地处理表格。 这是一个非常强大的事情。 通常一个OO软件是build立在数据库之上的,但是OO工具集不能被应用,因为数据库本身不允许它。 有列ID和名称仍然不是很好,但它是一个步骤。

select
i.ID,il.ID从发票我左joinInvoiceLines il i.ID = il.InvoiceID

为什么不能这样做?

 Select Invoices.ID , InvoiceLines.ID From Invoices Left Join InvoiceLines on Invoices.ID = InvoiceLines.InvoiceID 

在我看来,这是非常可读和简单。 命名variables作为我和il是一个糟糕的select。

我刚刚开始在一个只使用“ID”的地方工作(在核心表中,由外键中的TableNameID引用),并且已经发现了由它直接引起的两个生产问题。

在一种情况下,查询使用“…其中ID(SELECT ID FROM OtherTable …”而不是“…其中ID(SELECT TRANSID FROM OtherTable …”中的ID)

任何人都可以诚实地说,如果使用完整的,一致的名称,错误的语句会读“… TransID在(SELECT OtherTableID from OtherTable …”)我不认为所以。

另一个问题发生在重构代码。 如果您使用临时表,而以前查询去核心表,然后旧的代码读取“… dbo.MyFunction(t.ID)…”,如果没有改变,但现在“t”指的是一个临时表,而不是核心表,你甚至没有得到一个错误 – 只是错误的结果。

如果产生不必要的错误是一个目标(也许有些人没有足够的工作?),那么这种命名惯例是伟大的。 否则,一致的命名是要走的路。

为了简单起见,大多数人在表格ID上命名该列。 如果它在另一个表上有一个外键引用,那么在联接的情况下,他们会明确地调用它的InvoiceID(使用你的例子),无论如何,你正在别名表,所以显式的inv.ID仍然比inv.InvoiceID简单

从正式数据字典的angular度来看,我将命名数据元素invoice_ID 。 通常,数据元素名称在数据字典中是唯一的,理想情况下始终具有相同的名称,但有时可能需要根据上下文需要额外的限定条件,例如,名为employee_ID的数据元素可以在组织结构图中使用两次,分别作为supervisor_employee_IDsubordinate_employee_ID

显然,命名约定是主观的,是一个风格问题。 我发现ISO / IEC 11179准则是一个有用的起点。

对于DBMS,我将表看作实体的集合(除了那些只包含一行(例如cofig表,常量表等)的表),例如我的employee_ID是关键字的表将被命名为Personnel 。 所以直接TableNameID约定不适用于我。

我已经看到了TableName.ID=PK TableNameID=FK大型数据模型上使用的TableName.ID=PK TableNameID=FK风格,不得不说,我觉得有点混乱:我更喜欢一个标识符的名称是相同的,即不会更改基于它发生的表的名称出现在。需要注意的是前面提到的风格似乎用于在每个表中添加一个IDENTITY (自动增量)列的商店,同时避开外键中的自然和复合键。 这些商店往往没有正式的数据字典,也没有build立数据模型。 再次,这只是一个风格问题,我不亲自订阅。 所以最终,这不适合我。

所有这一切,我可以看到一个情况,有时从列名称中删除限定符,当表的名称提供了一个上下文,例如名为employee_last_name的元素可能成为Personnel表中的last_name 。 这里的基本原理是,这个域名是“人的姓氏”,而且更可能与其他表中的姓氏列进行UNION编辑,而不是作为另一个表中的外键使用,但是之后我可能只是更改我的介意,有时你永远不会说。 事情就是这样:数据build模是部分艺术,部分是科学。

个人更喜欢(如上所述) FKPKTableID的Table.ID 。 即使(请不要拍我)Microsoft Accessbuild议这个。

不过,我也知道一些事实,一些生成工具偏爱TableID的PK,因为它们倾向于链接所有包含“ID”的列名, 包括ID!

即使查询devise器在Microsoft SQL Server上执行此操作(对于您创build的每个查询,您最终都会撕掉列ID上所有表上不必要的新创build的关系)

THUS就像我内部的OCD不喜欢它一样,我使用TableID约定进行滚动。 让我们记住它被称为数据库,因为它将成为许多许多应用程序的基础。 而且所有的技术都应该受益于一个规范化,描述清晰的模式。

不用说,当人们开始使用TableName,TableDescription等的时候,我会画线。 在我看来,公约应该做到以下几点:

  • 表名:多元化。 防爆。 雇员
  • 表别名:全表名称,单数化。 防爆。

     SELECT Employee.*, eMail.Address FROM Employees AS Employee LEFT JOIN eMails as eMail on Employee.eMailID = eMail.eMailID -- I would sure like it to just have the eMail.ID here.... but oh well 

[更新]

另外,在这个线程中有一些关于由于“种类关系”或angular色而造成的重复列的有效post。 例如,如果一个商店有一个雇员ID ,这告诉我蹲。 所以我有时会做一些像Store.EmployeeID_Manager 。 当然这有点大,但是至less人们不会发疯,试图find表ManagerID ,或者EmployeeID在那里做什么。 当查询是WHERE我会简化它为:selectEmployeeID_Manager作为ManagerID从商店

我认为只要你一致,你可以使用任何“ID”。 包括表名是重要的。 我build议使用像Erwin这样的build模工具来强制执行命名约定和标准,所以在编写查询时很容易理解表之间可能存在的关系。

我的意思是第一个陈述是,而不是身份证,你可以使用其他的东西,如“recno”。 那么这个表就会有一个invoice_recno的PK等等。

干杯,本

我的投票是针对表ID的InvoiceID。 当它用作外键并在查询中使用智能别名时,我也使用相同的命名约定。

  Select Invoice.InvoiceID, Lines.InvoiceLine, Customer.OrgName From Invoices Invoice Join InvoiceLines Lines on Lines.InvoiceID = Invoice.InvoiceID Join Customers Customer on Customer.CustomerID = Invoice.CustomerID 

当然,这比其他一些例子还要长。 但是微笑。 这是后代,有一天,一些可怜的初级编码器将不得不改变你的杰作。 在这个例子中,不存在歧义,并且当附加的表被添加到查询中时,将会对冗长性感到高兴。

对于数据库中的列名,我会使用“InvoiceID”。

如果我通过LINQ将这些字段复制到一个未命名的结构中,那么我可以在那里命名它为“ID”,如果它是结构中唯一的ID。

如果这个列不会被用在外键中,所以它只被用来唯一标识一个编辑或者删除的行,我将它命名为“PK”。

如果你给每个键一个唯一的名字,例如“invoices.invoice_id”而不是“invoices.id”,那么你可以使用“自然连接”和“使用”操作符,不用担心。 例如

 SELECT * FROM invoices NATURAL JOIN invoice_lines SELECT * FROM invoices JOIN invoice_lines USING (invoice_id) 

代替

 SELECT * from invoices JOIN invoice_lines ON invoices.id = invoice_lines.invoice_id 

SQL足够冗长而不会更冗长。

我为保持自己的一致性(表中有一个用作ID的单列主键) Table_pk就是命名表Table_pk的主键。 任何地方,我有一个外键指向表主键,我称之为PrimaryKeyTable_fk列。 这样我就知道如果我的Customer表中有一个Customer_fk ,而我的Order表中有一个Customer_pk ,那么我知道Order表引用了Customer表中的一个条目。

对我来说,这对于我认为更简单的连接尤其有意义。

 SELECT * FROM Customer AS c INNER JOIN Order AS c ON c.Customer_pk = o.Customer_fk 

FWIW,我们的新标准(改变,嗯,我的意思是“发展”,每个新项目)是:

  • 小写数据库字段名称
  • 大写的表名
  • 使用下划线来分隔字段名称中的单词 – 将其转换为代码中的Pascal大小写。
  • pk_前缀表示主键
  • _id后缀表示一个整数,自动递增的ID
  • fk_前缀表示外键(不需要后缀)
  • _VW后缀的意见
  • 布尔值的is_前缀

因此,名为NAMES的表可能具有字段pk_name_id, first_name, last_name, is_alive,fk_company以及一个名为LIVING_CUSTOMERS_VW的视图,定义如下:

 SELECT first_name,last_name
 FROM CONTACT.NAMES
 WHERE(is_alive ='True')

正如其他人所说,只要任何scheme一致,不会不必要地混淆你的意思。

我绝对同意在ID字段名称中包含表名,这正是您给出的原因。 一般来说,这是唯一包含表名的字段。

我讨厌这个普通的id名字。 我强烈希望始终使用invoice_id或其变体。 当我需要的时候,我总是知道哪个表是id的权威表,但是这使我困惑

 SELECT * from Invoice inv, InvoiceLine inv_l where inv_l.InvoiceID = inv.ID SELECT * from Invoice inv, InvoiceLine inv_l where inv_l.ID = inv.InvoiceLineID SELECT * from Invoice inv, InvoiceLine inv_l where inv_l.ID = inv.InvoiceID SELECT * from Invoice inv, InvoiceLine inv_l where inv_l.InvoiceLineID = inv.ID 

最糟糕的是你提到的混音,完全混乱。 我不得不使用一个数据库,其中几乎总是foo_id,除了最常用的ID之一。 那完全是地狱。

我更喜欢DomainName || 'ID'。 (即DomainName + ID)

DomainName通常但不总是与TableName相同。

ID本身的问题本身就是不能向上扩展。 一旦你有大约200个表,每个表都有一个名为ID的第一列,数据开始看起来都一样。 如果你总是用表格名称标识ID,那会有所帮助,但不是那么多。

DomainName&ID可以用来命名外键和主键。 当foriegn键以它们引用的列的名字命名时,这可以是助记符的帮助。 forms上,将外键的名称绑定到它所引用的键是不必要的,因为参照完整性约束将build立引用。 但是当阅读查询和更新时,它非常方便。

偶尔,DomainName || 'ID'不能被使用,因为在同一个表中有两个同名的列。 示例:Employees.EmployeeID和Employees.SupervisorID。 在这些情况下,我使用RoleName || 'ID',如例子。

最后但并非最不重要的是,我尽可能使用自然键而不是合成键。 在某些情况下,自然键不可用或不可靠,但是很多情况下自然键是正确的select。 在那些情况下,我让自然的关键取自然的名字。 这个名字通常甚至没有字母,“身份证”在里面。 例如:OrderNo其中No是“Number”的缩写。

对于每个表格,我select一个树状字母(例如Employees => Emp)

这样一个数字自动编号主键变成了nkEmp

它是简短的,在整个数据库中是独一无二的,我一眼就知道它的属性。

我在SQL和我使用的所有语言(主要是C#,Javascript,VB6)保持相同的名称。

请参阅Interakt网站的命名规则,了解一个经过深思熟虑的命名表和列的系统。 该方法使用每个表的后缀(产品表的_ctg或类别表的_ctg ),并将其附加到给定表中的每个列。 因此,产品表的标识列将是id_prd ,因此在数据库中是唯一的。

他们更进一步,以帮助理解外键:产品表中引用类别表的外键将是idctg_prd这样它就属于哪个表( _prd后缀)以及它引用哪个表是明显的类别)。

好处是,不同表中的标识列没有歧义,您可以一目了然地查看列名引用的列。

另请参阅主键/外键命名约定

你可以使用下面的命名约定。 它有缺陷,但它解决了你的特殊问题。

  1. 对表名使用简短的(3-4个字符)昵称,即Invoice- inv ,InvoiceLines – invl
  2. 使用这些昵称命名表中的列,即inv_idinvl_id
  3. 对于引用列,使用invl_inv_id作为名称。

这样你可以说

 SELECT * FROM Invoice LEFT JOIN InvoiceLines ON inv_id = invl_inv_id