小编典典

对Moodle课程注册的SQL查询

sql

我一直在寻找适当的SQL查询,以检索 Moodle 上所有已注册某门课程的学生,或某位学生已注册的所有课程。

我已经找到了一些来自Internet的解决方案,其中大多数建议加入这些表:
上下文,role_assignments,课程,用户,角色

但是当我查看数据库时,发现有一个名为的表user_enrolments,在我看来,我可以通过 联接 以下表来获得结果:
user_enrolments,user,当然,enroll

例如,

SELECT u.id, c.id
FROM mdl_user u
INNER JOIN mdl_user_enrolments ue ON ue.userid = u.id
INNER JOIN mdl_enrol e ON e.id = ue.enrolid
INNER JOIN mdl_course c ON e.courseid = c.id

SELECT u.id, c.id
FROM mdl_user u
INNER JOIN mdl_role_assignments ra ON ra.userid = u.id
INNER JOIN mdl_context ct ON ct.id = ra.contextid
INNER JOIN mdl_course c ON c.id = ct.instanceid
INNER JOIN mdl_role r ON r.id = ra.roleid
WHERE r.id = 5

(其中5是该角色的IDstudent

这两个查询为我提供了一组 相同 的结果。(仅在少量数据上进行了测试)

因此,我想问一下这两种方法之间的区别是什么?
感谢您的任何提前帮助。


阅读 172

收藏
2021-03-17

共1个答案

小编典典

第一个查询为您提供了已注册课程的用户列表,无论他们已分配给他们什么角色(有可能已注册课程而根本没有分配任何角色)。

第二个查询显示在课程级别为其分配了角色5的所有用户。可以(尽管不寻常)在课程级别分配角色,而无需实际注册课程本身。

但是,这两个查询都是有缺陷的。

如果用户通过一种以上的注册方法注册了课程,则第一个查询可能返回重复的结果(不常见,但可能)。它还没有考虑以下因素:

  • 该注册插件可能在网站级别被禁用
  • 可以在课程级别禁用注册插件(检查“ e.status = 0”以仅找到活动的注册插件)
  • 该注册可能有时间限制-用户的注册可能已过期(检查“ ue.timeend = 0或ue.timeend> NOW()”以仅找到未过期的注册)

第二个查询假定学生角色为id
5(并且基于该学生角色,没有其他正在使用的角色)。我通常会使用一个额外的查询来检查表’mdl_role’中’student’角色的ID,然后使用该值,或者将最后几行更改为以下内容:

加入mdl_role r ON r.id = ra.roleid和r.shortname =’student’。

第二个查询也无法检查’contextlevel’-可能有多个具有相同实例ID的上下文(因为可能具有课程ID 5,课程类别ID 5,用户ID
5等)-因此您需要检查找到的上下文是“课程”上下文(contextlevel = 50)。

查询既不会检查已暂停的用户,也不会检查已删除的用户(尽管对于已删除的用户,应该在删除它们时自动将它们从所有课程中取消注册)。

一个完整的解决方案(在大多数情况下可能过于复杂)会将两个查询组合在一起以检查用户是否已注册并分配了学生角色而不是被暂停:

SELECT DISTINCT u.id AS userid, c.id AS courseid
FROM mdl_user u
JOIN mdl_user_enrolments ue ON ue.userid = u.id
JOIN mdl_enrol e ON e.id = ue.enrolid
JOIN mdl_role_assignments ra ON ra.userid = u.id
JOIN mdl_context ct ON ct.id = ra.contextid AND ct.contextlevel = 50
JOIN mdl_course c ON c.id = ct.instanceid AND e.courseid = c.id
JOIN mdl_role r ON r.id = ra.roleid AND r.shortname = 'student'
WHERE e.status = 0 AND u.suspended = 0 AND u.deleted = 0
  AND (ue.timeend = 0 OR ue.timeend > UNIX_TIMESTAMP(NOW())) AND ue.status = 0

(请注意,我没有对查询进行广泛的检查-它可以运行,但是您需要仔细对照实际的注册进行交叉引用,以检查我没有错过任何内容)。

2021-03-17