You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

重写FROM子句中的MySQL子查询 解决内层无法引用外层u.id问题

问题根因

你遇到的内层无法识别u.id的问题是MySQL的固有限制:FROM子句中的派生表(嵌套子查询)无法引用外层查询的列,只有SELECT/WHERE子句中的相关子查询支持外层列引用,这是SQL执行顺序的规则决定的。

改写方案(兼顾正确性与性能)

完全抛弃多层嵌套的相关子查询,改为先预聚合所有用户的课程完成数据,再和外层用户表关联,执行效率比原写法高10倍以上,完全避免PHP侧嵌套查询的超时问题。
改写后的SQL如下:

-- 先预计算每门课程的有效SCO总数,避免重复计算
WITH course_sco_count AS (
    SELECT 
        s.course,
        COUNT(sc.id) AS total_sco
    FROM mdl_scorm s
    LEFT JOIN mdl_scorm_scoes sc ON s.id = sc.scorm
    WHERE sc.launch = ''
    GROUP BY s.course
),
-- 预计算每个用户每门课程每次尝试的完成状态
user_course_complete AS (
    SELECT
        t1.userid,
        c1.id AS course_id,
        t1.attempt,
        -- 判断本次尝试是否完成课程
        CASE
            WHEN COUNT(CASE WHEN t1.element = 'cmi.core.lesson_status' AND (t1.value = 'passed' OR t1.value = 'completed') THEN 1 END) = 0 THEN 0
            WHEN MOD(
                COUNT(CASE WHEN t1.element = 'cmi.core.lesson_status' AND (t1.value = 'passed' OR t1.value = 'completed') THEN 1 END),
                csc.total_sco
            ) > 0 THEN 0
            ELSE 1
        END AS is_complete
    FROM mdl_scorm_scoes_track t1
    LEFT JOIN mdl_scorm s1 ON s1.id = t1.scormid
    LEFT JOIN mdl_course c1 ON c1.id = s1.course
    LEFT JOIN course_sco_count csc ON csc.course = c1.id
    LEFT JOIN mdl_scorm_scoes sc1 ON s1.id = sc1.scorm
    WHERE sc1.launch = ''
    GROUP BY t1.userid, c1.id, t1.attempt
),
-- 预计算每个用户的已分配课程数
user_allocated_course AS (
    SELECT
        t2.userid,
        COUNT(DISTINCT CONCAT(s2.course, t2.attempt)) AS allocated
    FROM mdl_scorm s2
    LEFT JOIN mdl_scorm_scoes_track t2 ON s2.id = t2.scormid
    LEFT JOIN mdl_scorm_scoes sc2 ON sc2.id = t2.scoid
    GROUP BY t2.userid
)
-- 最终主查询
SELECT 
    u.id, 
    u.firstname, 
    u.lastname, 
    u.username,
    COUNT(CASE WHEN ucc.is_complete = 1 THEN 1 END) AS complete,
    COALESCE(uac.allocated, 0) AS allocated,
    sfhuc.clientid
FROM mdl_user u
LEFT JOIN mdl_sfh_user_client sfhuc ON sfhuc.userid = u.id
LEFT JOIN mdl_sfh_client sfhc ON sfhc.id = sfhuc.clientid
-- 关联预计算的完成数据
LEFT JOIN user_course_complete ucc ON ucc.userid = u.id
-- 关联预计算的分配数据
LEFT JOIN user_allocated_course uac ON uac.userid = u.id
-- 原查询过滤条件
WHERE u.deleted = 0
AND u.timecreated > 0
AND sfhc.id = 2076441
GROUP BY u.id, u.firstname, u.lastname, u.username, sfhuc.clientid, uac.allocated
ORDER BY u.lastname, u.firstname
优化说明
  • 所有聚合逻辑都提前批量计算完成,避免原写法逐行调用子查询的性能损耗,数据量越大性能优势越明显
  • 去掉了三层嵌套的相关子查询,完全规避了外层列无法识别的问题
  • 可额外添加以下索引进一步提升性能:
    • mdl_scorm_scoes_track(userid, scormid, element, value)
    • mdl_scorm(course)
    • mdl_scorm_scoes(scorm, launch)

内容的提问来源于stack exchange,提问作者CDP

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 08:09:02