Moodle trainer profiles and their courses sql query - sql

i want to get list of trainers and their courses:
I am using following query
SELECT u.id, u.firstname, u.lastname, u.email, c.fullname
FROM mdl_user u, mdl_role_assignments r, mdl_context cx, mdl_course c
WHERE u.id = r.userid
AND r.contextid = cx.id
AND cx.instanceid = c.id
AND r.roleid =3
AND cx.contextlevel =50
i am only getting single course, need help on this.

Try below one
SELECT u.id, u.firstname, u.lastname, u.email, c.fullname
from mdl_context cx
Left join mdl_course c ON cx.instanceid = c.id
Left join mdl_role_assignments r on r.contextid = cx.id
Left join mdl_user u on u.id = r.userid
WHERE r.roleid =3
AND cx.contextlevel =50

If you are using $DB->get_records_sql() then the first column needs to be unique. So you need to combine the userid and the course id.
$sql = "SELECT CONCAT(c.id, '_', u.id) AS uniqueid,
u.id AS userid,
u.firstname,
u.lastname,
u.email,
c.id AS courseid,
c.fullname,
r.id
FROM {user} u
JOIN {role_assignments} ra ON ra.userid = u.id
JOIN {role} r ON r.archetype = :archetype AND r.id = ra.roleid
JOIN {context} cx ON cx.id = ra.contextid AND cx.contextlevel = :context
JOIN {course} c ON c.id = cx.instanceid";
$params = array('context' => CONTEXT_COURSE, 'archetype' => 'teacher')
$trainers = $DB->get_records_sql($sql, $params);

Related

SQL ad-hoc report of ALL users not completed a course

Hya Gang!
I am very close to figuring out a report I can run ad hoc to find all our users who have not enrolled in a course. I do have a report for enrolled people that have not completed the course, but this search is not finding a given student who is not even enrolled.
The current code is
SELECT u.lastname, u.firstname , u.email , c.fullname,
DATE_FORMAT(FROM_UNIXTIME(cc.timecompleted),'%m/%d/%Y %T') AS 'Completed'
FROM
prefix_role_assignments AS ra
JOIN prefix_context AS context ON context.id = ra.contextid
AND
context.contextlevel = 50 JOIN prefix_course AS c ON c.id = context.instanceid
AND
c.fullname LIKE "SAMPLE_COURSE_NAME"
JOIN prefix_user AS u ON u.id = ra.userid
JOIN prefix_course_completions AS cc ON cc.course = c.id
AND cc.userid = u.id
ORDER BY
cc.timecompleted,
u.lastname,
u.firstname
Any thoughts??
This will list all users not enrolled in a course - could be a big list though.
Replace xxx with the course id
SELECT u.id AS userid, u.firstname, u.lastname, u.email
FROM mdl_user u
WHERE u.deleted = 0
AND u.suspended = 0
AND NOT EXISTS (
SELECT ue.userid
FROM mdl_user_enrolments ue
JOIN mdl_enrol e ON e.id = ue.enrolid AND e.courseid = xxx
WHERE ue.userid = u.id
)
Update... I found using "mdl_" will not work within the moodle framework, but you can replace it with "prefix_" and IT WORKS! Thank you SO much! I never would have thought of this setup.
SELECT u.id AS userid, u.firstname, u.lastname, u.email
FROM prefix_user u
WHERE u.deleted = 0
AND u.suspended = 0
and firstname not like "Guest user"
AND NOT EXISTS (
SELECT ue.userid
FROM prefix_user_enrolments ue
JOIN prefix_enrol e ON e.id = ue.enrolid AND e.courseid = XXX
WHERE ue.userid = u.id
)
ORDER BY
Lastname,
Firstname

Get total count using a window function

Hey all this is the query I have so far:
WITH LIMIT AS
(SELECT
U.userID
,U.username
,U.fname
,U.mname
,U.lname
,U.email
,U.active
,S.sName
,S.sID
,T.[value]
,T.trackingNumberID
,SU.primaryLocation
,row_number() OVER (ORDER BY U.userid) AS RN
,COUNT(*) OVER (ORDER BY U.userid) AS CNT
,UR.roleID
FROM
[---].[dbo].[tblUsers] AS U
LEFT OUTER JOIN [---].[dbo].[tblTrackingNumbers] AS T
ON T.userID = U.userID
LEFT OUTER JOIN [---].[dbo].[tblSU] AS SU
ON U.userID = SU.userID
LEFT OUTER JOIN [---].[dbo].[tblS] AS S
ON SU.sID = S.sID
LEFT OUTER JOIN [---].[dbo].[tblUserRoles] AS UR
ON UR.userID = U.userID
LEFT OUTER JOIN [---].[dbo].[tblRoles] AS R
ON UR.roleID = R.roleID
WHERE
U.active = 1
AND
SU.primaryLocation = 1
AND
SU.active = 1
AND
U.orgID = 1
AND
S.ID = 35
AND U.userID IN (SELECT userID
FROM [---].[dbo].[tblSU] AS SU
INNER JOIN [].[dbo].[tblS] AS S
ON S.sID = SU.sID
WHERE
SU.active = 1
AND
S.sID = 35)
) SELECT * FROM LIMIT WHERE RN Between 0 AND 10000
As you can see by the query above I am trying COUNT(*) OVER (ORDER BY U.userid) AS CNT which gives me the same count as RN.
What I need is the total amount of records this would be bringing back (842 rows).
COUNT(*) OVER (ORDER BY U.userid) AS CNT calulates a "running count" - the count until "that" row. If you want to count all rows in the complete result, use the window function without the order by
COUNT(*) OVER () AS CNT
this might sound cuckoo, but i found with large tables you get better performance if you select the count into a variable and then select your records and just add the variable. something with the count(*) over() causes bad performance when tables get too large.
DECLARE #RecordCount INT
SELECT #RecordCount = COUNT(*)
FROM [---].[dbo].[tblUsers] AS U
LEFT OUTER JOIN [---].[dbo].[tblTrackingNumbers] AS T ON T.userID = U.userID
LEFT OUTER JOIN [---].[dbo].[tblSU] AS SU ON U.userID = SU.userID
LEFT OUTER JOIN [---].[dbo].[tblS] AS S ON SU.sID = S.sID
LEFT OUTER JOIN [---].[dbo].[tblUserRoles] AS UR ON UR.userID = U.userID
LEFT OUTER JOIN [---].[dbo].[tblRoles] AS R ON UR.roleID = R.roleID
WHERE U.active = 1
AND SU.primaryLocation = 1
AND SU.active = 1
AND U.orgID = 1
AND S.ID = 35
AND U.userID IN (SELECT userID
FROM [---].[dbo].[tblSU] AS SU
INNER JOIN [].[dbo].[tblS] AS S ON S.sID = SU.sID
WHERE SU.active = 1
AND S.sID = 35)
SELECT U.userID,
U.username,
U.fname,
U.mname,
U.lname,
U.email,
U.active,
S.sName,
S.sID,
T.[value],
T.trackingNumberID,
SU.primaryLocation,
#RecordCount AS CNT,
UR.roleID
FROM [---].[dbo].[tblUsers] AS U
LEFT OUTER JOIN [---].[dbo].[tblTrackingNumbers] AS T ON T.userID = U.userID
LEFT OUTER JOIN [---].[dbo].[tblSU] AS SU ON U.userID = SU.userID
LEFT OUTER JOIN [---].[dbo].[tblS] AS S ON SU.sID = S.sID
LEFT OUTER JOIN [---].[dbo].[tblUserRoles] AS UR ON UR.userID = U.userID
LEFT OUTER JOIN [---].[dbo].[tblRoles] AS R ON UR.roleID = R.roleID
WHERE U.active = 1
AND SU.primaryLocation = 1
AND SU.active = 1
AND U.orgID = 1
AND S.ID = 35
AND U.userID IN (SELECT userID
FROM [---].[dbo].[tblSU] AS SU
INNER JOIN [].[dbo].[tblS] AS S ON S.sID = SU.sID
WHERE SU.active = 1
AND S.sID = 35)
ORDER BY U.userID
OFFSET 0 ROWS FETCH NEXT 10000 ROWS ONLY

SQL Subquery column equals operation

I am trying to do a SQL query for user with certain permission enabled flag. I know, I can do this:
select u.ID, u.Name,
(select p.Value
from Permissions p
where p.UserID = u.ID AND p.Key = 'CanEdit') as IsPermissionEnabled
from Users u
But it's not exactly what I need, can I do something like this:
select u.ID, u.Name,
((select p.Value
from Permissions p
where p.UserID = u.ID AND p.Key = 'CanEdit') = 'True')
as IsPermissionEnabled
from Users u
It didn't work for me. So, how to change my query to make it work?
Surely you should just join to the table to get p.Value.
Then you can do with it whatever you like:
SELECT
u.ID,
u.Name,
p.Value as IsPermissionEnabled
FROM Users u
LEFT OUTER JOIN Permissions p
ON p.UserID = u.ID
AND p.Key = 'CanEdit';
Try this query
select u.ID, u.Name, case when p.value>0 then 'True' else '' end
as IsPermissionEnabled
from Users u
left join permission p on p.UserID = u.ID and p.key='CanEdit'
In SQL Server, you need an explicit case statement. So, you can write the query as:
select u.ID, u.Name,
(case when (select p.Value
from Permissions p
where p.UserID = u.ID AND p.Key = 'CanEdit'
) = 'True'
then 1 else 0
end) as IsPermissionEnabled
from Users u;
A join ( inner or left) with a Case can be used to return the desired data with IsPermissionEnabled. Assuming intent is to treat IsPermissionEnabled as boolean, the case statement can set it to a bit value of 0 or 1 as below.
select u.USERID , u.Username, IsPermissionEnabled = case p.[Key] when 'CanEdit' then 1 else 0 end from [Permissions] p inner join [User] u on u.USERID = p.userid

Moodle SCORM SQL

What table and field I need to use in SQL to find SCORM activities that reports back score to Moodle and exclude the SCORM objects that are set as non scoring. Basically looking for the SCORM settings field: Require Minimum Score in SQL
The query:
SELECT
CONCAT(u.firstname,' ',u.lastname ) AS 'fullname',
cc.name AS 'Category',
c.fullname AS 'Course',
gi.itemname AS 'Item Name',
ROUND(gg.finalgrade / gg.rawgrademax * 100 ,2) AS 'Percentage',
asgm.status as 'Status',
p.status AS 'Completed',
gi.itemmodule as 'Type',
s.completionscorerequired AS require_minimum_score
FROM prefix_course AS c
JOIN prefix_course_categories AS cc ON cc.id = c.category
JOIN prefix_context AS ctx ON c.id = ctx.instanceid
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id
JOIN prefix_user AS u ON u.id = ra.userid
JOIN prefix_grade_items AS gi ON gi.courseid = c.id
JOIN prefix_scorm AS s ON c.id = s.course
LEFT JOIN prefix_grade_grades AS gg ON gi.id = gg.itemid AND gg.userid = u.id
LEFT JOIN prefix_course_completions AS p ON p.userid = u.id AND p.course = c.id
LEFT JOIN (
SELECT asgm.status as status, c.id as cid, u.id as uid, gi.id as giid
FROM prefix_course AS c
JOIN prefix_course_categories AS cc ON cc.id = c.category
JOIN prefix_context AS ctx ON c.id = ctx.instanceid
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id
JOIN prefix_user AS u ON u.id = ra.userid
JOIN prefix_grade_items AS gi ON gi.courseid = c.id
JOIN prefix_assign AS asg ON gi.iteminstance = asg.id and asg.course = c.id
JOIN prefix_assign_submission AS asgm ON asg.id = asgm.assignment and asgm.userid = u.id
) AS asgm ON c.id = asgm.cid and u.id = asgm.uid and gi.id = asgm.giid
WHERE (gi.itemmodule = 'quiz' OR gi.itemmodule= 'assign' OR gi.itemmodule= 'scorm') AND c.visible=1
SELECT s.id AS scormid, s.name AS scormname,
s.completionscorerequired AS require_minimum_score,
c.id AS courseid, c.fullname AS coursename
FROM mdl_scorm s
JOIN mdl_course c ON c.id = s.course

Find a way to query a list of items that meet ALL of a criteria using SQL

I'm trying to do the following:
select i.FirstName, i.LastName, COUNT(1) from (
select u.Id, uw.WidgetId from [DB].[dbo].[Widgets] w inner join
UserWidgets uw on w.Id = uw.WidgetId inner join
Users u on uw.UserId = u.Id
where uw.WidgetId in ('29017318-FD89-4952-A3A2-8405BD5C5C44',
'BDB7D25C-0794-4965-842D-E6D03A250418',
'CB4553AC-A47B-4AA6-9231-5C59C8F97655')
group by u.Id, uw.WidgetId
) a
inner join [Db2].[dbo].[Identities] i on a.Id = i.IdentityId
group by i.LastName, i.FirstName
order by i.LastName, i.FirstName
What I want is to ensure that the "In" statement requires that the User ONLY has those 3 Id's. No more, no less.
What is the best way to do this?
Try:
select i.FirstName, i.LastName, COUNT(1) from (
select u.Id, uw.WidgetId from [DB].[dbo].[Widgets] w inner join
UserWidgets uw on w.Id = uw.WidgetId
and uw.WidgetId in ('29017318-FD89-4952-A3A2-8405BD5C5C44',
'BDB7D25C-0794-4965-842D-E6D03A250418',
'CB4553AC-A47B-4AA6-9231-5C59C8F97655')
inner join Users u on uw.UserId = u.Id
left join UserWidgets uw2 on uw2.userid = u.id
and uw2.WidgetId not in ('29017318-FD89-4952-A3A2-8405BD5C5C44',
'BDB7D25C-0794-4965-842D-E6D03A250418',
'CB4553AC-A47B-4AA6-9231-5C59C8F97655')
where uw2.widgetid is null
group by u.Id, uw.WidgetId
) a
inner join [Db2].[dbo].[Identities] i on a.Id = i.IdentityId
group by i.LastName, i.FirstName
having count(1) = 3
order by i.LastName, i.FirstName
select i.FirstName, i.LastName, COUNT(1) from (
select u.Id, uw.WidgetId from [DB].[dbo].[Widgets] w inner join
UserWidgets uw on w.Id = uw.WidgetId inner join
Users u on uw.UserId = u.Id
where uw.WidgetId in ('29017318-FD89-4952-A3A2-8405BD5C5C44',
'BDB7D25C-0794-4965-842D-E6D03A250418',
'CB4553AC-A47B-4AA6-9231-5C59C8F97655')
AND count(WidgetId) = 3
group by u.Id, uw.WidgetId
) a
inner join [Db2].[dbo].[Identities] i on a.Id = i.IdentityId
group by i.LastName, i.FirstName
order by i.LastName, i.FirstName
I added the 'AND count(WidgetId) = 3' in to the query...i believe that would work?
This should work:
SELECT i.firstname,
i.lastname,
COUNT(1)
FROM (SELECT u.id,
uw.widgetid
FROM [DB].[dbo].[Widgets] w
INNER JOIN userwidgets uw
ON w.id = uw.widgetid
INNER JOIN users u
ON uw.userid = u.id
WHERE uw.widgetid IN ( '29017318-FD89-4952-A3A2-8405BD5C5C44',
'BDB7D25C-0794-4965-842D-E6D03A250418'
,
'CB4553AC-A47B-4AA6-9231-5C59C8F97655' )
AND NOT EXISTS (SELECT *
FROM [DB].[dbo].[Widgets] w2
INNER JOIN userwidgets uw2
ON w2.id = uw2.id
WHERE w2.id = w.id
AND uw2.widgetid NOT IN (
'29017318-FD89-4952-A3A2-8405BD5C5C44',
'BDB7D25C-0794-4965-842D-E6D03A250418'
,
'CB4553AC-A47B-4AA6-9231-5C59C8F97655' ))
GROUP BY u.id,
uw.widgetid) a
HAVING COUNT(DISTINCT uw.widgetid) = 3
INNER JOIN [Db2].[dbo].[Identities] i
ON a.id = i.identityid
GROUP BY i.lastname,
i.firstname
ORDER BY i.lastname,
i.firstname