SQL如何按首字符筛选去重 获取不带分节的主课程记录
Moodle主课程记录查询实现方案
需求说明
提取课程数据时,课程下设有A、B等多个分节,仅需查询不带分节标识的主课程记录。参考示例列表规则,主课程排在列表末尾,分节课程排列在主课程上方,本次目标获取的主课程记录值为1 / 4 / C-501 / Matematicas Aplicadas I / C-501。
现有方案问题
此前尝试DISTINCT LEFT(mc.shortname,5)、substr(mc.shortname,1,5)写法未生效,核心原因是这类写法仅对shortname字段做截断展示,没有做行级过滤;就算修正DISTINC的拼写错误,也无法达到过滤效果——不同分节课程的ID、学分、全名等字段值均不相同,最终还是会返回所有分节课程的完整信息。
当前使用的基础查询语句如下:
SELECT mc.id, (SELECT mcd.value from mdl_customfield_data mcd WHERE mcd.fieldid =5 AND mc.id = mcd.instanceid) tipo_curso, mcd.value creditos, mc.fullname, mc.shortname FROM mdl_course mc,mdl_customfield_data mcd WHERE mc.category = 10 AND mc.id = mcd.instanceid AND mcd.fieldid = 1;
参考示例截图:
可直接使用的正确查询语句
主课程与分节课程的核心区分规则:分节课程的shortname会在主课程编码后追加A/B等分节标识,主课程的shortname无额外后缀,同分类下不存在其他课程的shortname是它的前缀且长度更短。通过NOT EXISTS做行级过滤即可精准拿到主课程记录,不需要硬编码编码截断长度,适配不同长度的课程编码规则:
SELECT mc.id, (SELECT mcd.value from mdl_customfield_data mcd WHERE mcd.fieldid =5 AND mc.id = mcd.instanceid) tipo_curso, mcd.value creditos, mc.fullname, mc.shortname FROM mdl_course mc INNER JOIN mdl_customfield_data mcd ON mc.id = mcd.instanceid AND mcd.fieldid = 1 WHERE mc.category = 10 AND NOT EXISTS ( SELECT 1 FROM mdl_course mc2 WHERE mc2.category = 10 AND mc.shortname LIKE CONCAT(mc2.shortname, '%') AND LENGTH(mc2.shortname) < LENGTH(mc.shortname) )
逻辑说明
- 将原语句的隐式逗号关联改为显式
INNER JOIN,关联逻辑更清晰,避免漏写关联条件出现笛卡尔积 NOT EXISTS子句逐行校验:如果同分类下存在另一条课程记录,它的shortname是当前课程shortname的前缀且长度更短,说明当前记录是分节课程,直接排除;最终保留的就是无分节后缀的主课程- 不依赖固定的编码长度,就算后续课程编码规则调整,语句也能正常生效
内容的提问来源于stack exchange,提问作者user8282183292
相关产品推荐
相关产品推荐

