【问题标题】:Problems on using same field names in different tables, specially ID在不同表中使用相同字段名称的问题,特别是 ID
【发布时间】:2013-06-15 12:41:17
【问题描述】:

我正在开发一个大数据库,从这种情况下,我决定至少在决定表和字段布局时总是三思而后行。我最关心的是主键。

我几乎总是使用table name 加上_id 来命名这些索引。我这样做是因为在加入表格时我不必担心重复的字段名称,因为 Delphi 数据库组件将字段作为table_name.field_name 提供给我们,而只是字段。

另一方面,如果我们可以为每个表使用相同的 ID 字段名称,那么创建一个函数来处理与该索引控件相关的每个表总是更容易。

有没有人在选择这些数据库设计之一时有过不好的经历?在每个字段名上重复表名是一种好方法吗?

【问题讨论】:

  • 如果您打算使用 TClientDataSet 的嵌套数据集功能,请注意构成主表和明细表之间连接的字段必须共享相同的名称。请参阅 Hazzits 回答点 4。
  • 其实我用的是ZeosLib。

标签: database delphi database-design indexing


【解决方案1】:

我过去设计了许多数据库,并且多次犯了不一致的表和列命名的错误。我知道其他人有different opinions,但这些是我现在遵循的规则:

  1. 表名是复数形式 拥有products 表而不是product 表对我来说感觉很自然,尤其是在选择语法方面:SELECT whatever FROM products 感觉比SELECT whatever FROM product 好。最后选择单数还是复数都无所谓,只要不混用就可以了。

  2. 字段名称是单数 同样,这或多或少是一个随意的选择,但对我来说似乎很自然,并且是大多数人使用的。 (你可以说SELECT descriptions FROM products 更有意义,但是,你有什么不能争论的)

  3. 所有名称均为小写并使用下划线分隔单词 有些人使用 Pascal 风格的大写字母,例如 ProductId 甚至是 JavaScript 风格的 productId。过去我亲自使用过许多不同的数据库引擎,老实说,我懒得记住哪些是区分大小写的,哪些不是。 table_name 似乎被普遍接受,我从来没有遇到过任何问题。由于您专门为 Delphi 应用程序设计数据库,因此您可能希望选择 Pascal 样式,以便源代码不会混合不同的样式。我个人只是坚持field_name。 (顺便说一句:即使某些数据库允许在标识符中使用特殊字符,但我尽量避免它们像瘟疫一样,对于可能是数据库关键字的列名也是如此。即使我为表制造商设计了一个数据库,我也会从不将产品表命名为“tables”)

  4. 主键和外键包含表名 products 表获得一个 product_id 主键。无论其他表链接到该表,都将获得product_id 外键。这会自动记录数据库设计的一部分,并允许使用自然连接。我过去确实设计了一个数据库,其中每个表都有一个标有“id”的主键。这确实很快变得非常混乱。

  5. 其他列的表名没有前缀 这可能是这个列表上的规则,我每隔一段时间就会打破一次,但首先要做的是。根据这条规则,产品描述将进入description 字段,而不是product_description。造成这种情况的主要原因是代码中的混乱程度较低。查询变得更短并且更易于阅读。 SELECT product_id, description, price FROM products WHERE price>1 AND price<9SELECT product_id, product_description, product_price FROM products WHERE product_price>1 AND product_price<9 更容易阅读。两个查询都会做同样的事情,但一个比另一个跨越更多的代码行。 我有时会违反这条规则有三个原因:

    a. 用于主键。请参阅 #4 - 能够查看哪些列是主键,而不是杂乱无章,但足够重要,可以每次都记下来。

    b. 当两个完全不同的值类型共享相同的标识符时:人名与产品名称完全不同。在开发过程中的某些时候,它可以更轻松地区分person_nameproduct_name,而无需交出大量元数据。 (或者,就此而言,介于人员的 name 和产品的 brand_name 之间,这样就不需要表前缀。)

    c. 如果两个表都包含相同的字段名称,则很可能在查询中经常连接。如果您有一个产品的description 和一个订单的description,您可能需要重命名查询的列很多,这可能会很混乱。

同样,以上所有内容都是个人喜好。你的旅费可能会改变。唯一似乎得到普遍认同的是:选择一种风格并坚持下去

附:我可能没有回答您的部分问题,但是“......创建一个函数来处理与该索引控件相关的每个表总是更容易。”对我来说毫无意义。

【讨论】:

    【解决方案2】:

    我认为这主要是个人喜好和您喜欢打字的次数和时间。将所有字段名称键入为table_name.field_name,这样您就可以在join 语句中执行SELECT *,而不必在重复字段名称上使用表名进行预限定,这似乎需要在一个字段的几次前面输入很多可能需要进行资格预审,如果您的大多数选择语句都包含字段名称,那么必须输入 table_name.field_name 来输入字段似乎需要大量输入。

    我确信添加更长的字段名不会带来显着的性能问题,并且可能只有在架构信息通过网络传输 ODBC 时才会真正引起注意,但仍然不是真正的问题。

    我不了解 Delphi,但在 .NET 中,您也可以按位置查找字段名称,或者通过访问标记为主键字段的字段所以我不确定一个函数参数对于要求表具有相同的 ID 字段名称是否有效。

    我一直在我的表中保留名为 UID 的主键字段,并且没有在字段名称声明中包含表名,除了必须对多个表中的 UID 字段选择语句进行预限定之外,我从来没有遇到过问题.虽然我可以看到将 tablename.UID 包含在关键字段中的一些好处,因为跨多个表的许多 SELECT * 语句不会出现重复字段错误,除非其他表中有重复数据(我希望不会)。

    【讨论】:

    • 想一想,我确实遇到了一个问题,UniData ODBC 驱动程序最终限制了您可以提交的查询字符串的长度,它被限制为少于 256 个字符,并且是对我来说太局限了,无法在一个查询中包含我想要的所有字段名,并且这些字段名没有在字段名中以表名作为前缀。
    • 确实如此。这就是为什么我现在只从我的应用程序中调用程序的原因。我从不在我的代码中执行 SELECT,而只在过程中执行。
    【解决方案3】:

    要考虑的另一件事是数据库建模。 ERwin、Visio 等工具会自动将父 PRIMARY KEY 向下迁移关系,因此如果该字段在父表中有前缀,则无需在子表中重命名1。由于没有重命名,也没有任何人会忘记这样做的危险,只需看一眼字段的名称,您就可以自信地看到它的来源,而无需直观地跟踪字段起源的关系。当存在多个级别的关系并使 ER 图更具可读性时,这一点尤其重要,IMO。

    这也让我的 SQL 更清晰,因为我的大脑不需要“解析”别名来确定哪个字段来自哪里,并且使 NATURAL 连接的危险性降低了一点2,但其他人可能对此有不同的看法......


    1 如果您使用parent.idchild.id,则必须将迁移的密钥重命名为child.parent_id 之类的内容,以避免命名冲突。但是如果您使用parent.parent_idchild.child_id,则无需执行任何操作- 迁移的密钥会自动命名为child.parent_id。链继续以grandchild.grandchild_id 等...

    2老实说,如果你能提供帮助,你永远不应该做一个自然的 - 总是明确指定你的加入标准。

    【讨论】:

      【解决方案4】:

      在 delphi 中,您也可以使用别名来解决重复名称字段的问题。

      见:

      SELECT table1.fieldX AS 'myDesiredName', table2.fieldX AS 'myDesidedName2' FROM ...
      

      这解决了ClientdataSets o 对象查询中重复名称的问题。 您的 Delphi 应用程序使用您在 myDesiredName 中提供的名称

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-09-08
        • 2021-03-20
        • 2019-12-17
        • 2019-02-10
        • 1970-01-01
        • 2017-03-03
        • 1970-01-01
        相关资源
        最近更新 更多