带有排序和缺失字段的GROUP_CONCAT

时间:2015-02-12 21:08:29

标签: php mysql

我有一系列表格,我想以下列格式获取返回的行:

Student ID | Last Name | First Name | Quiz Scores
-------------------------------------------------
xxxxxxx    | Snow      | Jon        | 0,0,0,0,0,0,0,0

有3个相关表格(不能改变任何现有的DB结构):

  • person - 组织中所有人的表格
  • enrollment - 学生和教师注册数据表
  • tilt.quiz - 测验分数表,每行存储一个单独的分数

这个棘手的部分是测验分数。如果学生参加了测验,则仅存在测验分数的行。每个quiz行都有module,1-8。因此,学生可能的测验数据可能是(每个都是一个单独的行):

person_id | module | score
---------------------------
223355    | 1      | 100
223355    | 2      | 95
223355    | 4      | 80
223355    | 7      | 100

我需要以正确的顺序返回测验分数,并使用8个逗号分隔值,无论是否缺少任何或所有测验。

我目前有以下查询:

SELECT
    person.id,
    first_name,
    last_name,
    GROUP_CONCAT(tilt.quiz.score) AS scores
FROM person
    LEFT JOIN enrollment ON person.id = enrollment.person_id
    LEFT JOIN tilt.quiz ON person.id = tilt.quiz.person_id 
WHERE 
    enrollment.course_id = '$num' AND enrollment_status_id = 1
GROUP BY person.id
ORDER BY last_name

问题是:

  1. 它不按模块命令测验
  2. 如果缺少任何测验,则只返回较少的值
  3. 因此,我需要GROUP_CONCAT分数至少包含逗号以查找缺失的测验值,并正确排序。

    我考虑过的一个解决方案是创建一个测验分数的临时表,但我不确定这是最有效的方法还是确切的方法。

    编辑:另一个解决方案是执行查询以单独检查每个测验的存在但这看起来很笨重(总共9个查询而不是1个);我希望有一种更优雅的方式。

    如何实现这一目标?

2 个答案:

答案 0 :(得分:1)

这里有一些关于你的数据结构的假设,但这应该与你所追求的非常接近。请查看GROUP_CONCATCOALESCE的文档。

SELECT `person`.`id`, `person`.`first_name`, `person`.`last_name`,
  GROUP_CONCAT(
    COALESCE(`tilt`.`quiz`.`score`, 'N/A')
    ORDER BY `tilt`.`quiz`.`module_id`
  ) AS `scores`
FROM `person`
CROSS JOIN `modules`
LEFT JOIN `enrollment` USING (`person_id`)
LEFT JOIN `tilt`.`quiz` USING (`person_id`, `module_id`)
WHERE (`enrollment`.`course_id` = '$num')
  AND (`enrollment`.`enrollment_status_id` = 1)
GROUP BY `person`.`id`
ORDER BY `person`.`last_name`

答案 1 :(得分:1)

首先要做的是在分数上使用IFNULL()功能

然后,在GROUP_CONCAT

中使用ORDER BY

这是我建议的查询

SELECT
    person.id,
    first_name,
    last_name,
    GROUP_CONCAT(IFNULL(tilt.quiz.score,0) ORDER BY tilt.quiz.module) AS scores
FROM person
    LEFT JOIN enrollment ON person.id = enrollment.person_id
    LEFT JOIN tilt.quiz ON person.id = tilt.quiz.person_id 
WHERE 
    enrollment.course_id = '$num' AND enrollment_status_id = 1
GROUP BY person.id
ORDER BY last_name