我正在开发一个php程序,用户需要从下拉列表中选择技能(一个或多个) 然后我将结果保存在数组中: user_skills [] 然后每个项目都有一个必需技能列表,我将它保存在另一个数组中:proj_skills []
问题是: 将这些信息保存到数据库中的最佳方法是什么 我应该为项目技能和用户技能创建2个新表(列:proj_id和技能) 连续的每项技能,
什么是比较项目与用户技能并找到匹配技巧的最佳方法? 从user_skills中选择id,其中skill = proj_skill [i]和id IN(从user_skills中选择id,其中skill = Proj_skill [i + 1] .......嵌套select / loop或(递归)
怎么做,最好和最优化的方式是什么?
希望很清楚,在此先感谢:)
答案 0 :(得分:1)
如果用户可以与多个项目相关联,并且项目可以与多个用户相关联,那么最好将用户和项目的技能存储在单独的表中。
在设置两个表之后,我会创建第三个表来保存所有可能的技能(我假设没有技能只能与用户或仅与项目相关联)。现在,您将拥有以下表,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
子句。如果您尝试测试以查看某些内容是否为“NOT IN”包含null的结果集,即使您的用户和项目具有相同的技能,也不会收到任何结果。这是一篇关于http://bharatmane.com/blog/?p=52
答案 1 :(得分: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,则用户具有我们正在寻找的技能。
如果您想找到所有“兼容”的用户和项目,即所有(项目,用户) - 用户至少具有项目所需技能的所有(项目,用户) -
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_skills
和user_skills
技能,然后按项目和用户进行分组来实现此目的。之后,COUNT(*)
会告诉每个项目和用户有多少常用技能。最后,我们加入两个子查询,只显示(项目,用户) - 共同技能的数量等于项目所需技能的数量。
答案 2 :(得分:0)
我不是一个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)。