La façon la plus souple utilise plusieurs jointures; Les listes GROUP_CONCAT et les listes séparées par des virgules sont considérées comme un anti-modèle et cela peut ne pas fonctionner si la concaténation n'est pas faite exactement dans le bon ordre (l'ensemble de compétences 1,2,5 est considéré comme différent de 1,5,2).
SELECT c.* FROM candidates AS c
JOIN candidateskills AS cs ON (cs.cand_id = c.id)
JOIN skills AS sk1 ON (cs.skill_id = sk1.id)
JOIN skills AS sk2 ON (cs.skill_id = sk2.id)
...other sk(N)...
WHERE (sk1.skill = 'waterskiing')
AND (sk2.skill = 'snowboarding')
...
;
Cela permet Tailoring facile de compétences si, par exemple, chaque compétence a un niveau de compétence et vous avez besoin pour le snowboard pour être qualifiés ou au-dessus de niveau 5. Ce genre de flexibilité est un enfer à voir avec GROUP_CONCAT
.
Mais pour la correspondance simple, vous pouvez le faire plus rapidement en sélectionnant les compétences que vous voulez et il suffit de les compter:
SELECT c.* FROM candidates AS c
JOIN candidateskills AS cs ON (cs.cand_id = c.id)
WHERE cs.skill_id IN (1, 7, 24, 19, 115)
GROUP BY c.id
HAVING COUNT(1) = 5;
(Dans SQL plus approprié, vous aurez besoin d'indiquer explicitement tous les champs de c au lieu de "c. *", et répétez-les dans la clause GROUP BY. Plus les serveurs RDBMS intelligents ne s'en soucieront pas tant que vous les groupez par la clé primaire de C. MySQL actuellement s'en fout de toute façon, mais en mode strict, il le ferait).
Pour chaque compétence, vous exécutez une seule requête rapide sur les compétences pour récupérer son ID et assembler la requête ci-dessus.
Ou vous pouvez faire en une seule requête plus aussi longtemps que vous avez une correspondance exacte pour la compétence:
SELECT c.* FROM candidates AS c
JOIN candidateskills AS cs ON (cs.cand_id = c.id)
JOIN skills AS s ON (cs.skill_id = s.id)
WHERE s.skill IN ('javascript', 'html5', 'php')
GROUP BY c.id
HAVING COUNT(1) = 3;
Puisque vous voulez que cela en PHP:
$skills = array('javascript', 'html5', 'php');
$skno = count($skills);
$set = implode(',', array_fill('?', $skno));
$params = $skills;
$params[] = $skno;
$query = "SELECT c.* FROM candidates AS c
JOIN candidateskills AS cs ON (cs.cand_id = c.id)
JOIN skills AS s ON (cs.skill_id = s.id)
WHERE s.skill IN ({$set})
GROUP BY c.id
HAVING COUNT(1) = ?";
$stmt = $db->prepare($query);
$stmt->execute($params);
while ($candidate = $stmt->fetch(PDO::FETCH_ASSOC)) {
...
}
Il est bon solution mais il y a toujours un problème. Les identifiants de compétence peuvent être 5,6,7,8 et ce que nous voulons peut être 5 et 7. Dans cette condition, cette solution ne fonctionnera pas. –
Vous pouvez diviser la condition where et joindre un et pour chaque skill_id. –