使用GROUP_CONCAT

时间:2017-07-31 07:57:30

标签: php mysql codeigniter codeigniter-3

我有candidatescandidate-skillsskills的MySql表。 哪种方法是选择具备所有技能的候选人

我尝试使用以下查询。但这不准确。

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` 
where s.id in ('8','10') 
GROUP BY `t`.`id` 
ORDER BY `t`.`id` desc

我想要的两点是:

  1. 应该显示所有技能(当评论其中的条件时)
  2. 将显示所有技能的记录。 (具有一种技能的记录也显示为我使用数组中的位置)
  3. 我正在使用codeigniter框架。

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

3 个答案:

答案 0 :(得分: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
Codeigniter中的

//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();

答案 1 :(得分:1)

最灵活的方式是使用多个JOIN; GROUP_CONCAT和逗号分隔的列表被视为反模式,如果连接不是以正确的顺序完成,则它可能不起作用(技能组1,2,5被认为与1,5,2不同)。 / p>

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子句中重复它们。更聪明的RDBMS服务器不会只要你按照c的主键进行分组,MySQL 当前无论如何都不关心,但在严格模式下,它会这样做。

对于每项技能,您都会对技能进行单一,快速的查询,以检索其ID并汇总上述查询。

或者,只要您具有完全匹配的技能,您就可以在单个更大的查询中执行此操作:

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;

因为你想在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)) {
    ...
}

答案 2 :(得分:0)

也许这个

        Console.WriteLine("Define Array Size? ");
        int number = Convert.ToInt32(Console.ReadLine());

        Console.WriteLine("Enter numbers:\n");
        int[] arr = new int[number];

        for (int i = 0; i < number; i++)
        {
            arr[i] = Convert.ToInt32(Console.ReadLine());
        }

        for (int i = 0; i < arr.Length; i++ )
        {
            Console.WriteLine("Array Index: "+i + " AND Array Item: " + arr[i].ToString());
        }

        Console.ReadKey();