在一个字段中存储多个值

时间:2011-06-26 23:30:51

标签: php mysql sql database-design

我希望用户能够选择他们的专业。

例如,A人可以选择计算机科学,数学和历史作为他的专业。用户可以选择任意数量的专业。

我的数据库中有一个组织列表,只有学生才能接受特定专业。例如,组织A只接受计算机科学和数学专业。组织可以选择任意数量的专业。

我想让学生与适合他们专业的组织相匹配。例如,我想在数据库中搜索接受一个或多个Person的A专业的组织,这些专业是计算机科学,数学和历史。接受全部或大部分人员A级专业的组织将首先列出。因此,如果组织B接受所有三个人的A级专业,但组织A只接受两个人的A级专业,则组织B将首先列出。

如何存储组织在mysql数据库中接受的专业?如何存储学生的专业,以便在学生信息和组织信息之间进行有效匹配?

我正在考虑将组织接受的所有主要内容存储为数据库中的序列化值。

所以我有2张桌子

组织
ID int
name varchar(255)
majors_accepted blob

学生
ID int
name varchar(255)
专业blob

我可以将组织接受的专业存储为majors_accepted blob中的序列化值。该领域可能有一个以上的专业。

或者我可以将学生正在考虑的专业存储在Students表的专业领域中作为序列化值。该领域可能有1个以上的专业。然后我想我可以浏览组织表中的所有行,并将每个majors_accepted字段与学生数据进行比较。但这似乎效率低下......

3 个答案:

答案 0 :(得分:3)

我会这样做:

  1. 创建一个主要表 - 具有majorID和majorName
  2. 在具有studentID和majorID的学生和专业之间创建关联表。
  3. 在具有orgID和majorID的组织和专业之间创建关联表。
  4. 在一个字段中存储多个值并不是很好的数据库设计,就像你想要对你的blob做的那样,所以要像这样打破它,你可以做所有必要的查询来确定哪个组织是学生只需加入表即可加入。

    假设你正在寻找一个特定学生可以加入的组织(我们会说这个学生的学生ID是1):

    SELECT Students.ID,
           Organizations.name
    FROM Students 
    INNER JOIN StudentsMajors ON Students.ID = StudentsMajors.studentID
    INNER JOIN OrganizationsMajors ON StudentsMajors.majorID = OrganizationsMajors.majorID
    INNER JOIN Oranizations ON OrganizationsMajors.orgID = Organizations.ID
    WHERE Students.ID = 1
    

答案 1 :(得分:2)

不要尝试将主要列表作为blob存储在单个列中,为此使用单独的关联表:

create table organization_majors (
    organization_id int not null,
    major_id        int not null,
    primary key (organization_id, major_id)
);
create table student_majors (
    student_id int not null,
    major_id   int not null,
    primary key (student_id, major_id)
);

您可能还希望单独为主键中的每一列编制索引,但索引依赖于(通常情况下)您可能使用的查询类型。

然后,您可以使用标准SQL查询来检查主要内容是否匹配。例如,要查找major_id为1的所有学生:

select s.id, s.name
from students s join student_majors m on s.id = m.student_id
where m.major_id = 1

或查找可以在组织11中的所有学生:

select s.id, s.name
from students s
join student_majors sm on s.id = sm.student_id
join organization_majors om on sm.major_id = om.major_id
where om.organization_id = 11
group by s.id, s.name
having count(*) = (select count(*) from organization_majors where organization_id = 11)

答案 2 :(得分:2)

学生和专业之间的关系是多对多的。对于多对多的最佳设计是关联表,正如其他响应者已经说过的那样。关联表将返回学生表和主要表,其中包含主要名称等数据。

使用逗号等分隔符在一个字段中存储多个值是糟糕的设计。它违反了第一范式。当您违反First Normal Form时,您无法再对所有数据进行键控查找。

例如,您必须进行全表扫描才能找到具有特定专业的所有学生。这可能导致数千个磁盘ios,而不是少于100个磁盘ios进行三向连接。这慢了十倍。

当您计划对关联表进行键控查找时,请注意良好的索引设计。一个好的查询优化器以及良好的索引设计可以从您的连接中获得最佳速度。幸运的是,您可以返回并更改索引设计,而无需卸载和重新加载表。