指定GROUP BY值的首选结果

时间:2013-12-16 16:22:01

标签: mysql sql join group-by

我有以下(简化)查询:

SELECT
u.idnumber AS user_idnumber,
sst_status.value AS scorm_status,
sst_starttime.value AS scorm_starttime,
sst_duration.value AS scorm_duration,
sst_score.value AS scorm_score,
u.id as uid,
s.id as scormid,
ss.id as ssid

FROM {user} u

LEFT JOIN {prog_user_assignment} prua ON prua.userid = u.id
LEFT JOIN {prog} pr ON prua.programid = pr.id
LEFT JOIN {prog_courseset} prcs ON prcs.programid = pr.id
LEFT JOIN {prog_courseset_course} prcsc ON prcsc.coursesetid = prcs.id
LEFT JOIN {course} c ON prcsc.courseid = c.id
LEFT JOIN {scorm} s ON s.id = cm.instance
LEFT JOIN {scorm_scoes} ss ON ss.scorm = s.id

LEFT JOIN {scorm_scoes_track} sst_status
    ON sst_status.userid = u.id
    AND sst_status.scormid = ss.scorm
    AND sst_status.element = 'cmi_core.lesson_status'
    AND sst_status.scoid = ss.id
LEFT JOIN {scorm_scoes_track} sst_starttime
    ON sst_starttime.userid = u.id
    AND sst_starttime.scormid = ss.scorm
    AND sst_starttime.element = 'x.start.time'
    AND sst_starttime.scoid = ss.id
LEFT JOIN {scorm_scoes_track} sst_duration
    ON sst_duration.userid = u.id
    AND sst_duration.scormid = ss.scorm
    AND sst_duration.element = 'cmi.core.total_time'
    AND sst_duration.scoid = ss.id
LEFT JOIN {scorm_scoes_track} sst_score
    ON sst_score.userid = u.id
    AND sst_score.scormid = ss.scorm
    AND sst_score.element = 'cmi.core.score.raw'
    AND sst_score.scoid = ss.id

WHERE u.id IN([SOME_EXAMPLE_IDS_HERE]) AND u.deleted = 0
group by u.idnumber, c.id

现在问题是没有GROUP BY子句,一些记录具有scorm_status,scorm_starttime等的值。但是,这些包含重复项。但是,使用group by语句,仅为这些列返回NULL值。有没有人知道如何解决这个问题?

2 个答案:

答案 0 :(得分:0)

以下是您查询的简化版本:

select u.idnumber AS user_idnumber, sst_status.value AS scorm_status,
       sst_starttime.value AS scorm_starttime, sst_duration.value AS scorm_duration,
       sst_score.value AS scorm_score, u.id as uid, s.id as scormid, ss.id as ssid
. . .
group by u.idnumber, c.id;

您会注意到select中的大多数列都不在group by中。这是使用MySQL的(错误)功能,通常不允许在其他数据库中使用。

MySQL所做的是从结果中的一行中选择 abritrary 值。我们的想法是,如果group的列是常量,这可以很好地工作。但是,在其他情况下,它通常不会像预期的那样起作用。

如果您想要非NULL值,则可以使用max()min()来获取最大值或最小值。

例如:

min(sst_status.value) AS scorm_status

等等。

答案 1 :(得分:0)

使用GROUP_CONCAT和SUBSTRING_INDEX: -

SELECT
u.idnumber AS user_idnumber,
SUBSTRING_INDEX(GROUP_CONCAT(sst_status.value), ',', 1) AS scorm_status,
SUBSTRING_INDEX(GROUP_CONCAT(sst_starttime.value), ',', 1) AS scorm_starttime,
SUBSTRING_INDEX(GROUP_CONCAT(sst_duration.value), ',', 1) AS scorm_duration,
SUBSTRING_INDEX(GROUP_CONCAT(sst_score.value), ',', 1) AS scorm_score,
u.id as uid,
s.id as scormid,
ss.id as ssid

FROM {user} u

LEFT JOIN {prog_user_assignment} prua ON prua.userid = u.id
LEFT JOIN {prog} pr ON prua.programid = pr.id
LEFT JOIN {prog_courseset} prcs ON prcs.programid = pr.id
LEFT JOIN {prog_courseset_course} prcsc ON prcsc.coursesetid = prcs.id
LEFT JOIN {course} c ON prcsc.courseid = c.id
LEFT JOIN {scorm} s ON s.id = cm.instance
LEFT JOIN {scorm_scoes} ss ON ss.scorm = s.id

LEFT JOIN {scorm_scoes_track} sst_status
    ON sst_status.userid = u.id
    AND sst_status.scormid = ss.scorm
    AND sst_status.element = 'cmi_core.lesson_status'
    AND sst_status.scoid = ss.id
LEFT JOIN {scorm_scoes_track} sst_starttime
    ON sst_starttime.userid = u.id
    AND sst_starttime.scormid = ss.scorm
    AND sst_starttime.element = 'x.start.time'
    AND sst_starttime.scoid = ss.id
LEFT JOIN {scorm_scoes_track} sst_duration
    ON sst_duration.userid = u.id
    AND sst_duration.scormid = ss.scorm
    AND sst_duration.element = 'cmi.core.total_time'
    AND sst_duration.scoid = ss.id
LEFT JOIN {scorm_scoes_track} sst_score
    ON sst_score.userid = u.id
    AND sst_score.scormid = ss.scorm
    AND sst_score.element = 'cmi.core.score.raw'
    AND sst_score.scoid = ss.id

WHERE u.id IN([SOME_EXAMPLE_IDS_HERE]) AND u.deleted = 0
group by u.idnumber, c.id

这是获取这些字段的第一个非空值。请注意,这依赖于不包含逗号的字段(但很容易为GROUP_CONCAT指定不同的分隔符)。如果需要,您可以指定GROUP_CONCAT的订单以获取您的首选值。