Moodle SCORM SQL - 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

Related

JOIN two SELECT without UNION

It needs to download the ID, name and surname of those who have registered by the deadline and have an identity card (with the relevant conditions) or passport (with the relevant conditions). ID card and passport are two separate tables.
I have made the SQL queries in UNION format and it works:
select distinct p.id, p.name, p.surname from persons.person p
join persons.documents d on d.person_id = p.id
join persons.id_card idd on d.id_card_id = idd.id
join persons.id_card_to_registration ir on idd.id = ir.id_card
join registrations.registration r on ir.registration_id = r.id
where p.created_at >= '2022-01-01'
and p.created_at <= '2022-03-30'
and p.registration_id = r.id
and ir.status in (0,5)
UNION
select distinct p.id, p.name, p.surname from persons.person p
join persons.documents d on d.person_id = p.id
join persons.passport pass on d.passport_id = pass.id
join persons.passport_country pc on pc.id = pass_country_id
join persons.passport_to_registration pr on pass.id = pr.passport_id
join registrations.registration r on pr.registration_id = r.id
where p.created_at >= '2022-01-01'
and p.created_at <= '2022-03-30'
and p.registration_id = r.id
and pc.zone in (0,1) or (pc.zone is null and pass.safe = true);
I would now like to do this SQL in one query without union and unfortunately it doesn't work for me - I tried to do it like this:
select distinct p.id, p.name, p.surname from persons.person p
join persons.documents d on d.person_id = p.id
left join persons.id_card idd on d.id_card_id = idd.id
left join persons.id_card_to_registration ir on idd.id = ir.id_card
left join persons.passport pass on d.passport_id = pass.id
left join persons.passport_country pc on pc.id = pass_country_id
left join persons.passport_to_registration pr on pass.id = pr.passport_id
join registrations.registration r on ir.registration_id = r.id
where p.created_at >= '2022-01-01'
and p.created_at <= '2022-03-30'
and p.registration_id = r.id
and (ir.status in (0,5) or ir.status is null)
and pc.zone in (0,1) or (pc.zone is null and pass.safe = true)
And it doesn't return any records to me. I would like some advice on what error I have made. And is it possible to create such a query without union?
The SQL in clause may help to filter by each condition. This may be the way to avoid the union clause, please let me know if this works for you:
select distinct p.id, p.name, p.surname from persons.person p
where p.created_at >= '2022-01-01'
and p.created_at <= '2022-03-30'
and ((p.id in
(select distinct p2.id from persons.person p2
d.person_id from persons.documents d on d.person_id = p2.id
join persons.id_card idd on d.id_card_id = idd.id
join persons.id_card_to_registration ir on idd.id = ir.id_card
join registrations.registration r on ir.registration_id = r.id
where p2.registration_id = r.id
and ir.status in (0,5)
)
) or (
(p.id in
(select distinct p3.id from persons.person p3
d.person_id from persons.documents d on d.person_id = p3.id
join persons.passport pass on d.passport_id = pass.id
join persons.passport_country pc on pc.id = pass_country_id
join persons.passport_to_registration pr on pass.id = pr.passport_id
join registrations.registration r on pr.registration_id = r.id
where p3.registration_id = r.id
and pc.zone in (0,1) or (pc.zone is null and pass.safe = true);
)
)
))
I think you'll have better performance if you can convert the query to use EXISTS.
SELECT DISTINCT p.id, p.name, p.surname
FROM persons.person p
WHERE p.created_at >= '2022-01-01'
AND p.created_at <= '2022-03-30'
AND(EXISTS (SELECT *
FROM persons.documents d
JOIN persons.id_card idd
ON d.id_card_id = idd.id
JOIN persons.id_card_to_registration ir
ON idd.id = ir.id_card
JOIN registrations.registration r
ON ir.registration_id = r.id
WHERE p.id = d.person_id
AND p.registration_id = r.id
AND ir.status IN (0,5))
OR EXISTS (SELECT *
FROM persons.documents d
JOIN persons.passport pass
ON d.passport_id = pass.id
JOIN persons.passport_country pc
ON pc.id = pass_country_id
JOIN persons.passport_to_registration pr
ON pass.id = pr.passport_id
JOIN registrations.registration r
ON pr.registration_id = r.id
WHERE p.id = d.person_id
AND p.registration_id = r.id
AND pc.zone IN (0,1)
OR (pc.zone IS NULL
AND pass.safe = TRUE)))

Moodle trainer profiles and their courses sql query

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);

Moodle SQL assignment result/status

I got this SQL code from Moodle SQL scripts How to make the result to include all itemnames whether it has a score or not? prefix_grade_grade table contains the score
prefix_grade_items table has the itemnames
Not sure what vendor, these scripts are used in Moodle LMS open source system
SELECT u.firstname AS 'Name' , u.lastname AS 'Surname', c.fullname AS 'Course', cc.name AS 'Category',
CASE WHEN gi.itemtype = 'Course'
THEN c.fullname + ' Course Total'
ELSE gi.itemname
END AS 'Item Name', ROUND(gg.finalgrade / gg.rawgrademax * 100 ,2) AS Percentage
FROM prefix_course AS c
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_grades AS gg ON gg.userid = u.id
JOIN prefix_grade_items AS gi ON gi.id = gg.itemid
JOIN prefix_course_categories AS cc ON cc.id = c.category
WHERE gi.courseid = c.id AND gi.itemname != 'Attendance' AND gi.itemmodule != 'scorm'
ORDER BY `Name` ASC
You could probably just switch the JOIN around for the grade_grades and grade_items and then do a LEFT JOIN on the grade_grades. I would also move the WHERE condition to the gi JOIN:
JOIN prefix_grade_items AS gi ON gi.courseid = c.id AND gi.itemname != 'Attendance' AND gi.itemmodule != 'scorm'
LEFT JOIN prefix_grade_grades AS gg ON gg.userid = u.id AND gg.itemid = gi.id
Moodle can use Mysql, Postgresql, MariaDB, SQL Server and Oracle - so the queries are generic. There are some functions available for cross database compatible queries here : https://docs.moodle.org/dev/Data_manipulation_API#SQL_compatibility_functions

Subquery in from clause, Invalid Identifier in Where clause

select * from iiasa_inventory.inv_device d
join iiasa_inventory.inv_type ty on d.type_id = ty.id
join iiasa_inventory.inv_category c on ty.category_id = c.id
join iiasa_inventory.inv_device_2_barcode b on b.device_id = d.id
join iiasa_inventory.inv_barcodes bc on b.barcode_id = bc.id
join iiasa_inventory.inv_status s on d.status = s.id
join iiasa_inventory.inv_brand br on ty.brand_id = br.id
left join iiasa_inventory.inv_supplier su on su.id = d.supplier_id
left join iiasa_inventory.inv_supplier sup on sup.id = d.maintenance_with
left join (select distinct device_id from
iiasa_inventory.inv_device_2_persons_cc) dp
on dp.device_id = d.id
where dp.active = 1
I am trying to select my data but the where-clause says that "dp.active" is an INVALID Identifier. This is probably because the table dp is in the subquery. I have tried to give it an alias name and some other things I found while browsing stackoverflow, but I cant seem to find a solution. Any idea?
This is Oracle PL/SQL.
Put the check for active = 1 in the subquery as shown below.
select * from iiasa_inventory.inv_device d
join iiasa_inventory.inv_type ty on d.type_id = ty.id
join iiasa_inventory.inv_category c on ty.category_id = c.id
join iiasa_inventory.inv_device_2_barcode b on b.device_id = d.id
join iiasa_inventory.inv_barcodes bc on b.barcode_id = bc.id
join iiasa_inventory.inv_status s on d.status = s.id
join iiasa_inventory.inv_brand br on ty.brand_id = br.id
left join iiasa_inventory.inv_supplier su on su.id = d.supplier_id
left join iiasa_inventory.inv_supplier sup on sup.id = d.maintenance_with
left join (select distinct device_id from iiasa_inventory.inv_device_2_persons_cc where active = 1) dp on dp.device_id = d.id
That is because you are not selecting active column in dp.
select * from iiasa_inventory.inv_device d
join iiasa_inventory.inv_type ty on d.type_id = ty.id
join iiasa_inventory.inv_category c on ty.category_id = c.id
join iiasa_inventory.inv_device_2_barcode b on b.device_id = d.id
join iiasa_inventory.inv_barcodes bc on b.barcode_id = bc.id
join iiasa_inventory.inv_status s on d.status = s.id
join iiasa_inventory.inv_brand br on ty.brand_id = br.id
left join iiasa_inventory.inv_supplier su on su.id = d.supplier_id
left join iiasa_inventory.inv_supplier sup on sup.id = d.maintenance_with
left join (select distinct device_id,active from iiasa_inventory.inv_device_2_persons_cc) dp on dp.device_id = d.id
where dp.active = 1
OR you can just filter from the subquery itself. Like:
left join (select distinct device_id
from iiasa_inventory.inv_device_2_persons_cc
where active=1) dp on dp.device_id = d.id

Multiple left outer join with same table allowed?

I tried to convert below SQL in a more optimized way but it is giving error "Operand type clash: uniqueidentifier is incompatible with int". Could you please help me out
select E.EHOId, E.ReferenceId 'ReferenceNo',
(select Comp_Name from FoodAlertCRM.dbo.vCompanyPE where Comp_CompanyId = E.GroupId) 'Group',
(select Comp_Name from FoodAlertCRM.dbo.vCompanyPE where Comp_CompanyId = E.SiteId) 'Site',
E.VisitDate as 'VisitDate',
(select Name from EHO_Dropdowns where ID = E.FollowupAction) 'FollowupAction',
(select Name from EHO_LocalAuthority where ID = E.LocalAuthority) 'LocalAuthority',
(select Name from EHO_Dropdowns where ID = E.[Status]) 'Status',
(select Name from EHO_Dropdowns where ID = E.Position) 'Position',
(select Name from EHO_Dropdowns where ID = E.Structural) 'Structural',
(select Name from EHO_Dropdowns where ID = E.ConfidenceinManagement) 'ConfideninManagement',
(select Name from EHO_Dropdowns where ID = E.HygieneandSafety) 'HygieneandSafety',
(select Name from EHO_Dropdowns where ID = E.RoutineInspection) 'RoutineInspection',
(select Name from EHO_Dropdowns where ID = E.OutcomeofVisit) 'OutcomeofVisit',
e.OfficerName,e.FoodHygieneRating,e.ManageronDuty,e.Comments,
CASE E.AnnouncedVisit
When 0 Then 'No'
When 1 Then 'Yes'
Else ''
ENd as 'AnnouncedVisit',
(select u.Username from FoodAlertCRM.dbo.CDB_User u where u.UserId = e.CreatedBy ) 'CreatedBy',
(select COUNT(EHOId) from EHO_Attachments where EHOId = E.EHOId) as 'AttachmentCount'
from EHO_Log E
where E.IsActive = 1 AND e.IsDeleted = 0
Order by E.VisitDate desc
You see Above has alot of inner queries and performance will be very bad if there are thousand records. so i tried to get rid of inner queries.
select E.EHOId, E.ReferenceId 'ReferenceNo',
(select Comp_Name from FoodAlertCRM.dbo.vCompanyPE where Comp_CompanyId = E.GroupId) 'Group',
(select Comp_Name from FoodAlertCRM.dbo.vCompanyPE where Comp_CompanyId = E.SiteId) 'Site',
E.VisitDate as 'VisitDate',
F.Name 'FollowupAction',L.Name 'LocalAuthority', St.Name 'Status',
P.Name 'Position', S.Name 'Structural', C.Name 'ConfideninManagement',
H.Name 'HygieneandSafety', R.Name 'RoutineInspection', O.Name 'OutcomeofVisit',
e.OfficerName,e.FoodHygieneRating,e.ManageronDuty,e.Comments,
CASE E.AnnouncedVisit
When 0 Then 'No'
When 1 Then 'Yes'
Else ''
ENd as 'AnnouncedVisit',
(select u.Username from FoodAlertCRM.dbo.CDB_User u where u.UserId = e.CreatedBy ) 'CreatedBy',
(select COUNT(EHOId) from EHO_Attachments where EHOId = E.EHOId) as 'AttachmentCount'
from EHO_Log E
Left Outer Join EHO_Dropdowns St ON St.Id = E.[Status]
Left Outer Join EHO_Dropdowns F ON F.Id = E.FollowupAction
Left Outer Join EHO_Dropdowns L ON L.Id = E.LocalAuthority
Left Outer Join EHO_Dropdowns P ON P.Id = E.Position
Left Outer Join EHO_Dropdowns S ON S.Id = E.Structural
Left Outer Join EHO_Dropdowns C ON C.Id = E.ConfidenceinManagement
Left Outer Join EHO_Dropdowns H ON H.Id = E.HygieneandSafety
Left Outer Join EHO_Dropdowns R ON R.Id = E.RoutineInspection
Left Outer Join EHO_Dropdowns O ON O.Id = E.OutcomeofVisit
where E.IsActive = 1 AND e.IsDeleted = 0
Order by E.VisitDate desc
Above code failed and i thought multiple Left outer joins are not allowed and i converted it into below query but still it fails
select E.EHOId, E.ReferenceId 'ReferenceNo',
(select Comp_Name from FoodAlertCRM.dbo.vCompanyPE where Comp_CompanyId = E.GroupId) 'Group',
(select Comp_Name from FoodAlertCRM.dbo.vCompanyPE where Comp_CompanyId = E.SiteId) 'Site',
E.VisitDate as 'VisitDate',
D.Name 'FollowupAction',D.Name 'LocalAuthority', D.Name 'Status',
D.Name 'Position', D.Name 'Structural', D.Name 'ConfideninManagement',
D.Name 'HygieneandSafety', D.Name 'RoutineInspection', D.Name 'OutcomeofVisit',
e.OfficerName,e.FoodHygieneRating,e.ManageronDuty,e.Comments,
CASE E.AnnouncedVisit
When 0 Then 'No'
When 1 Then 'Yes'
Else ''
ENd as 'AnnouncedVisit',
(select u.Username from FoodAlertCRM.dbo.CDB_User u where u.UserId = e.CreatedBy ) 'CreatedBy',
(select COUNT(EHOId) from EHO_Attachments where EHOId = E.EHOId) as 'AttachmentCount'
from EHO_Log E
Left Outer Join EHO_Dropdowns D ON D.Id = E.[Status] AND D.Id = E.FollowupAction
AND D.Id = E.LocalAuthority AND D.Id = E.Position AND D.Id = E.Structural
AND D.Id = E.ConfidenceinManagement AND D.Id = E.HygieneandSafety
AND D.Id = E.RoutineInspection AND D.Id = E.OutcomeofVisit
where E.IsActive = 1 AND e.IsDeleted = 0
Order by E.VisitDate desc
Any idea guys? both of the new queries return error "Operand type clash: uniqueidentifier is incompatible with int".
I think the cause may be this line:
Left Outer Join EHO_Dropdowns L ON L.Id = E.LocalAuthority
Try changing it to be:
Left Outer Join EHO_LocalAuthority L ON L.Id = E.LocalAuthority
Mulitple Outer Join on Same Table :
Solution:
please use nvl on outer join fields
NVL(EHO_Dropdowns(+),EHO_LocalAuthority(+)) = E.LocalAuthority