【问题标题】:Database design - system default items and custom user items数据库设计 - 系统默认项和自定义用户项
【发布时间】:2012-02-10 14:25:15
【问题描述】:

这个问题适用于任何数据库表设计,您将拥有相同类型的系统默认项和自定义用户默认值(即用户可以添加自己的自定义项/设置)。

这是发票和付款类型的示例,默认情况下,发票可以具有 DueOnReceipt、NET10、NET15、NET30 的付款条件(这是所有用户的默认设置!)因此您将有两个表“INVOICE”和“PAYMENT_TERM” "

INVOICE
Id
...
PaymentTermId



PAYMENT_TERM (System default)
Id
Name

现在,让用户存储自己的自定义“PaymentTerms”的最佳方式是什么?为什么? (即用户可以使用系统默认付款条件或用户自己创建/添加的自定义付款条件)

选项1)将UserId添加到PaymentTerm,为添加自定义项目的用户设置userid,系统默认userid设置为null。

INVOICE
Id
...
PaymentTermId



PaymentTerm
Id
Name
UserId (System Default, UserId=null)

选项 2) 向发票“IsPaymentTermCustom”添加标志并创建自定义表“PAYMENT_TERM_CUSTOM”

INVOICE
Id
...
PaymentTermId
PaymentTermCustomId
IsPaymentTermCustom (True for custom, otherwise false for system default)

PaymentTerm
Id
Name

PAYMENT_TERM_CUSTOM
Id
Name
UserId

现在通过 SQL 查询检查用户是否使用自定义付款条件,如果 IsPaymentTermCustom=True,则表示用户正在使用自定义付款条件,否则为假。

选项 3) ??????

...

【问题讨论】:

  • 你能解释一下用户体验流程吗?用户如何实际选择“自定义”付款条件?当他们浏览结帐流程并准备提交发票时?
  • 当用户创建发票时,用户可以选择“PaymentTerms”,系统默认的付款条件被加载到下拉列表中,用户可以选择默认的付款条件或添加一个新的付款条件,(他自己的),因此下次下拉列表将加载系统默认值和用户的付款条件。
  • 如果某个特定用户创建了 PaymentTerm,其他人可以使用它,还是只能他们使用?
  • @WW 只是创建付款条件的单个用户,因此 UserId 将等于付款条件的所有者。
  • 系统默认付款条件的详细信息以后会更改吗?喜欢从 2012 年 1 月 1 日开始更改 NET10 的条款吗?如果是这样,那会是一种新的系统支付类型,还是旧的会与所有以前的发票一起更新?新条款会出现,旧条款会失效吗?是否有与 PAYMENT_TERM 相关的其他数据?发票与特定的 UserID 相关联,对吧?

标签: database database-design


【解决方案1】:

作为一般规则:

  • 更喜欢添加列而不是添加表
  • 倾向于添加行而不是添加列

一般来说,考虑因素是:

添加表格的效果

  • 需要对应用进行最多更改:您正在支持一种新的“事物”
  • 需要更复杂的 SQL:您必须以某种方式加入它
  • 可能需要更改其他表以添加引用新表的外键列
  • 影响性能,因为需要更多的 I/O 来加入和读取新表

请注意,我并不是说“从不添加表格”。只知道成本。

添加列的效果

  • 如果表很大,添加一列可能会很昂贵(ALTER TABLE ADD COLUMN 可能需要几个小时才能完成,在此期间表将被锁定,从而有效地使您的站点“关闭”),但这是一个-时间的事情
  • 项目成本低:易于编码/维护
  • 通常只需要对应用进行少量更改 - 这是事物的新方面,而不是新事物
  • 性能差异可忽略不计。不会明显更糟,但可能会快很多,具体取决于具体情况(如果让新列避免加入或进行昂贵的计算)。

添加行的效果

  • 零:如果您的数据模型可以通过添加更多行来处理您的新业务理念,那么这是最佳选择

(学究们请不要制作诸如“不存在‘零’影响之类的东西”或“但仍有更多磁盘用于更多行”之类的 cmets - 我说的是 material 对数据库/项目/代码的影响)


要回答这个问题:选项 1 最好(即在付款选项表中添加一列)。
推理基于上述准则,这种情况非常适合这些准则。

进一步,
我还将“标准”支付选项存储在 same 表中,但使用 NULL 用户 ID;这样一来,您只需在真正有一个支付选项时添加新的支付选项,而不是为每个客户添加新的支付选项,即使他们使用的是标准选项。

这也意味着您的发票表不需要需要更改,这是一件好事 - 这意味着对应用程序的该部分影响最小。

【讨论】:

  • 我想知道为什么那个选项会比选项 2 更好?
  • 选项 1 更好,因为您可以通过一个(简单的)数据库查询获得标准和用户特定的付款条件。
【解决方案2】:

在我看来,只有“付款条款”和“用户”。什么是“默认”支付条款的决定是一个业务规则,因此最好在应用程序的业务层中体现出来。

假设您希望从一开始就在您的应用程序中显示一组预定义的“默认”付款条款,这些付款条款表中应该已经存在。但是,我会在 USERS 和 PAYMENT TERMS 之间放置一个参考表:

USERS:
    user-id
    user_namde

USER_PAYMENT_TERMS:
    userID
    payment_term_id

PAYMENT_TERMS:
    payment_term_id
    payment_term

您的业务层应通过 GUI 向用户(或更可能是管理员)提供以下功能:

  1. 将 0 分配给特定用户的多个付款期限选项(某些 用户可能不希望默认值之一可用,因为 示例。
  2. 添加自定义付款条件,然后可将其分配给一个或多个用户(但这样可以避免不同用户创建重复的付款条件)
  3. 允许将自定义付款条款的定义分配给多个用户(例如,用户的公司有一个独特的付款流程,要求所有用户使用默认付款条款以外的付款条款?创建自定义条款一次,然后分配给所有用户。

您的应用程序业务层将建立管理支付条款访问权限的规则,然后您的用户界面可以访问这些规则。

然后,您的 UI 将(同样,可能通过管理员功能)允许设置一个或多个付款条件,以及您描述的标准,然后通过检查列表之类的方式将它们提供给一个或多个用户框(例如)。

【讨论】:

    【解决方案3】:

    选项 1 肯定更好,原因如下:-

    正确性

    • 您可以为付款期限名称的唯一性实施数据库约束
    • 您可以实现从 Invoice 到 PaymentTerm 的外键约束

    易于使用

    • 执行查询会简单得多,因为您总是从 Invoice 连接到 PaymentTerm,而不需要更复杂的连接。大多数情况下,当您选择时,您不会关心它是内置还是自定义付款条款。优化器将更轻松地使用普通连接,而不是依赖另一列来决定要连接哪个表。
    • 更容易显示来自一个表的 PaymentTerms 列表

    我们在数据模型中经常使用选项 1。

    【讨论】:

      【解决方案4】:

      在我看来,部分问题在于不同的付款条件也会导致不同的计算。如果我还在做焊接供应业务,我想加上“2% 10 NET 30”,这意味着如果在 10 天内全额付款,则可以享受 2% 的折扣,否则为 30。”

      撇开这个问题不谈,我认为付款条款的所有权是有道理的。假设用户表(未显示)包括用户“系统”,例如 user_id 0。

      create table payment_terms (
        payment_term_id integer primary key,
        payment_term_owner_id integer not null references users (user_id),
        payment_term_desc varchar(30) not null unique,
      );
      
      insert into payment_terms values (1, 0, 'Net 10');
      insert into payment_terms values (2, 0, 'Net 15');
      ...
      insert into payment_terms values (5, 1, '2% 10, Net 30');
      

      这使外键保持简单,并且可以在运行时轻松选择付款条件以在用户界面中显示。

      在这里要非常小心。您可能希望将描述而不是 ID 号与您的发票一起存储。 (它是唯一的;您可以为其设置外键引用。)如果您只存储 ID 号,更新用户的自定义描述可能会巧妙地破坏引用它的所有数据。

      例如,假设用户创建了一个自定义付款期限编号 5,“2% 10, Net 30”。您将 ID 号 5 存储在发票表中。然后用户决定从今天开始情况会有所不同,并将该描述更新为“2% 10, Net 20”。现在,在您过去的所有发票上,算法不再符合付款条件。

      你的审计师会杀了你。两次。

      您需要防止普通用户删除系统用户拥有的行。有几种方法可以做到这一点。

      • 使用 BEFORE DELETE 触发器。
      • 添加另一个表,其中包含对系统用户拥有的行的外键引用。
      • 通过防止删除系统行的存储过程限制所有访问。

      (而且标志几乎从来都不是最好的主意。)

      【讨论】:

      • 不完全。 a) 没有空值。 b) 独特的描述。 c) 发票使用唯一描述的外键。 (如果我在设计它,我可能根本不会使用 payment_term_id。)
      【解决方案5】:

      将数据库设计的一般规则应用于手头的问题:

      • 系统付款条件表
      • 用户付款条件表
      • 以上两者的连接视图

      现在您可以在查看付款条件时加入发票。

      好处:

      • 没有标志列
      • 没有空值
      • 您将系统默认值与用户数据分开
      • 对于 db,事情变得简单了

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-11-10
        • 2020-01-08
        • 1970-01-01
        • 2013-04-23
        • 1970-01-01
        相关资源
        最近更新 更多