2012-02-04 2 views
1

я работаю над программой PHP, пользователю необходимо выбрать навыки (один или несколько) из выпадающего списка тогда я сохранить результат в массиве: user_skills [] то каждый проект имеет список необходимых навыков тоже, я спасу его в другой массив: proj_skills []базы данных - разработка таблиц и запросов

вопрос: , что это лучший способ, чтобы сохранить эти данные в базу данных я должен создать 2 новых столы для навыков проектов и навыков пользователя (столбцы: proj_id и умение) каждый навык в строке,

a nd, что является лучшим способом сравнить проект с навыками пользователя и найти подходящие навыки? выберите id из user_skills, где skill = proj_skill [i] и id IN (выберите id из user_skills, где skill = Proj_skill [i + 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; 

Итак, мы первый отфильтровывать все ненужные навыки, где положение, а затем группы пользователем. После этого COUNT(*) расскажет, сколько совпадений было у каждого пользователя. В заключении есть только пользователи с тремя навыками соответствия, что означает, что у этих пользователей были, по крайней мере, те навыки, которые мы искали.

Если вы хотите, чтобы показать все пользователь, которые имеют навыки 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(*) рассказывается, сколько общих навыков у каждого проекта и у пользователя есть. Наконец, мы присоединяем два подзапроса и показываем только (проектные, пользовательские) пары, где количество общих навыков равно количеству навыков, необходимых для проекта.

1

Если пользователь может быть связан с несколькими проектами, и проект может быть связан с несколькими пользователями, похоже, было бы лучше хранить навыки для пользователей и проектов в отдельных таблицах.

После настройки обеих таблиц я создал бы третью таблицу для хранения всех возможных навыков (я предполагаю, что нет навыков, которые могут быть связаны только с пользователем или только с проектом). Итак, теперь у вас будут следующие таблицы: пользователи, проекты, 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. Ваша лучшая производительность - это спросить, что именно вы хотите только один раз. Кроме того, если вы повторите так, как вы писали выше, вы предполагаете, что все идентификаторы будут в последовательности, но возможно (и, вероятно), что навыков не будет. Таким образом, у двух могли бы быть навыки 1 и 3 вместе, но не 2. Вы остановили бы свою петлю после получения ничего общего на навыке 2? Вы должны думать в sets. Кроме того, будьте осторожны с предложением IN. Если вы попытаетесь проверить, есть ли что-то «НЕ В» в результирующем наборе, содержащем нуль, вы не получите никаких результатов, даже если у пользователя и проекта есть общие навыки. Вот статья по теме http://bharatmane.com/blog/?p=52

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 - это параметр, который вы передаете запросу, его значение будет идентификатором данного проекта).

Смежные вопросы