不同级别的 2 个表中的唯一用户名。合适的数据库设计?
Unique usernames in 2 tables at different levels. Suitable database design?
我与供应商有一个 table。此 table 包含名称、用户名和密码哈希等内容。
有时一个供应商只是一个人,在这种情况下这很好。但有时供应商是一家公司,在这种情况下,可能需要多名员工登录。到目前为止,所有供应商员工每个供应商共享一个 username/password。现在我想给每个人个人证书。
我已经有一个 table 供应商联系人,所以最简单的方法是向 table 添加 2 列用户名和密码哈希。但是,由于我想保留在供应商 table 中为单人供应商提供用户名和密码哈希的选项,因此我无法为用户名创建唯一索引,因为它们分布在 2 tables.
我当然可以在 PHP 中强制使用唯一的用户名,但我想知道我是否犯了数据库设计错误。我考虑过创建一个新的 table 'users' 来放入所有凭据,但不知何故感觉不对。有什么建议吗?
这是创建第二个 table 的好案例。
考虑以下 table 结构:
Suppliers: SupplierId, Name, Address, etc..
SupplierLogins: SupplierLoginId, SupplierId, Username, Password
您可以使用此结构添加单个登录或多个登录。您的独特组合可以在 SupplierId, Username
组合上。 IMO,电子邮件 ID 是一个很好的登录方式 - 它消除了必须记住用户名的需要。
此外,例如,如果 Joel@Superuser.com 换了工作并转到了不同的供应商,那么他就变成了 Joel@AskDifferent.com,这样您就不必丢失所有的数据旧登录下的东西
我会把所有登录名都放在联系人 table 中,即使对于只有一个登录名的供应商也是如此。您还需要供应商的一次登录联系信息,将所有类似信息放在一个 table.
我认为 David Aldridge 和 Ray More 都给了你潜在的 suitable 设计建议,但我想更全面地回答你的问题,并专注于你的陈述“ [你]想知道[你]是否犯了数据库设计错误。"
简短版本: 是的,我认为你 犯了一个设计错误 - 坚持将单人供应商登录详细信息放在供应商 table - 这导致您拒绝自己的替代想法以及其他人建议的想法。
长版: 首先,从概念上而不是技术上考虑这个问题。登录详细信息属于谁?过去,它们属于供应商。现在,他们属于供应商员工。
在数据建模过程的早期(即在您到达创建物理模型之前),我们谈论属性而不是列,谈论实体而不是 tables - 所以登录详细信息是属性供应商雇员实体的属性,而不是供应商实体的属性。这意味着当您进行物理数据库设计时,这些列应该位于(或关联)SupplierContact table.
那么为什么登录总是属于供应商员工而不是供应商?想想这个场景:
You work with a supplier which has a single employee, so you create
one set of login details for them. A year later, the supplier's
business expands, and the person running it hires an assistant - they
also need access, so you need to make another set of login details for
the same supplier.
对于您建议的模型,您需要从 Supplier table 中删除当前的登录详细信息,并向 SupplierContact 添加两组详细信息。根据您的应用程序设计,您可能还会发现自己需要关闭供应商的原始帐户或强制重置他们的密码 - 这会让他们感到恼火。
另一种情况:如果您有正当理由拥有两种不同类型的帐户 - 供应商的组织帐户和供应商员工的个人帐户 - 那么情况就不同了.但是,您仍然可以实现将所有帐户集中在一个 table 中的两个目标,同时仍然将每种类型的帐户与相关 table(即供应商或供应商联系人)相关联。
例如,您可以有一个名为 table 的帐户,其中包含登录详细信息。从那里,有几个选项可以 link table 到供应商 或 SupplierContact。我不想讨论选择哪个选项,因为它是一个在其他地方(包括 SO 上)讨论得很好的问题,可以说是一个品味问题,但这里有一些选项:
- 在Account中添加两个可为空的外键列,一个可以保存SupplierId,一个可以保存SupplierContactId。可能建立一个约束以确保始终填充两者之一。
- 创建两个单独的 tables,SupplierAccount 和 SupplierContactAccount,各有两列。第一个应该有 SupplierId 和 AccountId 列,外键指向 Supplier 和 Account,第二个应该有 SupplierContactId 和 AccountId 列,外键指向 SupplierContact 和 Account。可能构建约束以确保帐户中的行不与多个供应商或供应商联系人相关联。
请注意,除非我真的有两种不同类型的帐户,否则我不会执行上述操作。它增加了复杂性,除非需要,否则不应这样做;如果您保留与 Supplier 关联的详细信息的唯一原因是您习惯了该结构或只是喜欢这种方式,那么请不要这样做。
另一种选择: 与此同时,我又想到了这个。我不会详细介绍,因为您已经接受了这一点并且可能知道足够的知识可以继续前进,但另一种选择是使用 Party 数据建模模式。
这种模式可以很好地处理您需要以类似方式与个人和组织或人群进行交互的情况。对于 Dennis 提到的情况,它也很有用,在这种情况下,您可能会以多种不同的方式与个人或组织互动 - 即,一方可能扮演多个角色。
Here's an article 关于这个想法,我第一次 运行 时发现它很有用。如果您想更深入地了解,撰写该文章的 Len Silverston 还出版了一些非常有用的数据建模书籍。这些书从更多 conceptual/abstract 级别一直到物理数据库模式。如果您在网上四处寻找派对数据模型模式,我相信您可以在网上找到类似的资源,如果这对您的情况有用的话。
我也有类似的情况,也许你可以从中吸取教训。首先,您应该考虑供应商是否真的只是供应商。在许多情况下,供应商也可能是客户。突然间,您的整个情况会因当前设置而变得更加复杂。为了解决这个问题,我将创建以下 tables:
- 帐号(id、姓名、地址、登录名、密码等)
- 供应商(id、账户...)
- 客户
- 等等
现在您可以在供应商和帐户以及客户和帐户之间创建关系。为了让一家公司有多个登录名,我为公司账户创建了子账户。为此,您可以有一个名为 parent
的字段并创建与另一个帐户的关系,也许还有一个名为 type
的字段,您可以在其中定义它是用户帐户还是公司帐户。
您可以将联系信息绑定到公司账户,让子账户使用这些信息。通过使用它,还可以更轻松地跟踪哪个用户在做什么。根据您的 clients/suppliers 和您所在的位置,为了遵守公司合规性,这也可能是必要的。
通过定义不同的帐户类型,您还可以定义这些帐户可以做什么(除了它们的组之外,还可以根据它们的类型进行权限处理等)。例如,用户帐户可以更改地址,但公司帐户只能在批准后才能执行此操作。
我不会将用户帐户绑定到供应商,而是将其绑定到另一个 company/organisation 帐户(正如我已经描述的那样),然后由供应商 table 引用该帐户。您现在基本上可以将每条信息绑定到一个帐户而不是多个帐户,但仍将这些信息提供给子帐户(如果需要且可行)。这有更多的好处,比如可以轻松地跟踪帐户关系等。您现在还可以将一个帐户绑定到多个公司帐户,如果某人在一家拥有姊妹公司的公司工作,这种情况并不少见。
我与供应商有一个 table。此 table 包含名称、用户名和密码哈希等内容。
有时一个供应商只是一个人,在这种情况下这很好。但有时供应商是一家公司,在这种情况下,可能需要多名员工登录。到目前为止,所有供应商员工每个供应商共享一个 username/password。现在我想给每个人个人证书。
我已经有一个 table 供应商联系人,所以最简单的方法是向 table 添加 2 列用户名和密码哈希。但是,由于我想保留在供应商 table 中为单人供应商提供用户名和密码哈希的选项,因此我无法为用户名创建唯一索引,因为它们分布在 2 tables.
我当然可以在 PHP 中强制使用唯一的用户名,但我想知道我是否犯了数据库设计错误。我考虑过创建一个新的 table 'users' 来放入所有凭据,但不知何故感觉不对。有什么建议吗?
这是创建第二个 table 的好案例。
考虑以下 table 结构:
Suppliers: SupplierId, Name, Address, etc..
SupplierLogins: SupplierLoginId, SupplierId, Username, Password
您可以使用此结构添加单个登录或多个登录。您的独特组合可以在 SupplierId, Username
组合上。 IMO,电子邮件 ID 是一个很好的登录方式 - 它消除了必须记住用户名的需要。
此外,例如,如果 Joel@Superuser.com 换了工作并转到了不同的供应商,那么他就变成了 Joel@AskDifferent.com,这样您就不必丢失所有的数据旧登录下的东西
我会把所有登录名都放在联系人 table 中,即使对于只有一个登录名的供应商也是如此。您还需要供应商的一次登录联系信息,将所有类似信息放在一个 table.
我认为 David Aldridge 和 Ray More 都给了你潜在的 suitable 设计建议,但我想更全面地回答你的问题,并专注于你的陈述“ [你]想知道[你]是否犯了数据库设计错误。"
简短版本: 是的,我认为你 犯了一个设计错误 - 坚持将单人供应商登录详细信息放在供应商 table - 这导致您拒绝自己的替代想法以及其他人建议的想法。
长版: 首先,从概念上而不是技术上考虑这个问题。登录详细信息属于谁?过去,它们属于供应商。现在,他们属于供应商员工。
在数据建模过程的早期(即在您到达创建物理模型之前),我们谈论属性而不是列,谈论实体而不是 tables - 所以登录详细信息是属性供应商雇员实体的属性,而不是供应商实体的属性。这意味着当您进行物理数据库设计时,这些列应该位于(或关联)SupplierContact table.
那么为什么登录总是属于供应商员工而不是供应商?想想这个场景:
You work with a supplier which has a single employee, so you create one set of login details for them. A year later, the supplier's business expands, and the person running it hires an assistant - they also need access, so you need to make another set of login details for the same supplier.
对于您建议的模型,您需要从 Supplier table 中删除当前的登录详细信息,并向 SupplierContact 添加两组详细信息。根据您的应用程序设计,您可能还会发现自己需要关闭供应商的原始帐户或强制重置他们的密码 - 这会让他们感到恼火。
另一种情况:如果您有正当理由拥有两种不同类型的帐户 - 供应商的组织帐户和供应商员工的个人帐户 - 那么情况就不同了.但是,您仍然可以实现将所有帐户集中在一个 table 中的两个目标,同时仍然将每种类型的帐户与相关 table(即供应商或供应商联系人)相关联。
例如,您可以有一个名为 table 的帐户,其中包含登录详细信息。从那里,有几个选项可以 link table 到供应商 或 SupplierContact。我不想讨论选择哪个选项,因为它是一个在其他地方(包括 SO 上)讨论得很好的问题,可以说是一个品味问题,但这里有一些选项:
- 在Account中添加两个可为空的外键列,一个可以保存SupplierId,一个可以保存SupplierContactId。可能建立一个约束以确保始终填充两者之一。
- 创建两个单独的 tables,SupplierAccount 和 SupplierContactAccount,各有两列。第一个应该有 SupplierId 和 AccountId 列,外键指向 Supplier 和 Account,第二个应该有 SupplierContactId 和 AccountId 列,外键指向 SupplierContact 和 Account。可能构建约束以确保帐户中的行不与多个供应商或供应商联系人相关联。
请注意,除非我真的有两种不同类型的帐户,否则我不会执行上述操作。它增加了复杂性,除非需要,否则不应这样做;如果您保留与 Supplier 关联的详细信息的唯一原因是您习惯了该结构或只是喜欢这种方式,那么请不要这样做。
另一种选择: 与此同时,我又想到了这个。我不会详细介绍,因为您已经接受了这一点并且可能知道足够的知识可以继续前进,但另一种选择是使用 Party 数据建模模式。
这种模式可以很好地处理您需要以类似方式与个人和组织或人群进行交互的情况。对于 Dennis 提到的情况,它也很有用,在这种情况下,您可能会以多种不同的方式与个人或组织互动 - 即,一方可能扮演多个角色。
Here's an article 关于这个想法,我第一次 运行 时发现它很有用。如果您想更深入地了解,撰写该文章的 Len Silverston 还出版了一些非常有用的数据建模书籍。这些书从更多 conceptual/abstract 级别一直到物理数据库模式。如果您在网上四处寻找派对数据模型模式,我相信您可以在网上找到类似的资源,如果这对您的情况有用的话。
我也有类似的情况,也许你可以从中吸取教训。首先,您应该考虑供应商是否真的只是供应商。在许多情况下,供应商也可能是客户。突然间,您的整个情况会因当前设置而变得更加复杂。为了解决这个问题,我将创建以下 tables:
- 帐号(id、姓名、地址、登录名、密码等)
- 供应商(id、账户...)
- 客户
- 等等
现在您可以在供应商和帐户以及客户和帐户之间创建关系。为了让一家公司有多个登录名,我为公司账户创建了子账户。为此,您可以有一个名为 parent
的字段并创建与另一个帐户的关系,也许还有一个名为 type
的字段,您可以在其中定义它是用户帐户还是公司帐户。
您可以将联系信息绑定到公司账户,让子账户使用这些信息。通过使用它,还可以更轻松地跟踪哪个用户在做什么。根据您的 clients/suppliers 和您所在的位置,为了遵守公司合规性,这也可能是必要的。
通过定义不同的帐户类型,您还可以定义这些帐户可以做什么(除了它们的组之外,还可以根据它们的类型进行权限处理等)。例如,用户帐户可以更改地址,但公司帐户只能在批准后才能执行此操作。
我不会将用户帐户绑定到供应商,而是将其绑定到另一个 company/organisation 帐户(正如我已经描述的那样),然后由供应商 table 引用该帐户。您现在基本上可以将每条信息绑定到一个帐户而不是多个帐户,但仍将这些信息提供给子帐户(如果需要且可行)。这有更多的好处,比如可以轻松地跟踪帐户关系等。您现在还可以将一个帐户绑定到多个公司帐户,如果某人在一家拥有姊妹公司的公司工作,这种情况并不少见。