【问题标题】:How to Structure a Table where *some* Columns can have Multiple Values? [duplicate]如何构建*某些*列可以有多个值的表? [复制]
【发布时间】:2023-03-28 13:41:01
【问题描述】:

可能重复:
How to Store Multiple Options selected by User in a Table

我对此感到非常困惑。

我希望我的用户能够限制谁可以与他们联系。因此,我需要为每个用户及其选择的条件创建一个新的 RESTRICTIONS 表,该表将为每个用户的限制条件创建一个列。这些列将包括年龄、收入、寻找、毒品等。其中一些列(寻找、毒品等)可能包含多种选择,这就是我的问题。考虑到某些条件(列)可以有多个值而其他条件没有,我该如何以这种方式构建表格?

有人告诉我连接表和枚举值(我以前从未使用过这两者),但我真的很困惑如何构建一个表,其中某些列(不是全部)可以包含多项选择。

如何将这些多项选择存储在表格的那些特定列中,以及如何构建 RESTRICTIONS 的整个表格?

【问题讨论】:

  • 类似的?看起来是同一个用户提出的同一个问题
  • 我之前的问题不够清楚或不够具体,所以我得到的答案让我感到困惑。这个问题更清晰,更具体,结果我得到了更多对我来说更清楚的答案。我不明白为什么版主会关闭一个收到很好、多样和彻底答案的问题。这似乎完全适得其反。

标签: php mysql database database-design


【解决方案1】:

一个 DB 列(至少在理论上)应该包含多个值。不幸的是,有些程序员在单个列中存储多个值(例如,值以逗号分隔)——这些程序员(在大多数情况下)破坏了 DB 和 SQL 的概念。

我建议您阅读有关 Database Normalization 的信息,以开始组织您的表格。并且,尽最大努力实现Codd's Third Normal Form

【讨论】:

    【解决方案2】:

    这是最简单的方法。多个属性成为第二个表中的行。

    CREATE TABLE restrictions (
      user_id INTEGER PRIMARY KEY, -- references users (user_id), not shown
      age_restriction VARCHAR(10) NULL,
      income_restriction VARCHAR(20) NULL
    );
    
    CREATE TABLE looking_for (
      user_id INTEGER NOT NULL REFERENCES restrictions (user_id),
      looking_for VARCHAR(35) NOT NULL, -- could also be a foreign key.
      PRIMARY KEY (user_id, looking_for)
    );
    
    INSERT INTO restrictions (user_id) VALUES (1);
    INSERT INTO restrictions (user_id, age_restriction) VALUES (2, '> 25');
    
    INSERT INTO looking_for VALUES (1, 'boat');
    INSERT INTO looking_for VALUES (1, 'dunky fazoo');
    

    如果您想接受多个年龄限制,例如“> 25”和“

    要检索所有限制,请使用 OUTER JOIN。

    SELECT r.user_id, r.age_restriction, r.income_restriction, lf.looking_for
    FROM restrictions r
    LEFT JOIN looking_for lf ON lf.user_id = r.user_id
    

    【讨论】:

    • 非常清晰透彻,谢谢。使用您的示例,我将如何获取所有用户限制(包括不在限制表本身中的限制)?
    • 使用外连接。请参阅上面的修改。
    • 这是迄今为止最清晰的答案,谢谢。为什么说在“looking_for”表中,“looking_for”列也可以是外键?
    • 它可能是另一个表(未显示)的外键,其中仅包含可能允许查找的有效内容。现在,用户可以在其中输入任何内容,例如“atoinshrdlu”或“Phhht”。
    【解决方案3】:

    您可能需要不止一张桌子。

    您已经有一个“用户”表,对吧?如果您的“限制”条件之一每个用户只能有一个值,则该列属于“用户”表。所以你可能在 users 表中有列“min_age”和“max_age”,因为大概每个用户只有一个他们正在寻找的连续年龄范围。

    另一方面,对于每个可以有多个值的限制条件,您需要一个新表。所以你可能有一个表“users_restrictions_drugs”,其中主键是(用户,药物)。但是您可能还有一个表“users_restrictions_lookingfor”,其中主键是(用户,查找)。无论“寻找”是什么。

    对于其中一些表格,它可能也有意义

    • 将第二列(不是“用户”的列)定义为枚举
    • 或(更好)有一个额外的表,列出第二列的可能值并由外键引用。

    【讨论】:

    • 好的,所以要组织每个用户的限制条件,我需要为单个(非多个)条件创建一个 RESTRICTIONS 表,还需要为每个多个条件创建一个附加的连接表,是否正确?如果是这样,那听起来很复杂,因为所有条件都不在同一个表下,并且获取所有用户条件似乎涉及多个查询。这是最好的方法吗?如果是这样,我会走这条路。
    • 几乎,但您不需要 RESTRICTIONS 表。这些列都可以放在用户表中。对于可以有多个值的条件,您只需要额外的表格。
    • 很有趣,但我担心这可能会使 User 表太大。这样做有什么缺点,或者在这种情况下,一张更大的桌子比第二张桌子更可取吗?
    • “太大”是什么意思?你的意思是它有超过 1000 列(InnoDB 的最大值),或者行大小大于 65,535 字节(MySQL 的最大值)? RDBMS 旨在处理大表和小表。
    【解决方案4】:
    table restrictions
    user_id smoker_ok min_height max_height min_age max_age
    -------------------------------------------------------
    1       Y               150       200        24     34
    2       N               100       180        32     57
    
    table drug_restrictions
    user_id     drug_id   drug_allowed
    ----------------------------------
    1                H               N
    1                M               Y
    2                E               Y
    

    就是一个例子。在限制表中,您可以存储明确的奇异值 - 吸烟者是或否,或最小和最大要求。 对于有多个选择的每个表,您可以创建一个连接表 - 我已经给出了一个关于药物的示例。 在 drug_restrictions 表中,用户 1 说她不希望人们使用 H,但确实希望人们使用 M。

    此解决方案允许您将“drug_id”用作数据库中填充用户界面上“drugs”字段的任何表的外键。它允许您对这些外键使用常规的标准 SQL 约定,并通过将它们声明为外键来在数据库级别强制执行它们。

    当然,缺点是您必须查询大量表才能找到匹配的记录,这并不好玩。

    因此,您也可以遵循 Catcall 的建议 - 这大大减少了表的数量,但无法使用“标准”外键完整性约束。这可能没问题 - 它肯定会更快。

    我不愿意使用枚举——它们往往会导致复杂的查询,并且不是“标准”SQL。

    【讨论】:

    • 好的,所以要组织每个用户的限制条件,我需要为单个(非多个)条件创建一个 RESTRICTIONS 表,还需要为每个多个条件创建一个附加的连接表,是否正确?如果是这样,这听起来很复杂,因为所有条件都不在同一个表下,并且获取用户的所有条件似乎涉及多个查询。这是最好的方法吗?如果是这样,我会走这条路。
    • 好吧,像往常一样,这取决于 - 我已经详细说明了我的答案。
    • 感谢您的澄清,内维尔。我很感激。速度对我来说更重要,所以我将专注于 Catcall 的答案。再次感谢。
    【解决方案5】:

    有些列有重复值的表没有问题。考虑一个有用户的 tbale;如果两个用户的生日相同,没有问题吗?

    唯一的问题是一个主键 出现多次的表。例如,一个用户表很可能将username 作为其主键,而您不希望两个用户具有相同的用户名。

    因此,制作一张列出用户的表格,一张列出限制的表格,以及一张连接这两者的表格。后者将为每个用户/权限组合提供一个条目。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-11
      • 1970-01-01
      • 2017-02-20
      • 2017-11-26
      • 2020-01-05
      • 2020-12-12
      相关资源
      最近更新 更多