【问题标题】:Database - tables design and query数据库 - 表设计和查询
【发布时间】:2012-02-26 16:02:00
【问题描述】:

我正在开发一个 php 程序,用户需要从下拉列表中选择技能(一项或多项) 然后我将结果保存在数组中: 用户技能[] 那么每个项目也有一个所需技能列表,我将它保存在另一个数组中:proj_skills[]

问题是: 将这些信息保存到数据库中的最佳方法是什么 我应该为项目技能和用户技能创建 2 个新表(列:proj_id 和技能) 每个技能连续,

比较项目与用户技能并找到匹配技能的最佳方法是什么? select id from user_skills where Skill=proj_skill[i] and id IN (select id from user_skills where Skill=Proj_skill[i+1].......嵌套选择/循环或(递归)

怎么做,最好的优化方法是什么?

希望清楚,在此先感谢 :)

【问题讨论】:

    标签: php mysql sql database select


    【解决方案1】:

    我不知道这是否是最好或最优化的方法,但这是一种方法。 :)

    首先,您需要的表格:(为简单起见,我省略了名称列等)

    CREATE TABLE skills (
        id INT UNSIGNED NOT NULL AUTO_INCREMENT,
        PRIMARY KEY (id)
    ) ENGINE=InnoDB;
    
    CREATE TABLE users (
        id INT UNSIGNED NOT NULL AUTO_INCREMENT,
        PRIMARY KEY (id)
    ) ENGINE=InnoDB;
    
    CREATE TABLE projects (
        id INT UNSIGNED NOT NULL AUTO_INCREMENT,
        PRIMARY KEY (id)
    ) ENGINE=InnoDB;
    
    CREATE TABLE user_skills (
        user_id INT UNSIGNED NOT NULL,
        skill_id INT UNSIGNED NOT NULL,
        PRIMARY KEY (user_id, skill_id),
        FOREIGN KEY (user_id) REFERENCES users (id),
        FOREIGN KEY (skill_id) REFERENCES skills (id)
    ) ENGINE=InnoDB;
    
    CREATE TABLE project_skills (
        project_id INT UNSIGNED NOT NULL,
        skill_id INT UNSIGNED NOT NULL,
        PRIMARY KEY (project_id, skill_id),
        FOREIGN KEY (project_id) REFERENCES projects (id),
        FOREIGN KEY (skill_id) REFERENCES skills (id)
    ) ENGINE=InnoDB;
    

    如果您想显示至少具有编号为 1、3 和 5 的技能的所有用户:

    SELECT user_id
    FROM user_skills
    WHERE skill_id IN (1, 3, 5)
    GROUP BY user_id
    HAVING COUNT(*) = 3;
    

    所以这里我们先用where子句过滤掉所有不相关的技能,然后按用户分组。之后,COUNT(*) 告诉我们每个用户有多少匹配技能。然后,having 子句仅显示具有 3 个匹配技能的用户,这意味着这些用户至少具有我们正在寻找的技能。

    如果您想显示所有具有技能 1、3 和 5 但没有其他技能的用户:

    SELECT s1.user_id
    FROM (
        SELECT user_id, COUNT(*) count
        FROM user_skills
        GROUP BY user_id
    ) s1
    INNER JOIN (
        SELECT user_id, COUNT(*) count
        FROM user_skills
        WHERE skill_id IN (1, 3, 5)
        GROUP BY user_id
    ) s2 ON (s1.user_id = s2.user_id)
    WHERE s1.count = 3 AND s2.count = 3;
    

    这里第一个子查询查找每个用户的总技能数,第二个子查询查找每个用户的匹配技能数。如果两者都是 3,则用户具有我们正在寻找的技能。

    如果要查找所有“兼容”的用户和项目,即用户至少具有项目所需的所有技能的所有 (project, user) -pairs:

    SELECT s2.project_id, s2.user_id
    FROM (
        SELECT project_id, COUNT(*) count
        FROM project_skills
        GROUP BY project_id
    ) s1
    INNER JOIN (
        SELECT project_skills.project_id, user_skills.user_id, COUNT(*) count
        FROM project_skills
        INNER JOIN user_skills ON (user_skills.skill_id = project_skills.skill_id)
        GROUP BY project_skills.project_id, user_skills.user_id
    ) s2 ON (s1.project_id = s2.project_id)
    WHERE s2.count = s1.count;
    

    在这里,第一个子查询找出每个项目所需的技能数量。第二个子查询找出每个(项目,用户)对有多少共同技能。它通过在技能上加入project_skillsuser_skills 然后按项目和用户分组来做到这一点。之后,COUNT(*) 告诉每个项目和用户有多少共同技能。最后,我们加入两个子查询,只显示 (project, user) -对,其中通用技能的数量等于项目所需的技能数量。

    【讨论】:

      【解决方案2】:

      如果一个用户可以与多个项目相关联,并且一个项目可以与多个用户相关联,那么听起来最好将用户和项目的技能存储在单独的表中。

      设置完两个表后,我将创建第三个表来保存所有可能的技能(我假设没有只能与用户或项目相关联的技能)。所以现在您将拥有以下表格,Users、Projects、UserSkills 和 ProjectSkills。

      设置完成后,假设您可以将 UserID 和 ProjectID 传递到查询中,我只需将用户技能与 SkillID 上的项目技能结合起来。例如,

      SELECT Q1.UserID,
             Q1.Skill
      FROM   (SELECT Users.UserID,
                     Skills1.Skill,
                     Skills1.SkillID
              FROM   Users
                     INNER JOIN UserSkills
                       ON Users.UserID = UserSkills.UserID
                     INNER JOIN Skills AS Skills1
                       ON UserSkills.SkillID = Skills1.SkillID
              WHERE  Users.UserID = 123) AS Q1
             INNER JOIN (SELECT Projects.ProjectID,
                                Skills2.Skill,
                                Skills2.SkillID
                         FROM   Projects
                                INNER JOIN ProjectSkills
                                  ON Projects.ProjectID = ProjectSkills.ProjectID
                                INNER JOIN Skills AS Skills2
                                  ON Project.SkillID = Skills2.SkillID
                         WHERE  ProjectID = 456) AS Q2
               ON Q1.SkillID = Q2.SkillID;
      

      一般来说,您会希望在使用 SQL 时避免迭代。你最好的表现是只问一次你想要的东西。此外,如果您按照上面编写的方式进行迭代,您会假设所有 ID 都将按顺序排列,但技能可能(并且很可能)不是。所以,两者可以有共同的技能 1 和 3,但不是 2。你会在技能 2 没有共同点后停止循环吗?你必须在sets 中思考。另外,请注意IN 子句。如果您尝试测试某些内容是否“不在”包含空值的结果集中,即使您的用户和项目具有共同的技能,您也不会收到任何结果。这是一篇关于http://bharatmane.com/blog/?p=52主题的文章

      【讨论】:

        【解决方案3】:

        我不是 php 编码员,所以您的一些问题忽略了我,但在数据库设计方面,您需要三个表:人员、技能和技能人员。后一个表将是一个“链接表”,至少有两个字段用作联合主键:人员和技能。您可以在此表中添加此人拥有该技能的程度。

        如果您有一个项目表和另一个项目所需技能的链接表,那么为了找到具备该项目所需技能的人,您需要编写如下内容:

        select people.name, skills.name
        from people inner join skillsperperson on people.id = skillsperperson.person
        inner join skills on skillsperperson.skill = skills.id
        inner join skillsperproject on skills.id = skillsperproject.skill
        where skillsperproject = :p1;  
        

        (:p1 是您传递给查询的参数;它的值将是给定项目的 id)。

        【讨论】:

          猜你喜欢
          • 2020-05-14
          • 2011-01-02
          • 2011-12-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-10-28
          • 1970-01-01
          相关资源
          最近更新 更多