2017-07-31 22 views
0

我拥有candidates,candidate-skillsskills的MySql表。 这是最好的方式选择所有技能的候选人使用GROUP_CONCAT选择具备所有技能的候选人

我试过使用以下查询。但它不准确。

两点我想是:

  1. 所有的技能应显示(在评论中那里的条件时)
  2. 记录了所有的技能都被显示。 (具有一种技能的记录也显示为我正在使用阵列中的哪个位置)

我正在使用codeigniter框架。

http://sqlfiddle.com/#!9/b75c3/49

回答

1

,而不是在那里使用having子句。

select `t`.*, GROUP_CONCAT(DISTINCT(s.name)) as skills, 
GROUP_CONCAT(DISTINCT(s.id)) as skill_ids 
FROM `candidates` `t` 
LEFT JOIN `candidate-skills` `cs` ON `t`.`id` = `cs`.`can_id` 
LEFT JOIN `skills` `s` ON `cs`.`skill_id` = `s`.`id` 
GROUP BY `t`.`id` 
having find_in_set ('8', skill_ids) and find_in_set ('10', skill_ids) 
ORDER BY `t`.`id` desc 
在笨

//take all skill ids in array 
$ids=['8','10']; 
$this->db->select("t.*"); 
$this->db->select("GROUP_CONCAT(DISTINCT(s.name)) as skills"); 
$this->db->select("GROUP_CONCAT(DISTINCT(s.id)) as skill_ids"); 
$this->db->from("candidates t"); 
$this->db->join("candidate-skills cs","t.id = cs.can_id"); 
$this->db->join("skills s","cs.skill_id = s.id"); 
$this->db->group_by("t.id"); 
foreach ($ids as $id) { 
$this->db->having("find_in_set ('$id', skill_ids)"); 
} 
$this->db->order_by("t.id","desc"); 
$query=$this->db->get(); 
$candidates=$query->result(); 
0

也许这

select t.* , 
     s.skills,s.skills_id 
FROM `candidates` `t` 
join 
(
select t.id tid, group_concat(s.name) skills, group_concat(s.id order by s.id) skills_id 
FROM `candidates` `t` 
LEFT JOIN `candidate-skills` `cs` ON `t`.`id` = `cs`.`can_id` 
LEFT JOIN `skills` `s` ON `cs`.`skill_id` = `s`.`id` 
group by t.id 
) s 
on s.tid = t.id 
where instr(skills_id,'8,10') > 0 

+----+----------------+---------------------+-------------+------------+-------------------------------------------+-------------+ 
| id | name   | created_on   | modified_on | is_deleted | skills         | skills_id | 
+----+----------------+---------------------+-------------+------------+-------------------------------------------+-------------+ 
| 1 | Eugine   | 2017-05-23 11:44:30 | NULL  | N   | zend framework 2,bootstrap,wordpress  | 8,10,12  | 
| 2 | Frinoy Francis | 2017-05-23 16:44:29 | NULL  | N   | html,html5,zend framework 2,php,bootstrap | 1,4,8,10,11 | 
+----+----------------+---------------------+-------------+------------+-------------------------------------------+-------------+ 
2 rows in set (0.03 sec) 

MariaDB [sandbox]> select t.* , 
    -> s.skills,s.skills_id 
    -> FROM `candidates` `t` 
    -> join 
    -> (
    -> select t.id tid, group_concat(s.name) skills, group_concat(s.id order by s.id) skills_id 
    -> FROM `candidates` `t` 
    -> LEFT JOIN `candidate-skills` `cs` ON `t`.`id` = `cs`.`can_id` 
    -> LEFT JOIN `skills` `s` ON `cs`.`skill_id` = `s`.`id` 
    -> group by t.id 
    ->) s 
    -> on s.tid = t.id 
    -> where instr(skills_id,'') > 0 
    -> ; 
+----+----------------+---------------------+-------------+------------+-------------------------------------------+-------------+ 
| id | name   | created_on   | modified_on | is_deleted | skills         | skills_id | 
+----+----------------+---------------------+-------------+------------+-------------------------------------------+-------------+ 
| 1 | Eugine   | 2017-05-23 11:44:30 | NULL  | N   | zend framework 2,bootstrap,wordpress  | 8,10,12  | 
| 2 | Frinoy Francis | 2017-05-23 16:44:29 | NULL  | N   | html,html5,zend framework 2,php,bootstrap | 1,4,8,10,11 | 
| 3 | Arun   | 2017-05-28 12:56:24 | NULL  | N   | bootstrap         | 8   | 
+----+----------------+---------------------+-------------+------------+-------------------------------------------+-------------+ 
3 rows in set (0.03 sec) 
+0

这是一个好解决方案,但仍然存在问题。技能ID可能是5,6,7,8,我们想要的可能是5和7.在这种情况下,这种解决方案将无法工作。 –

+0

你可以拆分where条件,并加入一个和每个skill_id。 –

1

使用多个最灵活的方式的JOIN; GROUP_CONCAT和逗号分隔列表被认为是反模式,如果拼接没有按照正确的顺序完成(技能集1,2,5被认为与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') 
     ... 
    ; 

这样的技能很容易剪裁,如果,例如,每个技能都有一个技能水平,你需要为滑雪要熟练达到或超过5级。这种灵活性是一个地狱做GROUP_CONCAT

但对于简单的匹配,则可以选择你想要的技能和快做只是对其计数:

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; 

(在更合适的SQL你需要明确指出所有而不是C领域“c。*”,然后在GROUP BY子句中重复它们,只要你用c的主键进行分组,更聪明的RDBMS服务器就不会在意了。

对于每项技能,您都可以在技能上运行单个快速查询以检索其ID并组装上述查询。

或者你可以在一个单一的,大的查询,只要你有技巧的精确匹配做的:既然你想这在PHP

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; 

$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)) { 
    ... 
}