在数据库表中命名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_ID
和subordinate_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模是部分艺术,部分是科学。
我个人更喜欢(如上所述) FK的PK和TableID的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
后缀)以及它引用哪个表是明显的类别)。
好处是,不同表中的标识列没有歧义,您可以一目了然地查看列名引用的列。
另请参阅主键/外键命名约定
你可以使用下面的命名约定。 它有缺陷,但它解决了你的特殊问题。
- 对表名使用简短的(3-4个字符)昵称,即Invoice-
inv
,InvoiceLines –invl
- 使用这些昵称命名表中的列,即
inv_id
,invl_id
- 对于引用列,使用
invl_inv_id
作为名称。
这样你可以说
SELECT * FROM Invoice LEFT JOIN InvoiceLines ON inv_id = invl_inv_id