phpcodeigniterjoindelimitedfind-in-set

Replace comma-separated ids with corresponding names in a CodeIgniter SELECT query result set


I have three tables like below:

test_case

id   project_id     requirement_id
 1      5                11,12
 2      4                12,13
 3      5                10,12

task_categories (refenced with test_case table with requirement_id)

 id      name
 10     ten   
 11     eleven   
 12     twelve
 13     thirtien     

projects (refenced with test_case table with project_id)

id    name
 4     P1        
 5     P2      

I want to make a query with a WHERE condition by passing parameter like project_id=5 and get output like below:

id   project_name     requirement_name
 1      P2             eleven,twelve
 3      P2              ten,twelve

I tried the following code in my model:

public function display($project_id) {
    $sql = "
        SELECT i.id as id, i.project_id as project_id, requirement_id, GROUP_CONCAT(c.name SEPARATOR '\n <br>*') as req_name, p.id as projects_id FROM test_case i, task_categories c, projects p 
        WHERE FIND_IN_SET(c.id, i.requirement_id) AND i.project_id = $project_id
        GROUP BY i.id";

    $query = $this->db->query($sql);
    return $query->result();
}

Solution

  • Your current approach has a problem because it results in selecting non aggregate columns while using GROUP BY. Here is a query which should work:

    SELECT t1.id,
           COALESCE(t2.project_name, 'NA') AS project_name,
           t1.req_name
    FROM
    (
        SELECT t.id,
               t.project_id,
               GROUP_CONCAT(tc.name SEPARATOR '\n <br>*') AS req_name
        FROM test_case t
        INNER JOIN task_categories tc
            ON FIND_IN_SET(tc.id, t.requirement_id) > 0
        GROUP BY t.id, t.project_id
    ) t1
    LEFT JOIN projects t2
        ON t1.project_id = t2.id
    

    In the above query, I join test_case and task_categories together in a subquery to obtain all combinations of id, project_id, and their requirements list. Then I use another LEFT JOIN to bring in the project name from the projects table.