https://docs.moodle.org/39/en/api.php?action=feedcontributions&user=Fox&feedformat=atomMoodleDocs - User contributions [en]2024-03-29T06:07:00ZUser contributionsMediaWiki 1.39.6https://docs.moodle.org/39/en/index.php?title=Upgrade_overview&diff=137285Upgrade overview2020-06-17T07:46:00Z<p>Fox: Moodle 3.5 needed to upgrade to Moodle 3.9</p>
<hr />
<div>{{Installing Moodle}} <br />
<span class="small-info-right">''Moodle {{Version}} available now!''</span><br />
Start enjoying the cool features of the latest and greatest version of Moodle in four easy steps...<br />
__NOTOC__<br />
==Step 1: Make sure that your server can run Moodle {{Version}}==<br />
<br />
(Note: You need to upgrade to Moodle 3.5 or later before upgrading to {{Version}}.)<br />
<br />
Go to ''Site administration > Server > Environment''<br />
<br />
Status OK for everything? Great! Go to step 2...<br />
<br />
Any problems? You probably need to upgrade your server software (such as PHP) to a more recent version.<br />
<br />
==Step 2: Be prepared!==<br />
<br />
As usual with any large upgrade, you should always be prepared to "roll back" if there's an issue with your data or some custom code you've added.<br />
<br />
; A test install: We highly advise you make a copy of your production site to practice the upgrade on first. That way, if you run into any problems that need fixing you won't affect your main site.<br />
<br />
; Always make backups: When upgrading your production instance, make sure you have copies of everything, just in case. Full instructions are here: [[Site backup]].<br />
<br />
==Step 3: Replace your Moodle code==<br />
<br />
At this point you can replace the Moodle code on your server with the version you downloaded.<br />
<br />
; Check plugins: Any plugins you have installed will also to be replaced with a version for your new Moodle version. If there is not yet an updated version of the plugin available, it will need to be uninstalled before upgrading your site.<br />
<br />
==Step 4: Perform the upgrade!==<br />
<br />
Trigger the upgrade by [[Upgrading#Finishing_the_upgrade|visiting the admin page]].<br />
<br />
If you have a large site this may take hours, so we recommend [[Administration_via_command_line#Upgrading|upgrading via command line]].<br />
<br />
==How did you go?==<br />
<br />
; Yes - it worked!: Great! Repeat the process for Moodle {{Version}}, and please post in the [http://moodle.org/mod/forum/view.php?id=28 Installation help forum] and share your success with the Moodle community!<br />
; No - I had an error: Don’t worry, help is at hand. Post in the [http://moodle.org/mod/forum/view.php?id=28 Installation help forum] where our experts are waiting to explain any errors you obtain.<br />
<br />
==See also==<br />
<br />
* [[Upgrading]] for full details of the process<br />
* [[Upgrading FAQ]]<br />
<br />
[[Category:Installation]]<br />
<br />
[[de:Aktualisierung in Kürze]]<br />
[[es:Visión general de actualización]]<br />
[[ja:アップグレード概要]]<br />
[[fr:Aperçu des mises à jour]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=Upgrading&diff=137284Upgrading2020-06-17T07:43:09Z<p>Fox: Updating needed version (other improvments/review needed)</p>
<hr />
<div>{{Installing Moodle}} <br />
''This page explains in detail how to upgrade Moodle. For a summary of the process, see [[Upgrade overview]].''<br />
<br />
==Check the requirements==<br />
<br />
Before upgrading, check that your server meets all requirements for {{Version}} in ''Site administration > Server > [[Environment]]''. <br />
<br />
See the [{{Release notes}} release notes] in the dev docs for both [{{Release notes}}#Server_requirements server] and [{{Release notes}}#Client_requirements client] software requirements.<br />
<br />
Notes:<br />
<br />
* You can only upgrade to Moodle {{Version}} from Moodle 3.5 or later. If upgrading from earlier versions, you must [https://docs.moodle.org/35/en/Upgrading_to_Moodle_3.5 upgrade to 3.5] as a first step.<br />
<br />
==Before upgrading==<br />
<br />
'''We advise that you test the upgrade first on a COPY of your production site, to make sure it works as you expect.'''<br />
<br />
Consider setting the [[Upgrade key|upgrade key]] for your site.<br />
<br />
== Backup important data ==<br />
<br />
There are three areas that should be backed up before any upgrade:<br />
#Moodle software (For example, everything in server/htdocs/moodle)<br />
#Moodle uploaded files (For example, server/moodledata)<br />
#Moodle database (For example, your Postgres or MySQL database dump)<br />
<br />
See [[Site backup]] for more specific information.<br />
<br />
== Check for plugin updates ==<br />
<br />
If you have [[Automatic updates deployment]] enabled, you will be able to update installed plugins automatically during the upgrade. Just make sure you check for available updates (via the button for it) at the Plugins check screen.<br />
<br />
If you are updating plugins manually, it is a good moment now to check in the [http://moodle.org/plugins Moodle Plugins directory] whether there is a {{Version}} version available for any plugins (including themes) that you have previously installed on your site. If so, download the plugin package. In the next step, you will copy it to the appropriate location in your Moodle code (see [[Installing plugins]]).<br />
<br />
The upgrade of the plugin will then happen as part of the Moodle upgrade process.<br />
<br />
If an out-of-date plugin causes your upgrade to fail, you can usually delete the plugin code rather than uninstalling it from within Moodle so that the data associated with it is not deleted.<br />
<br />
==Put your site into maintenance mode==<br />
Before you begin upgrading your site, you should put it into [[Maintenance_mode | maintenance mode]] to stop any non-admin users from logging in. Then you should wait for any currently running cron processes to complete before proceeding.<br />
<br />
== Install the new Moodle software ==<br />
You can fetch the current version of the software at<br />
<br />
wget http://sourceforge.net/projects/moodle/files/Moodle/stable39/moodle-latest-39.tgz<br />
<br />
=== Standard install package ===<br />
<br />
# Move your old Moodle software program files to another location. ''Do NOT copy new files over the old files.''<br />
# Unzip or unpack the upgrade file so that all the new Moodle software program files are in the location the old files used to be in on the server. Moodle will adjust SQL and moodledata if it needs to in the upgrade.<br />
# Copy your old [[Configuration file|config.php file]] back to the new Moodle directory. <br />
# As mentioned above, if you had installed any plugins on your site you should add them to the new code tree (Moodle directory structure) now. It is important to check that you get the correct version for your new version of Moodle. Be particularly careful that you do not overwrite any code in the new version of Moodle and that you place the plugin folders in the correct directory (the same directory that they are in in the current installation.)<br />
# Your moodledata folder should be located separately to your Moodle code folder and, as such, should not need anything done to it. Moodle 3.0 will throw a warning if it is located in a web accessible folder and the moodledata should never be located in the Moodle code folder. If you are moving your installation to a new server or new location on your server, then you will need to follow the [[Migration]] documents.<br />
<br />
====Linux====<br />
mv moodle moodle.backup<br />
tar xvzf moodle-latest-{{Version}}.tgz<br />
<br />
Next, copy across your config.php, any custom plugins, and your .htaccess file if you created one ('''check that custom plugins are the correct version for your new Moodle first'''):<br />
<br />
cp moodle.backup/config.php moodle<br />
cp -pr moodle.backup/theme/mytheme moodle/theme/mytheme<br />
cp -pr moodle.backup/mod/mymod moodle/mod/mymod<br />
<br />
Don't forget to make moodle/config.php (and the rest of the source code) readable by your www server. For maximum security the files should not be writeable by your server. This is especially important on a 'production' server open to the public internet. <br />
<br />
chown -R root:root moodle (Linux debian - or even create a user especially for moodle. '''Don't''' use the web server user, e.g. www-data)<br />
chmod -R 755 moodle<br />
<br />
If you use cron, take care that cron.php is executeable and uses the correct php command: <br />
chmod 740 admin/cli/cron.php (some configurations need chmod 750 or chmod 755)<br />
copy the first line from cron.php (if it looks like '#!/usr/local/bin/php' or '#!/usr/local/bin/php5.3', no need to copy '<?php') <br />
if necessary. However, for a simple upgrade, there should be no need to change anything with cron.<br />
<br />
=== Using Git ===<br />
<br />
You can use Git for updating or upgrading your Moodle. See [[Git for Administrators]] for details.<br />
<br />
===Command line upgrade===<br />
<br />
On Linux servers, Moodle {{Version}} supports running the [[CLI|upgrade from the command line]], rather than through a web browser. This is likely to be more reliable, particularly for large sites.<br />
<br />
== Finishing the upgrade ==<br />
<br />
The last step is to trigger the upgrade processes within Moodle. <br />
<br />
If you put your site into Maintenance mode earlier; take it out now!<br />
<br />
To do this just go to ''Site administration > Notifications''.<br />
<br />
Moodle will automatically detect the new version and perform all the SQL database or file system upgrades that are necessary. If there is anything it can't do itself (very rare) then you will see messages telling you what you need to do.<br />
<br />
Assuming all goes well (no error messages) then you can start using your new version of Moodle and enjoy the new features!<br />
<br />
Note: If you are running multiple servers then you should purge all caches manually (via ''Site administration > Development > Purge all caches'') after completing the upgrade on all servers.<br />
<br />
===Fatal error: Maximum execution time of 30 seconds exceeded...===<br />
<br />
If your server uses a main language other than English, you may encounter a 'Fatal error: Maximum execution time of 30 seconds exceeded' when you try to upgrade it. You can increase max_execution_time = 160 on php.ini to allow the scripts enough time to process the language update. Otherwise, you can switch to English as the default language before doing the upgrade and back to your original language after a successful upgrade. See the forum discussion at https://moodle.org/mod/forum/discuss.php?d=119598.<br />
<br />
==After upgrading==<br />
<br />
==Possible issues that may affect you in Moodle {{Version}}==<br />
<br />
===Course overview improvements===<br />
<br />
New course overview settings enable an admin to <br />
<br />
* reduce the currently available layouts (Card, List and Summary)<br />
* specify which filter options are available, including providing a custom filter which uses course custom field values<br />
<br />
===Course request changes===<br />
<br />
The capabilities moodle/course:request and moodle/site:approvecourse may now be applied in the category context.<br />
<br />
===Removed functionality===<br />
<br />
* The Community finder block and course-sharing functionality have been removed as part of the preparations for the new MoodleNet open social media platform.<br />
* The People block has been removed because there is a Participants link in the navigation drawer (Boost theme) and in the navigation block (Classic theme).<br />
<br />
''Please add more items here...''<br />
<br />
See also the list of [https://tracker.moodle.org/issues/?jql=project%20%3D%20mdl%20AND%20resolution%20%3D%20fixed%20AND%20fixVersion%20in%20(%223.9%22)%20AND%20labels%20%3D%20upgrade_notes upgrade_notes-labelled issues] and [https://tracker.moodle.org/issues/?jql=project%20%3D%20mdl%20AND%20resolution%20%3D%20fixed%20AND%20fixVersion%20in%20(%223.9%22)%20AND%20labels%20%3D%20ui_change%20 ui_change-labelled issues]. <br />
<br />
===New capabilities in Moodle {{Version}}===<br />
<br />
'''Forum'''<br />
<br />
* forumreport/summary:view<br />
* forumreport/summary:viewall<br />
* mod/forum:exportforum<br />
* mod/forum:grade<br />
<br />
'''H5P'''<br />
<br />
* atto/h5p:addembed<br />
* moodle/h5p:deploy<br />
* moodle/h5p:setdisplayoptions<br />
* moodle/h5p:updatelibraries<br />
<br />
=== Moodle 3.5, 3.6, 3.7 and 3.8 improvements ===<br />
<br />
Depending on which version you are upgrading from, please see the section 'Possible issues that may affect you' in the documentation<br />
<br />
* [https://docs.moodle.org/35/en/Upgrading Upgrading to Moodle 3.5]<br />
* [https://docs.moodle.org/36/en/Upgrading Upgrading to Moodle 3.6]<br />
* [https://docs.moodle.org/37/en/Upgrading Upgrading to Moodle 3.7]<br />
* [https://docs.moodle.org/38/en/Upgrading Upgrading to Moodle 3.8]<br />
<br />
==Any questions about the process?==<br />
<br />
Please post in the [https://moodle.org/mod/forum/view.php?id=28 Installing and upgrading help forum] on moodle.org.<br />
<br />
==See also==<br />
<br />
* [[dev:Moodle {{Version}} release notes|Moodle {{Version}} release notes]]<br />
* [https://moodle.org/mod/forum/discuss.php?d=393570 Problem accessing dropdown such as personal profile since 3.8 (20191118) update] forum discussion<br />
<br />
[[es:Actualización de moodle]]<br />
[[fr:Mise à jour]]<br />
[[ja:Moodleをアップグレードする]]<br />
[[de:Aktualisierung von Moodle]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=Course_meta_link&diff=136875Course meta link2020-04-17T08:36:15Z<p>Fox: French link</p>
<hr />
<div>{{Enrolment}}<br />
==About the Course meta link==<br />
The Course meta link makes it possible for all users enrolled in one course to be automatically enrolled in one or more other courses. The Course meta link plugin needs to be enabled both on the site level by the site admin and has to be enabled within the course. <br />
<br />
==Course settings for Course meta link==<br />
<br />
*In a course, go to ''Administration > Course administration > Users > Enrolment methods''.<br />
*Click the dropdown menu under the enrolment methods and select 'Course meta link'.<br />
''<br />
[[File:enrolmentmethods29c.png|thumb|center|300px]]<br />
*In the screen that comes up next, either type in a search term to find your course, or select from the dropdown box the course or courses you wish to bring enrolments from, and then click 'Add method': <br />
<br />
[[File:NFCoursemetalinkeg.png|thumb|center|Several courses may be selected at once|400px]] <br />
<br />
*For each linked course, the users may be added to an existing group in the new course, or a new group may be created for them. (Groups from the linked courses are not synced to groups in the new courses. All users will be added to one group when the link is made.)<br />
<br />
:Note: ''A teacher in a course will only be able to choose from courses they are teachers in elsewhere.''<br />
<br />
*The users from the source (child) course will now be enrolled in the current course - see the numbers in the screenshot below:<br />
<br />
[[File:NFCoursemetalinkusers.png]]<br />
<br />
*When new users are enrolled to the source (child) course, they will be automatically brought into the current target (meta)course.<br />
<br />
==Site settings for Course meta link==<br />
<br />
The Course meta link plugin may be enabled or disabled throughout the site in ''Administration > Site administration > Plugins > Enrolments > Manage enrol plugins''.<br />
<br />
The page ''Administration > Site administration > Plugins > Enrolments > Course meta link'' contains options for defaults that admin can set. (It can be also be accessed by clicking the ''Settings'' link on on the course meta link section of ''Administration > Site administration > Plugins > Enrolments > Manage enrol plugins'')<br />
<br />
By default all role assignments from child courses are synchronised to meta courses. However, the "Roles that are not synchronised to metacourses" setting enables administrators to exclude particular roles.<br />
<br />
==Course meta link capabilities==<br />
<br />
*[[Capabilities/enrol/meta:config|Configure meta enrol instances]]<br />
*[[Capabilities/enrol/meta:selectaslinked|Select course as meta linked]]<br />
<br />
==Enabling teachers to add meta links==<br />
<br />
An administrator can enable teachers to add course meta links as follows:<br />
<br />
* Go to ''Site Administration > Users > Permissions > Define Roles''<br />
* Select the Teacher Role and click on the Edit button<br />
* Scroll down to Course Meta Link as shown in the images below:<br />
{| class="nicetable" <br />
|-<br />
|[[Image:metacoursepermissionset00.png|Permission block for allowing Teachers to link Meta courses.]] <br />
|-<br />
| style="text-align: center;"| The default setting is "Not Set"<br />
|-<br />
|[[Image:metacoursepermissionset01.png|Permission changes for editing.]] <br />
|-<br />
| style="text-align: center;"| When the Edit button is clicked, the panel changes to "Allow" and a checkbox<br />
|- <br />
|[[Image:metacoursepermissionset02.png|Setting permission to allow Teachers to link Meta courses.]]<br />
|-<br />
| style="text-align: center;"| Change to "Allow" by a click on the checkbox. <br />
|}<br />
* Scroll to the bottom of the page to save your changes.<br />
<br />
==Examples of meta-linked courses==<br />
<br />
{| class="nicetable"<br />
|-<br />
![[Image:simplemetacourse0.png|thumb|left|200px|Created - a child course and a meta course.]] <br />
![[Image:simplemetacourse1.png|thumb|left|200px|Associating one child course and one meta course.]]<br />
|}<br />
<br />
Examples: one "child" course (a course linked to a meta course) can be associated with many meta courses. Or one meta course can have many child courses associated with it. Both the child courses (non-meta courses) and the meta courses are independent and can be recycled many times, that is, each can be associated with many of the other. <br />
<br />
{| class="nicetable" <br />
|-<br />
![[Image:simplemetacourse2.png|thumb|left|200px|2 child courses and a meta course.]] <br />
![[Image:simplemetacourse3.png|thumb|left|200px|1 child course and 2 meta courses.]]<br />
![[Image:simplemetacourse4a.png|thumb|left|200px|3 child courses and 2 meta courses.]]<br />
|}<br />
<br />
There is one limitation: you cannot 'nest' metacourses. In other words, if you have child course A linked to meta course B, and you then link B as a child course to meta course C, a student enrolled in A will be added to B, but not to C. In this situation, you would need to add a meta link directly between A and C instead of trying to nest them. (Another option might be to use [[Cohorts]].)<br />
<br />
<br />
==See also==<br />
<br />
Some known issues:<br />
<br />
* MDL-34938 - Important Open Issue: Enrolment expiration date settings in child course do not properly unenrol students from the Meta-course - (old: FIXED as of Moodle 2.9)<br />
* MDL-27628 - A workaround in the tracker for adding more than one course at a time (old: FIXED as of Moodle 3.1)<br />
<br />
How to use:<br />
* [https://moodle.org/mod/forum/discuss.php?d=316161#p1266891 Re: Help setting up meta link metacourses with parent child courses] forum post<br />
* [http://www.youtube.com/watch?v=hA5QcTb13no&feature=player_embedded Screencast showing how to use the Course meta link plugin to make a Metacourse]<br />
*[[Metacourse examples of use]]<br />
<br />
[[de:Meta-Einschreibung]]<br />
[[es:Enlace a metacurso]]<br />
[[fr:Lien méta-cours]]<br />
[[ja:コースメタリンク]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=Moodle_app_guide_for_admins&diff=136687Moodle app guide for admins2020-02-27T10:02:56Z<p>Fox: /* Customise your app theme */</p>
<hr />
<div>{{Mobile}}<br />
==Enable mobile services on your site==<br />
Your site needs to have mobile access enabled so users can use the mobile app.<br />
<br />
For sites using https, mobile access is enabled by default in new installations of Moodle 3.0 onwards.<br />
<br />
For http sites, mobile access can be enabled by an administrator as follows:<br />
<br />
# In ''Site administration > Mobile app > Mobile settings'' tick the 'Enable web services for mobile devices' checkbox<br />
# Click the button to save changes.<br />
<br />
If your site uses a [https://en.wikipedia.org/wiki/Transport_Layer_Security SSL certificate], it must be a trusted certificate. For security reasons the app doesn't work with self-signed certificates.<br />
<br />
Please, verify that your certificate is valid via: https://www.geocerts.com/ssl_checker (you shouldn't see any warning).<br />
<br />
If your site has the /login directory protected (frequently done when using the Shibboleth authentication method), you must enable access to the login/token.php script.<br />
<br />
===Frame embedding===<br />
If your sites uses [https://en.wikipedia.org/wiki/ReCAPTCHA reCaptcha], Vimeo videos or custom menu items (as described bellow) you must enable the admin setting "Allow frame embedding" (allowframembedding).<br />
<br />
==Mobile authentication==<br />
<br />
If your site uses a SSO authentication method (CAS, Shibboleth, LDAP SSO, OAuth...), then select via a browser window or via an embedded browser for 'Type of login' (typeoflogin) in 'Mobile authentication' in the Site administration. (This setting is provided for older pre-Moodle 3.2 sites via the [[Moodle Mobile additional features]] plugin.)<br />
<br />
The options 'browser window' and 'embedded browser' are very similar; the only difference is when redirecting the user to enter their credentials in the site, the site will be opened in the device's default browser (for browser window) or the site will be opened "embedded" in the mobile app (for embedded browser). The user experience is better in embedded browser, but not all the authentication plugins will work in embedded browser (for example, if JavaScript popups are required they must use the 'browser window'). The admin should check whether both options work, and if so, choose 'embedded browser'.<br />
<br />
If you are using Google OAuth you will have to use the 'browser window' method because Google recently blocked authentication via 'embedded browsers'.<br />
<br />
If your organisation uses a custom branded app and 'Type of login' is set to 'Via a browser window' or 'Via embedded browser', then a URL scheme (forcedurlscheme) may be set. This will result in only the custom branded app working for the site: the official Moodle Mobile app will not work.<br />
<br />
== Customise your app theme ==<br />
<br />
The app can also retrieve your custom styles from your Moodle site. Since the app is a HTML5 app, you can safely apply any CSS, CSS2 and CSS3 style.<br />
<br />
Go to ''Administration > Site administration > Mobile app > Mobile appearance'' and enter in the mobilecssurl field a valid URL pointing to a CSS file containing your custom styles.<br />
<br />
The CSS should be placed inside your Moodle installation (in your custom theme or inside a local plugin).<br />
<br />
'''For example:''' ''https://mymoodlesite.com/theme/mytheme/style/mymobileapp.css''<br />
<br />
Once the user is logged in the app, remote CSS files for applying your custom styles are regularly retrieved.<br />
<br />
Notice that on the first time a user opens the app, he will see the default "orange" style. Your custom styles will be applied once the user has added a site in the app.<br />
<br />
For further information, see the dev docs [[:dev:Moodle Mobile Themes|Moodle Mobile Themes]].<br />
<br />
If you want your own custom branding for your organization, Moodle offers the The [https://moodle.com/branded-app Branded Moodle Mobile app] service, please visit https://moodle.com/app/ for more information.<br />
<br />
== Moodle Mobile additional features plugin for old Moodle sites ==<br />
<br />
For old Moodle sites it is recommended to install the [[Moodle Mobile additional features]] plugin.<br />
<br />
== Notifications ==<br />
<br />
You might find them annoying but push notifications keeps you and your users informed and updated on everything about the app. Moodle only send useful and important notifications such as new features or service disruptions.<br />
<br />
Enabling push notifications is easy! An administrator can enable it by connecting their Moodle site/s to our free Notifications server available (only) for registered Moodle sites. <br />
<br />
An access key can be obtained via ''Site administration > Plugins > Message outputs > Manage message outputs''. Then by clicking the link to the Mobile settings, on the next page select ''Request access key''.<br />
<br />
The full guide on enabling push notifications can be found here: [[Mobile app notifications]]<br />
<br />
== App banners ==<br />
[[File:app banner.png|thumb|Moodle Mobile app banner]]<br />
App banners let your users know that there is a mobile app available for the site. App banners are only displayed when accessing the site using a mobile browser.<br />
<br />
In Moodle 3.3 onwards, app banners for Android are supported as well as for iOS.<br />
<br />
App banners are disabled by default. They can be enabled in 'Mobile appearance' in the Site administration.<br />
<br />
If you are using a custom mobile app, you need to provide the unique identifier for the iOS and Android app; if you are using the Moodle Mobile app, the settings may be left as default.<br />
<br />
Please, notice the following:<br />
* App banners for iOS devices (iPhone, iPad or iPod) are only shown when accessing the site using the Safari browser<br />
* App banners for Android devices are only shown in very recent Chrome browser versions and when the app is not installed. Note also that Chrome uses an engagement heuristic that will display the banner only on certain conditions, like interactions with the site, the last time you interacted with it, etc. You can remove the engagement restriction check by disabling this special chrome flag: chrome://flags/#bypass-app-banner-engagement-checks<br />
<br />
=='Get the mobile app' link==<br />
<br />
In Moodle 3.4 onwards, the link 'Get the mobile app' in the footer of each page on the site encourages users to make use of the mobile app. <br />
<br />
By default, the link is https://download.moodle.org/mobile however the setting 'App download page' can be changed e.g. for sites using a branded mobile app.<br />
<br />
If mobile services are not enabled for the site, then the 'Get the mobile app' link is not displayed. <br />
<br />
To prevent the 'Get the mobile app' link being displayed, simply remove the URL from the 'App download page' setting and save changes.<br />
<br />
== Configuring the app from your site ==<br />
<br />
In Moodle 3.3 onwards, or with the [[Moodle Mobile additional features]] plugin, settings in the Site administration enable admins to configure the app.<br />
<br />
* In Moodle 3.3 onwards go to ''Site administration > Mobile features''<br />
* In sites with the Moodle Mobile additional features plugin installed, go to ''Site administration > Plugins > Local plugins > Mobile additional features''<br />
<br />
===Force log out===<br />
<br />
Replace the Change site option to "Log out" so that users must enter their credentials on their next access. This is useful for custom mobile apps, as there is no reason for users wanting to switch to a different site.<br />
<br />
===Disabled features===<br />
<br />
The mobile app may be simplified by removing unwanted features. Some items may already be not available in the app because they are not enabled on your site.<br />
<br />
Options to remove include:<br />
<br />
* Offline use<br />
* Blocks<br />
* Comments<br />
* Ratings<br />
* Tags<br />
* Create new account<br />
* Responsive menu items (new in 3.7)<br />
* Main menu<br />
** Site home<br />
** My courses<br />
** Dashboard<br />
** Calendar<br />
** Notifications<br />
** Messages<br />
** Grades<br />
** My learning plans<br />
** Blog<br />
** Files<br />
** Web page<br />
** Help<br />
* Course<br />
** Blocks<br />
** Blog<br />
** Search<br />
** Competencies<br />
** Participants<br />
** Grades<br />
** Course completion<br />
** Notes<br />
** Download course (new in 3.5)<br />
** Download courses (new in 3.5)<br />
* User<br />
** Blog<br />
** Badges<br />
** Competencies<br />
** Course completion<br />
** Grades<br />
** Send message<br />
** Add contact<br />
** Block contact<br />
** Add a new note<br />
** User picture<br />
* Files<br />
** Private files<br />
** Ste files<br />
** Upload<br />
* Modules (Each module can be disabled separately)<br />
* Blocks (Each block available in the app can be disabled separately)<br />
<br />
===Custom menu items===<br />
<br />
Additional items can be added to the app main menu (the side menu), such as a link to a different grade book.<br />
<br />
Each custom menu item should have format: item text, link URL, link-opening method and language code (optional, for displaying the item to users of the specified language only), separated by pipe characters.<br />
<br />
Possible link-opening methods are:<br />
<br />
* app - for linking to an activity supported by the app i.e. almost all activity types, as listed in [[Moodle Mobile features]].<br />
* inappbrowser - for linking to external URLs or site functionalities not supported by the app. The link will open in a browser inside the app overlaying the complete screen.<br />
* browser - as for inappbrowser except that the link will instead open in the device default browser outside the app.<br />
* embedded - as for inappbrowser except that the link will instead open in an iframe in a new page in the app. (For this option you may need to enable the admin setting "Allow frame embedding" (allowframembedding)<br />
<br />
Tip: If you add a custom menu item and save changes, then it doesn't appear in the app main menu, double check that the item is correctly formatted.<br />
<br />
Please, note that if the app is using a language not indicated in the previous list, the first language in the list will be used.<br />
<br />
If you want options tied to a language, you can append _only to the language code, for example:<br />
en_only<br />
es_only<br />
<br />
Will display the custom menu item only when the app language is English or Spanish.<br />
<br />
===Responsive menu items===<br />
<br />
From 3.7 onwards menu items on bottom tabs are moved to the side of the screen on big screens. Also the number of items displayed on the menu may vary:<br />
<br />
* On small screens (usually phones) from 2 to 5 items will be displayed depending on the size of the screen.<br />
* On big screens (usually tablets an desktop version) more than 2 items will be displayed without limit.<br />
<br />
If '''Responsive menu items''' is selected in Disabled features items will be displayed in side of bottom anyway but 5 items will be displayed in all cases without depending on the size of the screen.<br />
<br />
===Custom language strings ===<br />
<br />
Words and phrases displayed in the app can be customised via the "Custom language strings" (customlangstrings) setting.<br />
<br />
Enter each custom language string on a new line with format: string identifier, custom language string and language code, separated by pipe characters. For example:<br />
<br />
mm.user.student|Learner|en<br />
mm.user.student|Aprendiz|es<br />
<br />
The complete list of string identifiers is listed in https://raw.githubusercontent.com/moodlehq/moodleapp/master/src/assets/lang/en.json. The string identifier is before the colon. <br />
<br />
For example:<br />
<br />
[[File:Mobile string identifiers list examples.png|300px]]<br />
<br />
means that the string "Student" has string identifier "mm.user.student".<br />
<br />
==Web services token duration==<br />
<br />
In Moodle 3.4 onwards, an admin can set how long a web services token created by a user (for example via the mobile app) is valid. (In previous versions of Moodle a token was valid for 3 months.)<br />
<br />
==App's cache==<br />
<br />
The app caches WebService requests to decrease data usage and increase the app's speed. When the app needs to get some data from Moodle, it will use a cached request as long as it isn't expired.<br />
<br />
This cache was improved in Moodle App 3.7.0, now there are several cache times depending on the WS being called. This means that some requests will expire more often than others. Also, if the user isn't using a WiFi connection, the expiration time will also be longer to decrease the data usage. These cache times cannot be configured using a Moodle setting.<br />
<br />
==See also==<br />
<br />
* [[Moodle Mobile FAQ]] for other administration-related mobile app questions.<br />
* [[:dev:Moodle Mobile debugging WS requests]] - a guide to helping you find and report problems with the Moodle Mobile app on your site<br />
* [[:dev: Moodle Mobile Roadmap]]<br />
* [[:dev:Moodle Mobile release notes]]<br />
* [[:dev:Moodle Mobile|Moodle Mobile developer docs]]<br />
* [[Moodle Mobile availability plugin]]<br />
* [[Mobile web services]]<br />
<br />
[[fr: Guide mobile pour administrateurs]]<br />
[[es:Moodle app guía para administradores]]<br />
[[de:Moodle App - Anleitung für Administrator/innen]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=error/admin/accessdenied&diff=136221error/admin/accessdenied2019-12-12T16:42:54Z<p>Fox: French link</p>
<hr />
<div>This error is encountered if you do not have admin privileges or if you are not logged in. This means that you are not authorized to enter such an area or run such scripts.<br />
<br />
[[Category:Error]]<br />
<br />
[[es:error/admin/accessdenied]]<br />
[[fr:error/admin/accessdenied]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=Git_for_Administrators&diff=136000Git for Administrators2019-11-22T12:53:38Z<p>Fox: /* See also */</p>
<hr />
<div>{{Installing Moodle}}<br />
This page describes how to maintain a copy of Moodle on your production server which can easily be upgraded using Git. If you have customisations of Moodle core code, you are advised to follow the instructions in the [[:dev:Git for developers|Git for developers guide]].<br />
<br />
To get the most of Git it is worth making the effort to understand its basic concepts - see the section below. It can be a bit of a steep learning curve, especially if you are used to CVS or Subversion. <br />
<br />
== Getting hold of Git (Windows, OSX, Linux and others) ==<br />
<br />
Support for Git was, up until recently, mostly confined to Linux but builds are now available for most popular operating systems:<br />
<br />
* List of downloads from Git site - http://git-scm.com/download<br />
<br />
Once you have downloaded and installed your OS relevant git installation, the git commands in this document should work with your operating system.<br />
<br />
== Obtaining the code from Git ==<br />
<br />
The command line version of Git is discussed here. Graphical clients are little more than wrappers around the command line version, so you should be able to deduce the correct parameters quite easily. <br />
<br />
You can find the official Moodle git repository at git://git.moodle.org/moodle.git (with an official clone at git://github.com/moodle/moodle.git). To initialize your local checkout, use<br />
<pre><br />
$ cd /path/to/your/webroot<br />
$ git clone git://git.moodle.org/moodle.git (1)<br />
$ cd moodle<br />
$ git branch -a (2)<br />
$ git branch --track MOODLE_38_STABLE origin/MOODLE_38_STABLE (3)<br />
$ git checkout MOODLE_38_STABLE (4)<br />
</pre><br />
* The command (1) initializes the new local repository as a clone of the 'upstream' (i.e. the remote server based) moodle.git repository. The upstream repository is called 'origin' by default. It creates a new directory named ''moodle'', where it downloads all the files. This operation can take a while as it is actually getting the entire history of all Moodle versions<br />
* The command (2) lists all available branches.<br />
* Use the command (3) to create a new local branch called MOODLE_38_STABLE and set it to track the remote branch MOODLE_38_STABLE from the upstream repository.<br />
* The command (4) actually switches to the newly created local branch. <br />
==Git Connection Refused Error==<br />
*If connection refused, use: $ git clone https://github.com/moodle/moodle.git<br />
''fatal: unable to connect to git.moodle.org:<br />
git.moodle.org[0: 34.210.133.53]: errno=Connection refused''<br />
<br />
Note that Git has a huge number of options for each command and it's actually possible to do the above process with a single command (left as an exercise!!).<br />
<br />
==Git from behind a firewall==<br />
<br />
Git uses a read-only protocol that may be blocked by your firewall (port 9418). If this is a problem, you can use Github's http version <nowiki>https://github.com/moodle/moodle.git</nowiki>. It's a bit slower, so use the Git protocol if you can.<br />
<br />
== Updating your installation ==<br />
<br />
The Moodle development team performs integration and testing of fixed bugs every Monday and Tuesday. On Wednesday you can install all patches by updating your code. Check the [http://git.moodle.org/gw?p=moodle.git;a=summary shortlog] to see if the official repository has been already updated or not.<br />
<br />
To update your code to the latest version (on the MOODLE_38_STABLE branch) '''all''' you have to do is:<br />
<pre><br />
$ cd /path/to/your/moodle/<br />
$ git pull<br />
</pre><br />
If this is a production site you should still consider the [[Upgrade]] instructions (e.g. take backups).<br />
<br />
== Installing a contributed extension from its Git repository ==<br />
<br />
This is one way to handle adding plugins from other Git repositories into your Moodle repository. Another way is to use Git Submodules. However, at the time of writing, this is one of Git's rougher features and should be regarded as an advanced option. <br />
<br />
For example, let us say we want to install the [[Certificate module]] from its Git repository into our Moodle {{Version}}.<br />
<pre><br />
$ cd /path/to/your/moodle/<br />
$ cd mod (1)<br />
$ git clone https://github.com/markn86/moodle-mod_certificate.git certificate (2)<br />
$ cd certificate<br />
$ git checkout -b MOODLE_38_STABLE origin/MOODLE_38_STABLE (3)<br />
$ git branch -d master (4)<br />
</pre><br />
The command (1) changes the current directory into the ''mod'' folder of your local Moodle clone. The command (2) creates a new subdirectory ''certificate'' and makes a local clone of vanilla Certificate repository. The command (3) creates a new local branch that will track the remote branch with a Certificate version for Moodle {{Version}}. The command (4) deletes the ''master'' that was created automatically by git-clone in (2) as we do not want it in this production checkout.<br />
<br />
Note: you should check first the compatibility of a module with your Moodle branch by asking directly to the Maintainer before cloning the repo or - if you want to guess it - by issuing the command below before running the command (3), in order to verify what is available among the branches:<br />
<pre><br />
$ git branch -a<br />
* master<br />
remotes/origin/HEAD -> origin/master<br />
remotes/origin/MOODLE_20_STABLE<br />
remotes/origin/MOODLE_21_STABLE<br />
remotes/origin/MOODLE_22_STABLE<br />
remotes/origin/MOODLE_23_STABLE<br />
remotes/origin/MOODLE_24_STABLE<br />
remotes/origin/MOODLE_25_STABLE<br />
remotes/origin/MOODLE_26_STABLE<br />
remotes/origin/MOODLE_27_STABLE<br />
remotes/origin/MOODLE_28_STABLE<br />
remotes/origin/MOODLE_29_STABLE<br />
remotes/origin/MOODLE_30_STABLE<br />
remotes/origin/MOODLE_31_STABLE<br />
remotes/origin/master<br />
</pre><br />
This will avoid an error message when you issue the command (3) against a nonexistent branch, e.g.:<br />
<pre><br />
§ git checkout -b MOODLE_31_STABLE origin/MOODLE_31_STABLE<br />
fatal: git checkout: updating paths is incompatible with switching branches.<br />
Did you intend to checkout 'origin/MOODLE_31_STABLE' which can not be resolved as commit?<br />
</pre><br />
<br />
Note: To fix above error, use: "git fetch origin MOODLE_31_STABLE:LOCAL_MOODLE_31_STABLE"<br />
<br />
Now it is wise to add the new directory mod/certificate/ to the list of ignored files of the main Moodle clone, otherwise a status of the main clone will keep reminding you that the new code has not been checked in.<br />
<pre><br />
$ cd /path/to/your/moodle/<br />
$ echo /mod/certificate/ >> .git/info/exclude<br />
</pre><br />
To update your Moodle installation now, you must visit both Git repositories and pull changes from upstream.<br />
<pre><br />
$ cd /path/to/your/moodle/<br />
$ git pull<br />
$ cd mod/certificate<br />
$ git pull<br />
</pre><br />
Writing a shell script with these lines in the root of Moodle installation is a very good idea. Otherwise it is easy to forget what Git repositories are there within the main Moodle repository.<br />
<br />
== Installing and maintaining contributed extensions using Git submodules ==<br />
<br />
As it was said in the previous section, this is for advanced users only.<br />
Therefore it is necessary, that you have some experience with Git and its commands.<br />
A step-by-step explanation will be provided, but in order to follow these steps it is helpful to understand, what these commands do.<br />
<br />
Advanced options and commands can be found at [[https://git-scm.com/book/en/v2/Git-Tools-Submodules|the Git book]].<br />
If you have any questions about Git submodules, please visit the site above first.<br />
<br />
=== Installing a new extension into an existing Moodle ===<br />
<br />
As an example we use the [[Certificate module]] from the previous section.<br />
<pre><br />
$ cd /path/to/your/moodle<br />
$ git submodule add https://github.com/markn86/moodle-mod_certificate.git mod/certificate<br />
</pre><br />
<br />
Note, that Git is reporting two new files in the repository:<br />
<pre><br />
$ git status<br />
# On branch MOODLE_29_STABLE<br />
# Changes to be committed:<br />
# (use "git reset HEAD <file>..." to unstage)<br />
#<br />
# new file: .gitmodules<br />
# new file: mod/certificate<br />
#<br />
</pre><br />
<br />
The file '''.gitmodules''' contains the local path and url of all your submodules.<br />
It has to be committed, if you intend to clone the repository later (see the page [[Moodle development environment with Git submodules]]).<br />
Before commiting, make sure to check the configuration of the plugin's Git repository, since the automatically generated settings may be not sufficient.<br />
For future updates it is helpful, to track the remote branch, which corresponds to the Moodle version of your repository.<br />
<pre><br />
$ cd mod/certificate<br />
$ git branch -avv<br />
* master 345f5b1 [origin/master] Replaced deprecated function<br />
remotes/origin/HEAD -> origin/master<br />
remotes/origin/MOODLE_20_STABLE 1aa1040 Added option to print 'grade category' grade<br />
remotes/origin/MOODLE_21_STABLE 1aa1040 Added option to print 'grade category' grade<br />
remotes/origin/MOODLE_22_STABLE 1aa1040 Added option to print 'grade category' grade<br />
remotes/origin/MOODLE_23_STABLE fe047de Check that the function exists rather than relying on the Moodle version<br />
remotes/origin/MOODLE_24_STABLE 1051f7d CONTRIB-4892 Fixed the email to others functionality<br />
remotes/origin/MOODLE_25_STABLE cdb221a CONTRIB-4946: Removed character from language file breaking AMOS<br />
remotes/origin/MOODLE_26_STABLE 696802a Increased version<br />
remotes/origin/MOODLE_27_STABLE d3c0379 Increased version<br />
remotes/origin/MOODLE_28_STABLE fa8df83 Increased version<br />
remotes/origin/MOODLE_29_STABLE 3f03740 Replaced deprecated function<br />
remotes/origin/master 345f5b1 Replaced deprecated function<br />
</pre><br />
<br />
Git created the branch '''master''' which tracks '''origin/master''' automatically, because the remote repository has checked out '''master'''.<br />
Therefore, create a new branch, which tracks the appropriate remote branch.<br />
Of course, this is only possible, if the remote repository offers those branches. <br />
<pre><br />
$ git checkout -b MOODLE_29_STABLE origin/MOODLE_29_STABLE<br />
Branch MOODLE_29_STABLE set up to track remote branch MOODLE_29_STABLE from origin.<br />
Switched to a new branch 'MOODLE_29_STABLE'<br />
$ git branch -D master<br />
Deleted branch master (was 345f5b1).<br />
</pre><br />
It is not necessary to delete the '''master''' branch, but it's useless to keep it.<br />
In fact, these settings don't need to be touched afterwards.<br />
<br />
The final step is to commit the changes to the main repository.<br />
<pre><br />
$ cd /path/to/your/moodle<br />
$ git commit -a -m "New extension mod_certificate installed"<br />
</pre><br />
<br />
It has to be ensured, that the commit includes only the changes for the new Git submodule (since '''-a''' commits all non-staged changes).<br />
<br />
=== Maintaining Git submodules ===<br />
<br />
Maintaining a set of submodules is extremely easy.<br />
Consider a Moodle repository with several submodules installed.<br />
Keep in mind, that the extension '''mod_mylittleextension''' is a fake plugin, created for a test scenario in this example.<br />
It is not an official Moodle module. For updating all your submodules at once, type in:<br />
<pre><br />
$ cd /path/to/your/moodle<br />
$ git submodule foreach git pull<br />
Entering 'block/coursefeedback'<br />
Already up-to-date.<br />
Entering 'mod/certificate'<br />
Already up-to-date.<br />
Entering 'mod/mylittleextension'<br />
remote: Counting objects: 6, done.<br />
remote: Compressing objects: 100% (4/4), done.<br />
remote: Total 4 (delta 0), reused 0 (delta 0)<br />
Unpacking objects: 100% (4/4), done.<br />
From /local/repositories/mle<br />
89d9eae..64c122d master -> origin/master<br />
Updating 89d9eae..64c122d<br />
Fast-forward<br />
index.html | 9 +++++++++<br />
version.php | 6 +++---<br />
2 files changed, 12 insertions(+), 3 deletions(-)<br />
create mode 100644 index.html<br />
$ git status<br />
# On branch MOODLE_29_STABLE<br />
# Changes not staged for commit:<br />
# (use "git add <file>..." to update what will be committed)<br />
# (use "git checkout -- <file>..." to discard changes in working directory)<br />
#<br />
# modified: mod/mylittleextension (new commits)<br />
#<br />
</pre><br />
<br />
The command '''git submodule foreach [another command]''' walks through all submodule repositiories and executes what is specified by '''[another command]'''.<br />
In this case it is '''git pull'''.<br />
Therefore the module mylittleextension was updated and the main repository isn't clean anymore until changes are committed:<br />
<pre><br />
$ git commit -a -m "Plugin updates"<br />
</pre><br />
<br />
Maintaining plugins with Git submodules has also another application than simplifying the update process.<br />
In a greater scale it can be used to maintain a Moodle project, where multiple developers need to have an exact copy of your moodle without organizing external plugins manually.<br />
You can read more about this topic at the page [[Moodle development environment with Git submodules]].<br />
<br />
== See also ==<br />
<br />
* [[Windows installation using Git]]<br />
* [[Git for Mac]]<br />
* [[:dev:Moodle versions]]<br />
* For fixing a Tracker Issue (MDL) / Forking Moodle / CONTRIButing code [[:dev:User:Sam_Hemelryk/My_Moodle_Git_workflow|User:Sam_Hemelryk/My_Moodle_Git_workflow]]<br />
* [[Moodle_Production_Server_with_GIT|Case study Git + Moodle from Technical University Berlin]]<br />
<br />
; Moodle forum discussions<br />
* [https://moodle.org/mod/forum/discuss.php?d=255175 Github and Moodle deployment for production]<br />
* [http://moodle.org/mod/forum/discuss.php?d=168094 GIT help needed]<br />
* [https://moodle.org/mod/forum/discuss.php?d=231046 Clear git guide for Admins (not developers)]<br />
* [https://moodle.org/mod/forum/discuss.php?d=393756 Best way to use Git]<br />
<br />
; External resources <br />
* [http://thamblings.blogspot.com.au/2013/07/upgrading-moodle-from-git.html Deploying Moodle from git - Blog post from a production experience]<br />
* [http://gitref.org/ Git Reference]<br />
* [http://progit.org/book/ Pro Git book]<br />
<br />
[[ja:管理者用Git]]<br />
[[fr:Git_pour_administrateurs]]<br />
[[es:Git para Administradores]]<br />
[[en:Git für Administratoren]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=Capabilities/gradeimport/xml:view&diff=134090Capabilities/gradeimport/xml:view2019-05-24T09:23:32Z<p>Fox: French link</p>
<hr />
<div>{{Capabilities}}<br />
* This allows a user to [[Grade import|import grades]] via XML file<br />
* This capability is allowed for the default roles of manager and teacher<br />
<br />
[[Category:Capabilities|Grade]]<br />
[[Category:Grades]]<br />
<br />
[[eu:Capabilities/gradeimport/xml:view]]<br />
[[fr:Capabilities/gradeimport/xml:view]]<br />
[[ja:ケイパビリティ/gradeimport/xml:view]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=Capabilities/gradeexport/ods:view&diff=134088Capabilities/gradeexport/ods:view2019-05-24T09:20:56Z<p>Fox: French link</p>
<hr />
<div>{{Capabilities}}<br />
<br />
*This allows a user to use the OpenOffice [[Grade export|grade export]].<br />
*This capability is set to allow for the default roles of manager, teacher and non-editing teacher.<br />
<br />
[[Category:Capabilities|Grade]]<br />
[[Category:Grades]]<br />
<br />
[[eu:Capabilities/gradeexport/ods:view]]<br />
[[fr:Capabilities/gradeexport/ods:view]]<br />
[[ja:ケイパビリティ/gradeexport/ods:view]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=Upgrade_overview&diff=134057Upgrade overview2019-05-23T09:25:38Z<p>Fox: /* Step 1: Make sure that your server can run Moodle {{Version}} */</p>
<hr />
<div>{{Installing Moodle}} <br />
<span class="small-info-right">''Moodle {{Version}} available now!''</span><br />
Start enjoying the cool features of the latest and greatest version of Moodle in four easy steps...<br />
__NOTOC__<br />
==Step 1: Make sure that your server can run Moodle {{Version}}==<br />
<br />
(Note: You need to upgrade to Moodle 3.2 or later before upgrading to {{Version}}.)<br />
<br />
Go to ''Site administration > Server > Environment''<br />
<br />
Status OK for everything? Great! Go to step 2...<br />
<br />
Any problems? You probably need to upgrade your server software (such as PHP) to a more recent version.<br />
<br />
==Step 2: Be prepared!==<br />
<br />
As usual with any large upgrade, you should always be prepared to "roll back" if there's an issue with your data or some custom code you've added.<br />
<br />
; A test install: We highly advise you make a copy of your production site to practice the upgrade on first. That way, if you run into any problems that need fixing you won't affect your main site.<br />
<br />
; Always make backups: When upgrading your production instance, make sure you have copies of everything, just in case. Full instructions are here: [[Site backup]].<br />
<br />
==Step 3: Replace your Moodle code==<br />
<br />
At this point you can replace the Moodle code on your server with the version you downloaded.<br />
<br />
; Check plugins: Any plugins you have installed will also to be replaced with a version for your new Moodle version. If there is not yet an updated version of the plugin available, it will need to be uninstalled before upgrading your site.<br />
<br />
==Step 4: Perform the upgrade!==<br />
<br />
Trigger the upgrade by [[Upgrading#Finishing_the_upgrade|visiting the admin page]].<br />
<br />
If you have a large site this may take hours, so we recommend [[Administration_via_command_line#Upgrading|upgrading via command line]].<br />
<br />
==How did you go?==<br />
<br />
; Yes - it worked!: Great! Repeat the process for Moodle {{Version}}, and please post in the [http://moodle.org/mod/forum/view.php?id=28 Installation help forum] and share your success with the Moodle community!<br />
; No - I had an error: Don’t worry, help is at hand. Post in the [http://moodle.org/mod/forum/view.php?id=28 Installation help forum] where our experts are waiting to explain any errors you obtain.<br />
<br />
==See also==<br />
<br />
* [[Upgrading]] for full details of the process<br />
* [[Upgrading FAQ]]<br />
<br />
[[Category:Installation]]<br />
<br />
[[de:Aktualisierung in Kürze]]<br />
[[es:Visión general de actualización]]<br />
[[ja:アップグレード概要]]<br />
[[fr:Aperçu des mises à jour]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=Upgrading_FAQ&diff=133856Upgrading FAQ2019-05-17T10:06:57Z<p>Fox: /* How do I upgrade from 1.9.x to {{Version}}? */</p>
<hr />
<div>{{Installing Moodle}}<br />
==How do I upgrade from 1.9.x to {{Version}}?==<br />
<br />
1.x -> 1.9.19+ -> 2.2.11 -> 2.7.20 -> 3.2.9 -> {{Version}} <br />
<br />
(It is better to upgrade to latest current stable before going to next branch, the same for plugins; upgrading from early stable branches usually works but there is no guarantee.)<br />
<br />
Moodle 2.2.11 may be downloaded from https://download.moodle.org/stable22/.<br />
<br />
==How do I upgrade Moodle? Do I just overwrite the files?==<br />
<br />
Do NOT overwrite files, as it may cause strange errors. Read the [[Upgrading]] documentation before proceeding.<br />
<br />
==I obtain the message "Upgrade already running in this session, please wait!"==<br />
<br />
Most likely you refreshed the page before the completion message. If you are absolutely sure that there are no upgrade processes active (php and/or mysql), you can click on "!!!" and restart the upgrade.<br />
<br />
:''Note'': If you click on "'!!!" or try to restart the upgrade from another browser, there is a chance that your data in the database could be corrupted. If this happens, you will need to restore the database from sql dump and then restart the upgrade and wait - the process can take several hours on large sites.<br />
<br />
==Can I upgrade more than one version at a time?==<br />
<br />
You can only upgrade to Moodle {{Version}} from Moodle 3.2 or later.<br />
<br />
You can only upgrade to Moodle 2.7 from Moodle 2.2 or later.<br />
<br />
You can only upgrade to Moodle 2.2 from Moodle 1.9 or later.<br />
<br />
==I have custom code in my site. How do I upgrade?==<br />
Please see this forum post on [https://moodle.org/mod/forum/discuss.php?d=263355#p1141326 upgrading with custom code] for some suggestions.<br />
<br />
==Any further questions?==<br />
<br />
Please post in the [https://moodle.org/mod/forum/view.php?id=28 Installing and upgrading help forum] on moodle.org.<br />
<br />
==See also==<br />
<br />
* [[Installation FAQ]]<br />
<br />
[[Category:FAQ]]<br />
<br />
[[es:Actualización FAQ]]<br />
[[fr:FAQ de mise à jour]]<br />
[[ja:アップグレードFAQ]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=Upgrading&diff=133821Upgrading2019-05-16T10:33:27Z<p>Fox: /* Possible issues that may affect you in Moodle {{Version}} */</p>
<hr />
<div>{{Installing Moodle}} <br />
''This page explains in detail how to upgrade Moodle. For a summary of the process, see [[Upgrade overview]].''<br />
<br />
==Check the requirements==<br />
<br />
Before upgrading, check that your server meets all requirements for {{Version}} in ''Site administration > Server > [[Environment]]''. <br />
<br />
See the [{{Release notes}} release notes] in the dev docs for both [{{Release notes}}#Server_requirements server] and [{{Release notes}}#Client_requirements client] software requirements.<br />
<br />
Notes:<br />
<br />
* You can only upgrade to Moodle {{Version}} from Moodle 3.1 or later. If upgrading from earlier versions, you must [https://docs.moodle.org/31/en/Upgrading_to_Moodle_3.1 upgrade to 3.1] as a first step.<br />
<br />
==Before upgrading==<br />
<br />
'''We advise that you test the upgrade first on a COPY of your production site, to make sure it works as you expect.'''<br />
<br />
Consider setting the [[Upgrade key|upgrade key]] for your site.<br />
<br />
== Backup important data ==<br />
<br />
There are three areas that should be backed up before any upgrade:<br />
#Moodle software (For example, everything in server/htdocs/moodle)<br />
#Moodle uploaded files (For example, server/moodledata)<br />
#Moodle database (For example, your Postgres or MySQL database dump)<br />
<br />
See [[Site backup]] for more specific information.<br />
<br />
== Check for plugin updates ==<br />
<br />
If you have [[Automatic updates deployment]] enabled, you will be able to update installed plugins automatically during the upgrade. Just make sure you check for available updates (via the button for it) at the Plugins check screen.<br />
<br />
If you are updating plugins manually, it is a good moment now to check in the [http://moodle.org/plugins Moodle Plugins directory] whether there is a {{Version}} version available for any plugins (including themes) that you have previously installed on your site. If so, download the plugin package. In the next step, you will copy it to the appropriate location in your Moodle code (see [[Installing plugins]]).<br />
<br />
The upgrade of the plugin will then happen as part of the Moodle upgrade process.<br />
<br />
If an out-of-date plugin causes your upgrade to fail, you can usually delete the plugin code rather than uninstalling it from within Moodle so that the data associated with it is not deleted.<br />
<br />
==Put your site into maintenance mode==<br />
Before you begin upgrading your site, you should put it into [[Maintenance_mode | maintenance mode]] to stop any non-admin users from logging in. Then you should wait for any currently running cron processes to complete before proceeding.<br />
<br />
== Install the new Moodle software ==<br />
You can fetch the current version of the software through <br />
<br />
wget http://sourceforge.net/projects/moodle/files/Moodle/stable{{Version2}}/moodle-latest-{{Version2}}.tgz<br />
<br />
=== Standard install package ===<br />
<br />
# Move your old Moodle software program files to another location. ''Do NOT copy new files over the old files.''<br />
# Unzip or unpack the upgrade file so that all the new Moodle software program files are in the location the old files used to be in on the server. Moodle will adjust SQL and moodledata if it needs to in the upgrade.<br />
# Copy your old [[Configuration file|config.php file]] back to the new Moodle directory. <br />
# As mentioned above, if you had installed any plugins on your site you should add them to the new code tree (Moodle directory structure) now. It is important to check that you get the correct version for your new version of Moodle. Be particularly careful that you do not overwrite any code in the new version of Moodle and that you place the plugin folders in the correct directory (the same directory that they are in in the current installation.)<br />
# Your moodledata folder should be located separately to your Moodle code folder and, as such, should not need anything done to it. Moodle 3.0 will throw a warning if it is located in a web accessible folder and the moodledata should never be located in the Moodle code folder. If you are moving your installation to a new server or new location on your server, then you will need to follow the [[Migration]] documents.<br />
<br />
====Linux====<br />
mv moodle moodle.backup<br />
tar xvzf moodle-latest-{{Version}}.tgz<br />
<br />
Next, copy across your config.php, any custom plugins, and your .htaccess file if you created one ('''check that custom plugins are the correct version for your new Moodle first'''):<br />
<br />
cp moodle.backup/config.php moodle<br />
cp -pr moodle.backup/theme/mytheme moodle/theme/mytheme<br />
cp -pr moodle.backup/mod/mymod moodle/mod/mymod<br />
<br />
Don't forget to make moodle/config.php (and the rest of the source code) readable by your www server. For maximum security the files should not be writeable by your server. This is especially important on a 'production' server open to the public internet. <br />
<br />
chown -R root:root moodle (Linux debian - or even create a user especially for moodle. '''Don't''' use the web server user, e.g. www-data)<br />
chmod -R 755 moodle<br />
<br />
If you use cron, take care that cron.php is executeable and uses the correct php command: <br />
chmod 740 admin/cli/cron.php (some configurations need chmod 750 or chmod 755)<br />
copy the first line from cron.php (if it looks like '#!/usr/local/bin/php' or '#!/usr/local/bin/php5.3', no need to copy '<?php') <br />
if necessary. However, for a simple upgrade, there should be no need to change anything with cron.<br />
<br />
=== Using Git ===<br />
<br />
You can use Git for updating or upgrading your Moodle. See [[Git for Administrators]] for details.<br />
<br />
===Command line upgrade===<br />
<br />
On Linux servers, Moodle {{Version}} supports running the [[CLI|upgrade from the command line]], rather than through a web browser. This is likely to be more reliable, particularly for large sites.<br />
<br />
== Finishing the upgrade ==<br />
<br />
The last step is to trigger the upgrade processes within Moodle. <br />
<br />
If you put your site into Maintenance mode earlier; take it out now!<br />
<br />
To do this just go to ''Administration > Site administration > Notifications''.<br />
<br />
Moodle will automatically detect the new version and perform all the SQL database or file system upgrades that are necessary. If there is anything it can't do itself (very rare) then you will see messages telling you what you need to do.<br />
<br />
Assuming all goes well (no error messages) then you can start using your new version of Moodle and enjoy the new features!<br />
<br />
Note: If you are running multiple servers then you should purge all caches manually (via ''Administration > Site administration > Development > Purge all caches'') after completing the upgrade on all servers.<br />
<br />
===Fatal error: Maximum execution time of 30 seconds exceeded...===<br />
<br />
If your server uses a main language other than English, you may encounter a 'Fatal error: Maximum execution time of 30 seconds exceeded' when you try to upgrade it. You can increase max_execution_time = 160 on php.ini to allow the scripts enough time to process the language update. Otherwise, you can switch to English as the default language before doing the upgrade and back to your original language after a succcessful upgrade. See the forum discussion at https://moodle.org/mod/forum/discuss.php?d=119598.<br />
<br />
==After upgrading==<br />
<br />
The config.php file from your installation should work fine but if you take a look at config-dist.php that came with Moodle 3.0 there are more/different options available (e.g. database drivers and settings). It's a good idea to map your old config.php settings to a new one based on the 3.0 config-dist.php.<br />
<br />
===Cron===<br />
<br />
Cron has received a major update (MDL-25499) and now has support for both scheduled and ad hoc tasks.<br />
<br />
The benefits of these changes are:<br />
* The schedule for every task can be configured by the admin<br />
* Tasks can run in parallel<br />
* Cron processes use locking to prevent the same task running at the same time by different processes<br />
* Clusters with multiple identical application nodes are supported, you can run cron on all of them<br />
<br />
A result of this is that cron can be run much more often, which means (for example) forum posts can be sent out sooner. To take advantage of the new cron system it is now strongly recommended that administrators increase the frequency that cron is run to at least ''once per minute''.<br />
<br />
You also may need to modify any automated scripts you have that are parsing the output from cron. It is no longer possible to simply monitor the output of cron for the string "Cron script completed correctly" (if that is what you were doing). An alternative is to monitor the output for the string "task failed:". If you detect that a task is failing, [[Cron#Debugging_Scheduled_Tasks|here]] are some tips for debugging the failure. <br />
<br />
Before the upgrade, there may have been a cron task that was failing, which was preventing the rest of cron from being executed. A failure in any single task will no longer prevent the rest of the Moodle cron tasks from executing, so you may uncover previously masked bugs. It is a good idea to closely monitor the output from cron after the upgrade.<br />
<br />
===Assignments===<br />
<br />
The old assignment (2.2) module has been removed from core and has been replaced by a stub to support transparently remapping URLs and restoring course backups from the old module to the new one. <br />
<br />
If you are still using the old assignment (2.2) module, after upgrading to Moodle 3.0 all assignment (2.2) activities will be hidden. You need to run the [[Assignment upgrade tool]] to un-hide the activities.<br />
<br />
If you really, really need to keep using the old assignment (2.2) module, you should update the code to Moodle 3.0, and then replace the "mod/assignment" folder with the one from https://github.com/moodlehq/moodle-mod_assignment/releases before completing the upgrade.<br />
<br />
==Possible issues that may affect you in Moodle {{Version}}==<br />
<br />
''Please add items here...''<br />
<br />
<br />
See also the list of [https://tracker.moodle.org/issues/?jql=project%20%3D%20mdl%20AND%20resolution%20%3D%20fixed%20AND%20fixVersion%20in%20(%223.7%22)%20AND%20labels%20%3D%20upgrade_notes upgrade_notes-labelled issues] and [https://tracker.moodle.org/issues/?jql=project%20%3D%20mdl%20AND%20resolution%20%3D%20fixed%20AND%20fixVersion%20in%20(%223.7%22)%20AND%20labels%20%3D%20ui_change%20 ui_change-labelled issues]. <br />
<br />
===New capabilities in Moodle {{Version}}===<br />
<br />
'''Assignment'''<br />
* [[Capabilities/mod/assign:showhiddengrader|mod/assign:showhiddengrader]]<br />
<br />
'''Forum'''<br />
* [[Capabilities/mod/forum:canoverridecutoff|mod/forum:canoverridecutoff]]<br />
* [[Capabilities/mod/forum:cantogglefavourite|mod/forum:cantogglefavourite]]<br />
* [[Capabilities/mod/forum:postprivatereply|mod/forum:postprivatereply]]<br />
* [[Capabilities/mod/forum:readprivatereplies|mod/forum:readprivatereplies]]<br />
<br />
'''Analytics'''<br />
* [[Capabilities/moodle/analytics:listowninsights|moodle/analytics:listowninsights]]<br />
<br />
'''Courses'''<br />
* [[Capabilities/moodle/course:changelockedcustomfields|moodle/course:changelockedcustomfields]]<br />
* [[Capabilities/moodle/course:configurecustomfields|moodle/course:configurecustomfields]]<br />
* [[Capabilities/moodle/category:viewcourselist|moodle/category:viewcourselist]]<br />
<br />
'''Privacy'''<br />
* [[Capabilities/tool/dataprivacy:makedatadeletionrequestsforchildren|tool/dataprivacy:makedatadeletionrequestsforchildren]]<br />
* [[Capabilities/tool/dataprivacy:requestdelete|tool/dataprivacy:requestdelete]]<br />
* [[Capabilities/tool/dataprivacy:requestdeleteforotheruser|tool/dataprivacy:requestdeleteforotheruser]]<br />
<br />
=== Moodle 3.2, 3.3, 3.4, 3.5 and 3.6 improvements ===<br />
<br />
Depending on which version you are upgrading from, please see the section 'Possible issues that may affect you' in the documentation<br />
<br />
* [https://docs.moodle.org/32/en/Upgrading Upgrading to Moodle 3.2]<br />
* [https://docs.moodle.org/33/en/Upgrading Upgrading to Moodle 3.3]<br />
* [https://docs.moodle.org/34/en/Upgrading Upgrading to Moodle 3.4]<br />
* [https://docs.moodle.org/35/en/Upgrading Upgrading to Moodle 3.5]<br />
* [https://docs.moodle.org/36/en/Upgrading Upgrading to Moodle 3.6]<br />
<br />
==See also==<br />
<br />
* [[Installation]]<br />
* Using Moodle [http://moodle.org/mod/forum/view.php?id=28 Installation help forum] <br />
* [[dev:Moodle {{Version}} release notes|Moodle {{Version}} release notes]]<br />
<br />
[[es:Actualización de moodle]]<br />
[[fr:Mise à jour]]<br />
[[ja:Moodleをアップグレードする]]<br />
[[de:Aktualisierung von Moodle]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=course/view/topics&diff=133586course/view/topics2019-04-23T09:34:19Z<p>Fox: Correcting redirection</p>
<hr />
<div>#redirect [[Course homepage]]<br />
<br />
[[es:course/view/topics]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=ad-hoc_contributed_reports&diff=133238ad-hoc contributed reports2019-03-07T09:17:11Z<p>Fox: /* How many distinct users connected to Moodle using the app by month */ Use prefix_ (and not mdl_)</p>
<hr />
<div>{{Sitewide reports}}<br />
==User and Role Report==<br />
<br />
===Count number of distinct learners and teachers enrolled per category (including all its sub categories)===<br />
<code sql>SELECT COUNT(DISTINCT lra.userid) AS learners, COUNT(DISTINCT tra.userid) as teachers<br />
FROM prefix_course AS c #, mdl_course_categories AS cats<br />
LEFT JOIN prefix_context AS ctx ON c.id = ctx.instanceid<br />
JOIN prefix_role_assignments AS lra ON lra.contextid = ctx.id<br />
JOIN prefix_role_assignments AS tra ON tra.contextid = ctx.id<br />
JOIN prefix_course_categories AS cats ON c.category = cats.id<br />
WHERE c.category = cats.id<br />
AND (<br />
cats.path LIKE '%/CATEGORYID/%' #Replace CATEGORYID with the category id you want to count (eg: 80)<br />
OR cats.path LIKE '%/CATEGORYID'<br />
)<br />
AND lra.roleid=5<br />
AND tra.roleid=3</code><br />
<br />
===Detailed ACTIONs for each ROLE (TEACHER, NON-EDITING TEACHER and STUDENT)===<br />
<code sql><br />
SELECT r.name, l.action, COUNT( l.userid ) AS counter<br />
FROM prefix_log AS l<br />
JOIN prefix_context AS context ON context.instanceid = l.course AND context.contextlevel = 50<br />
JOIN prefix_role_assignments AS ra ON l.userid = ra.userid AND ra.contextid = context.id<br />
JOIN prefix_role AS r ON ra.roleid = r.id<br />
WHERE ra.roleid IN ( 3, 4, 5 ) <br />
GROUP BY roleid, l.action<br />
</code><br />
<br />
===Student (user) COUNT in each Course===<br />
Including (optional) filter by: year (if included in course fullname).<br />
<code sql><br />
SELECT CONCAT('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',course.id,'">',course.fullname,'</a>') AS Course<br />
,CONCAT('<a target="_new" href="%%WWWROOT%%/user/index.php?contextid=',context.id,'">Show users</a>') AS Users<br />
, COUNT(course.id) AS Students<br />
FROM prefix_role_assignments AS asg<br />
JOIN prefix_context AS context ON asg.contextid = context.id AND context.contextlevel = 50<br />
JOIN prefix_user AS user ON user.id = asg.userid<br />
JOIN prefix_course AS course ON context.instanceid = course.id<br />
WHERE asg.roleid = 5 <br />
# AND course.fullname LIKE '%2013%'<br />
GROUP BY course.id<br />
ORDER BY COUNT(course.id) DESC<br />
</code><br />
<br />
=== Enrolment count in each Course ===<br />
<br />
Shows the total number of enroled users of all roles in each course. Sorted by course name.<br />
<br />
<code sql><br />
SELECT c.fullname, COUNT(ue.id) AS Enroled<br />
FROM prefix_course AS c <br />
JOIN prefix_enrol AS en ON en.courseid = c.id<br />
JOIN prefix_user_enrolments AS ue ON ue.enrolid = en.id<br />
GROUP BY c.id<br />
ORDER BY c.fullname<br />
</code><br />
<br />
===LIST of all site USERS by COURSE enrollment (Moodle 2.x)===<br />
<br />
<code sql><br />
SELECT<br />
user2.firstname AS Firstname,<br />
user2.lastname AS Lastname,<br />
user2.email AS Email,<br />
user2.city AS City,<br />
course.fullname AS Course<br />
,(SELECT shortname FROM prefix_role WHERE id=en.roleid) as Role<br />
,(SELECT name FROM prefix_role WHERE id=en.roleid) as RoleName<br />
<br />
FROM prefix_course as course <br />
JOIN prefix_enrol AS en ON en.courseid = course.id<br />
JOIN prefix_user_enrolments AS ue ON ue.enrolid = en.id<br />
JOIN prefix_user AS user2 ON ue.userid = user2.id<br />
</code><br />
<br />
===Enrolled users,which did not login into the Course, even once (Moodle 2)===<br />
Designed forMoodle 2 table structure and uses special plugin filter : %%FILTER_SEARCHTEXT:table.field%%<br />
<br />
<code sql><br />
SELECT<br />
user2.id as ID,<br />
ul.timeaccess,<br />
user2.firstname AS Firstname,<br />
user2.lastname AS Lastname,<br />
user2.email AS Email,<br />
user2.city AS City,<br />
user2.idnumber AS IDNumber,<br />
user2.phone1 AS Phone,<br />
user2.institution AS Institution,<br />
<br />
IF (user2.lastaccess = 0,'never',<br />
DATE_FORMAT(FROM_UNIXTIME(user2.lastaccess),'%Y-%m-%d')) AS dLastAccess<br />
<br />
,(SELECT DATE_FORMAT(FROM_UNIXTIME(timeaccess),'%Y-%m-%d') FROM prefix_user_lastaccess WHERE userid=user2.id and courseid=c.id) as CourseLastAccess<br />
<br />
,(SELECT r.name<br />
FROM prefix_user_enrolments AS uenrol<br />
JOIN prefix_enrol AS e ON e.id = uenrol.enrolid<br />
JOIN prefix_role AS r ON e.id = r.id<br />
WHERE uenrol.userid=user2.id and e.courseid = c.id) AS RoleName<br />
<br />
FROM prefix_user_enrolments as ue<br />
JOIN prefix_enrol as e on e.id = ue.enrolid<br />
JOIN prefix_course as c ON c.id = e.courseid<br />
JOIN prefix_user as user2 ON user2 .id = ue.userid<br />
LEFT JOIN prefix_user_lastaccess as ul on ul.userid = user2.id<br />
WHERE c.id=16 AND ul.timeaccess IS NULL<br />
%%FILTER_SEARCHTEXT:user2.firstname%%<br />
</code><br />
<br />
===Role assignments on categories===<br />
<code sql><br />
SELECT <br />
concat('<a target="_new" href="%%WWWROOT%%/course/category.php?id=',cc.id,'">',cc.id,'</a>') AS id,<br />
concat('<a target="_new" href="%%WWWROOT%%/course/category.php?id=',cc.id,'">',cc.name,'</a>') AS category,<br />
cc.depth, cc.path, r.name AS role,<br />
concat('<a target="_new" href="%%WWWROOT%%/user/view.php?id=',usr.id,'">',usr.lastname,'</a>') AS name,<br />
usr.firstname, usr.username, usr.email<br />
FROM prefix_course_categories cc<br />
INNER JOIN prefix_context cx ON cc.id = cx.instanceid<br />
AND cx.contextlevel = '40'<br />
INNER JOIN prefix_role_assignments ra ON cx.id = ra.contextid<br />
INNER JOIN prefix_role r ON ra.roleid = r.id<br />
INNER JOIN prefix_user usr ON ra.userid = usr.id<br />
ORDER BY cc.depth, cc.path, usr.lastname, usr.firstname, r.name, cc.name<br />
</code><br />
<br />
===Permissions Overides on Categories===<br />
(By: [http://moodle.org/mod/forum/discuss.php?d=153059#p712834 Séverin Terrier] )<br />
<code sql><br />
SELECT rc.id, ct.instanceid, ccat.name, rc.roleid, rc.capability, rc.permission, <br />
DATE_FORMAT( FROM_UNIXTIME( rc.timemodified ) , '%Y-%m-%d' ) AS timemodified, rc.modifierid, ct.instanceid, ct.path, ct.depth<br />
FROM `prefix_role_capabilities` AS rc<br />
INNER JOIN `prefix_context` AS ct ON rc.contextid = ct.id<br />
INNER JOIN `prefix_course_categories` AS ccat ON ccat.id = ct.instanceid<br />
AND `contextlevel` =40<br />
</code><br />
<br />
===Lists "Totally Opened Courses" (visible, opened to guests, with no password)===<br />
(By: [http://moodle.org/mod/forum/discuss.php?d=153059#p712837 Séverin Terrier] )<br />
<code sql><br />
SELECT<br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.id,'</a>') AS id,<br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.shortname,'</a>') AS 'Course',<br />
concat('<a target="_new" href="%%WWWROOT%%/enrol/instances.php?id=',c.id,'">Méthodes inscription</a>') AS 'Enrollment plugins',<br />
e.sortorder<br />
FROM prefix_enrol AS e, prefix_course AS c<br />
WHERE e.enrol='guest' AND e.status=0 AND e.password='' AND c.id=e.courseid AND c.visible=1<br />
</code><br />
<br />
===Lists "loggedin users" from the last 120 days===<br />
<code sql><br />
SELECT id,username,FROM_UNIXTIME(`lastlogin`) as days <br />
FROM `prefix_user` <br />
WHERE DATEDIFF( NOW(),FROM_UNIXTIME(`lastlogin`) ) < 120<br />
</code><br />
<br />
''and user count for that same population:''<br />
<code sql><br />
SELECT COUNT(id) as Users FROM `prefix_user` <br />
WHERE DATEDIFF( NOW(),FROM_UNIXTIME(`lastlogin`) ) < 120<br />
</code><br />
<br />
==== Users loggedin within the last 7 days ====<br />
<code sql><br />
SELECT<br />
l.* FROM mdl_logstore_standard_log l<br />
WHERE<br />
l.eventname = '\\core\\event\\user_loggedin'<br />
AND FROM_UNIXTIME(l.timecreated, '%Y-%m-%d') >= DATE_SUB(NOW(), INTERVAL 7 DAY)<br />
<br />
SELECT l.eventname FROM mdl_logstore_standard_log l<br />
GROUP BY l.eventname<br />
</code><br />
<br />
===Lists the users who have only logged into the site once===<br />
<code sql><br />
SELECT id, username, firstname, lastname, idnumber<br />
FROM prefix_user<br />
WHERE prefix_user.deleted = 0<br />
AND prefix_user.lastlogin = 0 <br />
AND prefix_user.lastaccess > 0<br />
</code><br />
<br />
===Students in all courses of some institute===<br />
What is the status (deleted or not) of all Students (roleid = 5) in all courses of some Institute<br />
<code sql><br />
SELECT c.id, c.fullname, u.firstname, u.lastname, u.deleted<br />
FROM prefix_course AS c<br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid<br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE ra.roleid =5<br />
AND ctx.instanceid = c.id<br />
AND u.institution = 'please enter school name here'<br />
</code><br />
<br />
===Full User info (for deleted users)===<br />
Including extra custom profile fields (from prefix_user_info_data)<br />
<code sql><br />
SELECT * <br />
FROM prefix_user as u <br />
JOIN prefix_user_info_data as uid ON uid.userid = u.id <br />
JOIN prefix_user_info_field as uif ON (uid.fieldid = uif.id AND uif.shortname = 'class')<br />
WHERE `deleted` = "1" and `institution`="your school name" and `department` = "your department" and `data` = "class level and number"<br />
</code><br />
<br />
===User's courses===<br />
change "u.id = 2" with a new user id<br />
<code sql><br />
SELECT u.firstname, u.lastname, c.id, c.fullname<br />
FROM prefix_course AS c<br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid<br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE u.id = 2<br />
</code><br />
<br />
===List Users with extra info (email) in current course===<br />
blocks/configurable_reports replaces %%COURSEID%% with course id.<br />
<code sql><br />
SELECT u.firstname, u.lastname, u.email<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS context ON context.id = ra.contextid AND context.contextlevel = 50<br />
JOIN prefix_course AS c ON c.id = context.instanceid AND c.id = %%COURSEID%%<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
</code><br />
<br />
===List Students with enrollment and completion dates in current course===<br />
This is meant to be a "global" report in Configurable Reports containing the following:<br />
firstname, lastname, idnumber, institution, department, email, student enrolment date, student completion date<br />
Note: for PGSQL, use to_timestamp() instead of FROM_UNIXTIME()<br />
Contributed by Elizabeth Dalton, Moodle HQ<br />
<br />
<code sql><br />
SELECT <br />
u.firstname<br />
, u.lastname<br />
, u.idnumber<br />
, u.institution<br />
, u.department<br />
, u.email<br />
, FROM_UNIXTIME(cc.timeenrolled)<br />
, FROM_UNIXTIME(cc.timecompleted)<br />
<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS context ON context.id = ra.contextid AND context.contextlevel = 50<br />
JOIN prefix_course AS c ON c.id = context.instanceid AND c.id = %%COURSEID%%<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
JOIN prefix_course_completions AS cc ON cc.course = c.id AND cc.userid = u.id<br />
</code><br />
<br />
===Special Roles===<br />
<code sql><br />
SELECT ra.roleid,r.name<br />
,concat('<a target="_new" href="%%WWWROOT%%/course/user.php?id=1&user=',ra.userid,'">',u.firstname ,' ',u.lastname,'</a>') AS Username<br />
,concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS Course<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_role AS r ON r.id = ra.roleid<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
JOIN prefix_context AS ctx ON (ctx.id = ra.contextid AND ctx.contextlevel = 50)<br />
JOIN prefix_course AS c ON ctx.instanceid = c.id<br />
WHERE ra.roleid > 6<br />
</code><br />
<br />
===Courses without Teachers===<br />
Actually, shows the number of Teachers in a course.<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') as Course<br />
,(SELECT Count( ra.userid ) AS Users FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id) AS Teachers<br />
FROM prefix_course AS c<br />
ORDER BY Teachers ASC<br />
</code><br />
<br />
===List of users who have been enrolled for more than 4 weeks===<br />
For Moodle 2.2 , by Isuru Madushanka Weerarathna <br />
<code sql><br />
SELECT uenr.userid As User, IF(enr.courseid=uenr.courseid ,'Y','N') As Enrolled, <br />
IF(DATEDIFF(NOW(), FROM_UNIXTIME(uenr.timecreated))>=28,'Y','N') As EnrolledMoreThan4Weeks<br />
FROM prefix_enrol As enr, prefix_user_enrolments AS uenr<br />
WHERE enr.id = uenr.enrolid AND enr.status = uenr.status<br />
</code><br />
<br />
=== List of users with language===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
An issue with systems that do not have their default language set up properly is the need to do a mass change for all users to a localization. A common case is changing default English to American English. <br />
<br />
This will show you the language setting for all users:<br />
<code sql><br />
SELECT username, lang from prefix_user <br />
</code><br />
<br />
NOTE: UPDATE commands require the ability to alter the database directly via tools like Adminer or PHPMyAdmin or other db tools.<br />
<br />
This code will change the setting from 'en' to 'en_us' for all users:<br />
<br />
<code sql><br />
UPDATE prefix_user SET lang = 'en_us' WHERE lang = 'en'<br />
</code><br />
<br />
To do this for only users who have a particular country set, use this as an example:<br />
<code sql><br />
UPDATE prefix_user SET lang = 'en_us' WHERE country = 'US' AND lang = 'en'<br />
</code><br />
<br />
=== List of users with Authentication ===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
Sometimes you need to do mass changes of authentication methods. A common case is changing default manual to LDAP. <br />
<br />
This will show you the Authentication setting for all users:<br />
<code sql><br />
SELECT username, auth from prefix_user <br />
</code><br />
<br />
NOTE: UPDATE commands require the ability to alter the database directly via tools like Adminer or PHPMyAdmin or other db tools. <br />
<br />
This code will change the setting from 'manual' to 'ldap' for all users except for the first two accounts which are Guest and Admin. (WARNING: it is bad practice to change your admin account from manual to an external method as failure of that external method will lock you out of Moodle as admin.)<br />
<br />
<code sql><br />
UPDATE prefix_user SET auth = 'ldap' WHERE auth = 'manual' AND id > 2<br />
</code><br />
<br />
=== Compare role capability and permissions ===<br />
<code sql><br />
SELECT DISTINCT mrc.capability <br />
,(SELECT rc.permission FROM `mdl_role_capabilities` AS rc WHERE rc.capability = mrc.capability <br />
AND rc.roleid = '1' AND rc.contextid = '1') AS Manager<br />
,(SELECT rc.permission FROM `mdl_role_capabilities` AS rc WHERE rc.capability = mrc.capability <br />
AND rc.roleid = '2' AND rc.contextid = '1') AS CourseCreator<br />
,(SELECT rc.permission FROM `mdl_role_capabilities` AS rc WHERE rc.capability = mrc.capability <br />
AND rc.roleid = '3' AND rc.contextid = '1') AS Teacher<br />
,(SELECT rc.permission FROM `mdl_role_capabilities` AS rc WHERE rc.capability = mrc.capability <br />
AND rc.roleid = '4' AND rc.contextid = '1') AS AssistantTeacher<br />
,(SELECT rc.permission FROM `mdl_role_capabilities` AS rc WHERE rc.capability = mrc.capability <br />
AND rc.roleid = '5' AND rc.contextid = '1') AS Student<br />
,(SELECT rc.permission FROM `mdl_role_capabilities` AS rc WHERE rc.capability = mrc.capability <br />
AND rc.roleid = '6' AND rc.contextid = '1') AS Guest<br />
<br />
FROM `mdl_role_capabilities` AS mrc<br />
</code><br />
<br />
=== User's accumulative time spent in course ===<br />
A sum up of the time delta between logstore_standard_log user's records, considering the a 2 hour session limit.<br />
<br />
Uses: current user's id %%USERID%% and current course's id %%COURSEID%% <br />
<br />
And also using a date filter (which can be ignored) <br />
<br />
The extra "User" field is used as a dummy field for the Line chart Series field, in which I use X=id, Series=Type, Y=delta.<br />
<br />
<code sql><br />
SELECT <br />
l.id, <br />
l.timecreated, <br />
DATE_FORMAT(FROM_UNIXTIME(l.timecreated),'%d-%m-%Y') AS dTime,<br />
@prevtime := (SELECT max(timecreated) FROM mdl_logstore_standard_log <br />
WHERE userid = %%USERID%% and id < l.id ORDER BY id ASC LIMIT 1) AS prev_time,<br />
IF (l.timecreated - @prevtime < 7200, @delta := @delta + (l.timecreated-@prevtime),0) AS sumtime,<br />
l.timecreated-@prevtime AS delta,<br />
"User" as type<br />
<br />
FROM prefix_logstore_standard_log as l, <br />
(SELECT @delta := 0) AS s_init <br />
# Change UserID<br />
WHERE l.userid = %%USERID%% AND l.courseid = %%COURSEID%%<br />
%%FILTER_STARTTIME:l.timecreated:>%% %%FILTER_ENDTIME:l.timecreated:<%% <br />
</code><br />
<br />
=== Low-Participation Student Report ===<br />
Contributed by Elizabeth Dalton, Granite State College / Moodle HQ<br />
<br />
This report returns a list of students who are enrolled in courses filtered by a short-name text marker (in this case "OL-") in the specified category, but have very low participation in the course during the specified time period (fewer than 2 "Edits" to Activity Modules, indicating few active contributions to the course). The number of "Edits" is provided for each student for the time period specified.<br />
<br />
An "Edit" is defined as course activity other than viewing content. Click the "Logs" link to review the student activity. The Logs offer the option to review "View" activity as well as "Edit" activity.<br />
<br />
Only "visible" courses are included in this report. The report may be downloaded as an Excel spreadsheet.<br />
<br />
Don't forget to set up Filters: "Start / End date filter" and "Filter categories" on the Filters tab in Configurable reports.<br />
<br />
<code sql><br />
SELECT u.lastname AS Last, u.firstname AS First, u.idnumber AS IDnumber, u.email AS email, c.shortname AS CourseID, count(l.id) AS Edits, CONCAT('<a target="_new" href="https://learn.granite.edu/report/log/index.php',CHAR(63),'chooselog=1&showusers=1&showcourses=0&id=',c.id,'&user=',u.id,'&date=0&modid=&modaction=-view&logformat=showashtml','">','Logs','</a>') AS Link<br />
<br />
FROM prefix_user AS u<br />
JOIN prefix_role_assignments AS ra ON u.id = ra.userid<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
<br />
LEFT JOIN prefix_log AS l ON l.userid = u.id AND l.course = c.id AND l.action NOT LIKE "view%" %%FILTER_STARTTIME:l.TIME:>%% %%FILTER_ENDTIME:l.TIME:<%%<br />
<br />
WHERE ra.roleid =5<br />
AND ctx.instanceid = c.id<br />
AND c.visible=1<br />
# This prefix filter allows the exclusion of non-online courses at the original institution. Alter this to fit your institution, or remove it.<br />
AND c.shortname LIKE '%OL-%'<br />
%%FILTER_CATEGORIES:c.category%%<br />
<br />
GROUP BY u.idnumber<br />
<br />
HAVING Edits < 2<br />
</code><br />
<br />
=== Messages of All Users in a Specific Course ===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
NOTE: This query will probably not work at all in 3.5 now due to the changes in the structure of the Messages database. - RT<br />
<br />
This query shows the personal messages between users in a specific course, given the course id number. Properly speaking, personal messages pertain only to users and are not part of courses, but by filtering enrollments for roles in a course, you can show this. <br />
<br />
This report as is shows only the messages between Teachers and Students, as the WHERE statement contains and AND ((...))) section that restrict this report to ONLY messages between Teachers (role id = 3) and Students (role id =5). Remove that part of the statement if you wish to see _all_ messages between all users, e.g. teachers to teachers, student to student. <br />
<br />
Also, if you have created custom roles, you can replace the default id numbers with custom ones to further enhance the report.<br />
<br />
<code sql><br />
SELECT <br />
u.username AS 'From',<br />
CONCAT(u.firstname ,' ',u.lastname) AS 'From Name',<br />
u2.username AS 'To',<br />
CONCAT(u2.firstname ,' ',u2.lastname) AS 'To Name',<br />
DATE_FORMAT(FROM_UNIXTIME(me.timecreated), '%Y-%m-%d %H:%i') AS 'When',<br />
me.subject AS 'Subject', <br />
me.smallmessage AS 'Message'<br />
FROM prefix_message me<br />
JOIN prefix_role_assignments AS ra ON ra.userid = me.useridfrom AND ra.roleid IN (3,4,5) <br />
JOIN prefix_role_assignments AS ra2 ON ra2.userid = me.useridto AND ra2.roleid IN (3,4,5) <br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id AND ra2.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
JOIN prefix_user u ON u.id = me.useridfrom<br />
JOIN prefix_user u2 ON u2.id = me.useridto<br />
WHERE c.id=## <br />
AND ((ra.roleid = 3 AND ra2.roleid = 5) OR (ra.roleid = 5 AND ra2.roleid = 3)) <br />
ORDER BY me.useridfrom, me.useridto, me.timecreated<br />
</code><br />
<br />
==Log Activity Reports==<br />
===Count all Active Users by ROLE in a course category (including all of its sub-categories)===<br />
<code sql><br />
SELECT COUNT(DISTINCT l.userid) as active<br />
FROM mdl_course as c<br />
JOIN mdl_context AS ctx ON ctx.instanceid=c.id<br />
JOIN mdl_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN mdl_user_lastaccess as l ON ra.userid = l.userid<br />
JOIN mdl_course_categories AS cats ON c.category = cats.id<br />
WHERE c.category=cats.id AND (<br />
cats.path LIKE '%/80/%'<br />
OR cats.path LIKE '%/80'<br />
) <br />
AND ra.roleid=3 AND ctx.contextlevel=50 #ra.roleid= TEACHER 3, NON-EDITING TEACHER 4, STUDENT 5<br />
AND l.timeaccess > (unix_timestamp() - ((60*60*24)*NO_OF_DAYS)) #NO_OF_DAYS change to number<br />
</code><br />
===Detailed "VIEW" ACTION for each ROLE (TEACHER,NONE-EDITING TEACHER and STUDENT)===<br />
<code sql><br />
SELECT l.action, count( l.userid ) as counter , r.name<br />
FROM `prefix_log` as l<br />
JOIN `prefix_role_assignments` AS ra on l.userid = ra.userid<br />
JOIN `prefix_role` AS r ON ra.roleid = r.id<br />
WHERE (ra.roleid IN (3,4,5)) AND (l.action LIKE '%view%' )<br />
GROUP BY roleid,l.action<br />
order by r.name,counter desc<br />
</code><br />
<br />
===Total Activity of Roles:"Teacher" and "None-Editing Teacher" by Dates and by Hours===<br />
The output columns of this report table can be used as base for a Pivot-Table<br />
which will show the amount of '''activity''' per '''hour''' per '''days''' in 3D graph view.<br />
<br />
<code sql><br />
SELECT DATE_FORMAT( FROM_UNIXTIME( l.time ) , '%Y-%m-%d' ) AS grptimed ,<br />
DATE_FORMAT( FROM_UNIXTIME( l.time ) , '%k' ) AS grptimeh , count( l.userid ) AS counter <br />
FROM `prefix_log` AS l<br />
JOIN prefix_user AS u ON u.id = l.userid<br />
JOIN prefix_role_assignments AS ra ON l.userid = ra.userid<br />
JOIN prefix_role AS r ON r.id = ra.roleid<br />
WHERE ra.roleid IN (3,4)<br />
GROUP BY grptimed,grptimeh<br />
ORDER BY grptimed,grptimeh<br />
</code><br />
<br />
===How many LOGINs per user and user's Activity===<br />
+ link username to a user activity graph report<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/user.php?id=1&user=',u.id,'&mode=alllogs">',u.firstname ,' ',u.lastname,'</a>') as Username<br />
,count(*) as logins<br />
,(SELECT count(*) FROM prefix_log WHERE userid = l.userid GROUP BY userid) as Activity <br />
FROM prefix_log as l JOIN prefix_user as u ON l.userid = u.id <br />
WHERE `action` LIKE '%login%' group by userid<br />
ORDER BY Activity DESC<br />
</code><br />
===Distinct user logins per month===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
The following will show you the months of the current calendar year with the total number of distinct, unique user logins per month. Change the year in the WHERE clause to the year you need.<br />
<br />
<code sql><br />
SELECT <br />
COUNT(DISTINCT l.userid) AS 'DistinctUserLogins', <br />
DATE_FORMAT(FROM_UNIXTIME(l.timecreated), '%M') AS 'Month'<br />
FROM prefix_logstore_standard_log l<br />
WHERE l.action = 'loggedin' AND YEAR(FROM_UNIXTIME(l.timecreated)) = '2017' <br />
GROUP BY MONTH(FROM_UNIXTIME(l.timecreated))<br />
</code><br />
<br />
===Total activity per course, per unique user on the last 24h===<br />
<code sql><br />
SELECT<br />
COUNT(DISTINCT userid) AS countUsers<br />
, COUNT(l.courseid) AS countVisits<br />
, CONCAT('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">', c.fullname, '</a>') AS Course<br />
<br />
FROM mdl_logstore_standard_log AS l<br />
JOIN mdl_course AS c ON c.id = l.courseid<br />
WHERE l.courseid > 0<br />
AND FROM_UNIXTIME(l.timecreated) >= DATE_SUB(NOW(), INTERVAL 1 DAY)<br />
AND c.fullname LIKE '%תשעו%'<br />
GROUP BY l.courseid<br />
ORDER BY countVisits DESC<br />
</code><br />
<br />
===Weekly Instructor Online Participation===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
Displays participation of instructors in all courses per week of a term, including pre-term and post-term edits. An edit is defined as a change to the course, such as a discussion post, the grading of an assignment, or the uploading of file attachments, as well as alterations to course content.<br />
<br />
* To specify a subject and/or course number, use % as a wildcard, e.g. ARTS% or ARTS501%<br />
* To match part of a last name, use %, e.g. Smi% will match "Smith", "Smile", etc.<br />
<br />
At our institution, we include filters on the course name or category to constrain by terms. These are very specific to how course names and categories are constructed at our institution, so I've removed those elements from this code. Also, our terms are 12 weeks long. You would want to insert additional "SUM" lines for longer terms, or remove lines for shorter terms.<br />
<br />
'''Note''': This report can take a long time to run. While it can be run in Configurable Reports on demand, it may be more appropriate to implement it in the Ad Hoc Queries plugin as a scheduled report.<br />
<br />
'''Note''': This version uses legacy (pre-2.7) logs. See below for post-2.7 Standard Logs version.<br />
<br />
<code sql><br />
SELECT <br />
c.shortname AS CourseID<br />
, cc.name AS Category<br />
, CONCAT(u.firstname ,' ',u.lastname) AS Instructor<br />
<br />
, (SELECT COUNT( ra2.userid ) AS Users2 FROM prefix_role_assignments AS ra2<br />
JOIN prefix_context AS ctx2 ON ra2.contextid = ctx2.id<br />
WHERE ra2.roleid = 5 AND ctx2.instanceid = c.id) AS Students<br />
<br />
, c.startdate AS Course_Start_Date<br />
<br />
, c.visible AS Visible<br />
<br />
, COUNT(l.id) AS Edits<br />
<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time)) - WEEK(FROM_UNIXTIME(c.startdate))<0,1,0)) AS BeforeTerm<br />
<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=0,1,0)) AS Week1<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=1,1,0)) AS Week2<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=2,1,0)) AS Week3<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=3,1,0)) AS Week4<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=4,1,0)) AS Week5<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=5,1,0)) AS Week6<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=6,1,0)) AS Week7<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=7,1,0)) AS Week8<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=8,1,0)) AS Week9<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=9,1,0)) AS Week10<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=10,1,0)) AS Week11<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=11,1,0)) AS Week12<br />
<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))>=12,1,0)) AS AfterTerm<br />
<br />
, CONCAT('<a target="_new" href="%%WWWROOT%%/report/log/index.php',CHAR(63),'chooselog=1&showusers=1&showcourses=0&id=',c.id,'&user=',u.id,'&date=0&modid=&modaction=&logformat=showashtml','">','Logs','</a>') AS Link<br />
<br />
FROM prefix_user AS u<br />
JOIN prefix_role_assignments AS ra ON u.id = ra.userid<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
JOIN prefix_course_categories as cc ON c.category = cc.id<br />
<br />
LEFT JOIN prefix_log AS l ON l.userid = u.id AND l.course = c.id AND l.action NOT LIKE "view%"<br />
<br />
WHERE ra.roleid =3<br />
AND ctx.instanceid = c.id<br />
AND c.shortname LIKE :course<br />
AND u.lastname LIKE :last_name<br />
<br />
GROUP BY u.idnumber, c.id<br />
HAVING students > 0<br />
ORDER BY c.shortname<br />
</code><br />
<br />
'''Note''': Post-2.7 log version:<br />
<br />
<code sql><br />
SELECT <br />
c.shortname AS CourseID<br />
, cc.name AS Category<br />
, CONCAT(u.firstname ,' ',u.lastname) AS Instructor<br />
<br />
, (SELECT COUNT( ra2.userid ) AS Users2 FROM prefix_role_assignments AS ra2<br />
JOIN prefix_context AS ctx2 ON ra2.contextid = ctx2.id<br />
WHERE ra2.roleid = 5 AND ctx2.instanceid = c.id) AS Students<br />
<br />
, FROM_UNIXTIME(c.startdate) AS Course_Start_Date<br />
<br />
, c.visible AS Visible<br />
<br />
, COUNT(DISTINCT l.id) AS Edits<br />
<br />
, COUNT(DISTINCT IF((l.timecreated-c.startdate)<0,l.id,NULL)) AS 'Before Term'<br />
<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=0,l.id,NULL)) AS 'Week 1'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=1,l.id,NULL)) AS 'Week 2'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=2,l.id,NULL)) AS 'Week 3'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=3,l.id,NULL)) AS 'Week 4'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=4,l.id,NULL)) AS 'Week 5'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=5,l.id,NULL)) AS 'Week 6'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=6,l.id,NULL)) AS 'Week 7'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=7,l.id,NULL)) AS 'Week 8'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=8,l.id,NULL)) AS 'Week 9'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=9,l.id,NULL)) AS 'Week 10'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=10,l.id,NULL)) AS 'Week 11'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=11,l.id,NULL)) AS 'Week 12'<br />
<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))>=12,l.id,NULL)) AS 'After Term'<br />
<br />
, CONCAT('<a target="_new" href="%%WWWROOT%%/report/log/index.php',CHAR(63),'chooselog=1&showusers=1&showcourses=0&id=',c.id,'&user=',u.id,'&date=0&modid=&modaction=&logformat=showashtml','">','Logs','</a>') AS Link<br />
<br />
FROM prefix_user AS u<br />
LEFT JOIN prefix_role_assignments AS ra ON u.id = ra.userid<br />
LEFT JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
LEFT JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
LEFT JOIN prefix_course_categories as cc ON c.category = cc.id<br />
<br />
LEFT JOIN prefix_logstore_standard_log AS l ON l.userid = u.id AND l.courseid = c.id AND l.crud IN ('c','u')<br />
<br />
WHERE ra.roleid =3<br />
AND ctx.instanceid = c.id<br />
AND c.shortname LIKE '%OL-%'<br />
AND cc.idnumber LIKE '%current%'<br />
<br />
GROUP BY u.idnumber, c.id<br />
#HAVING students > 0<br />
ORDER BY RIGHT(c.shortname,2), c.shortname<br />
</code><br />
<br />
===Weekly Student Online Participation===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
Displays participation of students in the current course by week, including pre-term and post-term edits. An edit is defined as a change to the course, such as a discussion post, the submission of an assignment, or the completion of a quiz, as well as alterations to course content such as database entries (if permitted).<br />
<br />
Links to three other reports are also provided:<br />
<br />
* Logs: complete log entries for the student in the course, organized by date<br />
* Activity Outline: the "Outline Report" from the User Activity Reports, summarizing the student's activity in the course, organized by course content<br />
* Consolidated Activity Report: the "Complete Report" from the User Activity Reports, detailing the student's activity in the course, organized by course content (includes text of forum posts)<br />
<br />
'''Note''': This should be defined as a "Global" report (visible from within all courses). At our institution, our terms are 12 weeks long. You would want to insert additional "SUM" lines for longer terms, or remove lines for shorter terms. We pull advisor names into student user profiles as part of our configuration. These lines are present in the code below, but are commented out, as they are very specific to your Moodle configuration.<br />
<br />
'''Note''': This version of the report uses legacy (pre-2.7) logs. See below for a post-2.7 Standard Logs version.<br />
<br />
<code sql><br />
SELECT <br />
u.lastname AS 'Last Name'<br />
, u.firstname AS 'First Name'<br />
, COUNT(l.id) AS 'Edits'<br />
<br />
, SUM(IF((l.time-c.startdate)/7<0,1,0)) AS 'Before Term'<br />
<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=0,1,0)) AS 'Week 1'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=1,1,0)) AS 'Week 2'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=2,1,0)) AS 'Week 3'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=3,1,0)) AS 'Week 4'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=4,1,0)) AS 'Week 5'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=5,1,0)) AS 'Week 6'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=6,1,0)) AS 'Week 7'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=7,1,0)) AS 'Week 8'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=8,1,0)) AS 'Week 9'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=9,1,0)) AS 'Week 10'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=10,1,0)) AS 'Week 11'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=11,1,0)) AS 'Week 12'<br />
<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))>=15,1,0)) AS 'After Term'<br />
<br />
, CONCAT('<a target="_blank" href="%%WWWROOT%%/report/log/index.php',CHAR(63),'chooselog=1&showusers=1&showcourses=0&id=',c.id,'&user=',u.id,'&date=0&modid=&modaction=&logformat=showashtml','">','Logs','</a>') AS 'Logs'<br />
<br />
, CONCAT('<a target="_blank" href="%%WWWROOT%%/report/outline/user.php',CHAR(63),'id=',u.id,'&course=',c.id,'&mode=outline">','Outline','</a>') AS 'Activity Outline'<br />
<br />
, CONCAT('<a target="_blank" href="%%WWWROOT%%/report/outline/user.php',CHAR(63),'id=',u.id,'&course=',c.id,'&mode=complete">','Activity','</a>') AS 'Consolidated Activity'<br />
<br />
FROM prefix_user AS u<br />
JOIN prefix_role_assignments AS ra ON u.id = ra.userid<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
JOIN prefix_course_categories as cc ON c.category = cc.id<br />
<br />
LEFT JOIN prefix_log AS l ON l.userid = u.id AND l.course = c.id AND l.action NOT LIKE "view%"<br />
<br />
WHERE ra.roleid =5<br />
AND ctx.instanceid = c.id<br />
<br />
AND c.id = %%COURSEID%%<br />
<br />
GROUP BY u.idnumber<br />
<br />
ORDER BY u.lastname, u.firstname<br />
</code><br />
<br />
'''Note''': Post-2.7 (Standard Logs) version<br />
<br />
<code sql><br />
SELECT <br />
u.lastname AS 'Last Name'<br />
, u.firstname AS 'First Name'<br />
, COUNT(l.id) AS 'Edits'<br />
<br />
, COUNT(DISTINCT IF((l.timecreated-c.startdate)<0,l.id,NULL)) AS 'Before Term'<br />
<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=0,l.id,NULL)) AS 'Week 1'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=1,l.id,NULL)) AS 'Week 2'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=2,l.id,NULL)) AS 'Week 3'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=3,l.id,NULL)) AS 'Week 4'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=4,l.id,NULL)) AS 'Week 5'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=5,l.id,NULL)) AS 'Week 6'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=6,l.id,NULL)) AS 'Week 7'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=7,l.id,NULL)) AS 'Week 8'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=8,l.id,NULL)) AS 'Week 9'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=9,l.id,NULL)) AS 'Week 10'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=10,l.id,NULL)) AS 'Week 11'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=11,l.id,NULL)) AS 'Week 12'<br />
<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))>=12,l.id,NULL)) AS 'After Term'<br />
<br />
# Our institution stores academic advisor names and emails in custom profile fields<br />
#, CONCAT('<a href="mailto:',uce.data,'">',uid.data, '</a>') AS 'Academic Advisor'<br />
<br />
, CONCAT('<a target="_blank" href="%%WWWROOT%%/report/log/index.php',CHAR(63),'chooselog=1&showusers=1&showcourses=0&id=',c.id,'&user=',u.id,'&date=0&modid=&modaction=&logformat=showashtml','">','Logs','</a>') AS 'Logs'<br />
<br />
, CONCAT('<a target="_blank" href="%%WWWROOT%%/report/outline/user.php',CHAR(63),'id=',u.id,'&course=',c.id,'&mode=outline">','Outline','</a>') AS 'Activity Outline'<br />
<br />
, CONCAT('<a target="_blank" href="%%WWWROOT%%/report/outline/user.php',CHAR(63),'id=',u.id,'&course=',c.id,'&mode=complete">','Activity','</a>') AS 'Consolidated Activity'<br />
<br />
, CONCAT('<a target="_blank" href="%%WWWROOT%%/mod/forum/user.php',CHAR(63),'id=',u.id,'&course=',c.id,'">','Posts','</a>') AS 'Posts'<br />
<br />
FROM prefix_user AS u<br />
JOIN prefix_role_assignments AS ra ON u.id = ra.userid<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
JOIN prefix_course_categories as cc ON c.category = cc.id<br />
<br />
# student academic coach - you can include custom profile field data with these methods<br />
# LEFT JOIN prefix_user_info_data as uid ON u.id = uid.userid AND uid.fieldid = '2'<br />
# student academic coach email<br />
# LEFT JOIN prefix_user_info_data as uce on u.id = uce.userid AND uce.fieldid = '6'<br />
<br />
LEFT JOIN prefix_logstore_standard_log AS l ON l.userid = u.id AND l.courseid = c.id AND l.crud IN ('c','u')<br />
<br />
WHERE ra.roleid =5<br />
AND ctx.instanceid = c.id<br />
<br />
AND c.id = %%COURSEID%%<br />
<br />
GROUP BY u.idnumber<br />
<br />
ORDER BY u.lastname, u.firstname<br />
</code><br />
<br />
===My Weekly Online Participation===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
Displays participation of the '''current user''' in the '''current course''' by week, including pre-term and post-term submissions/edits. A submission/edit is defined as a change to the course, such as a discussion post, the submission of an assignment, or the completion of a quiz, as well as alterations to course content such as database entries or new course activities or resources (if permitted).<br />
<br />
This report uses Standard Logs (post 2.7).<br />
<br />
<code sql><br />
SELECT <br />
<br />
l.component AS 'activity'<br />
<br />
, COUNT(DISTINCT IF((l.timecreated-c.startdate)<0,l.id,NULL)) AS 'Before Term'<br />
<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=0,l.id,NULL)) AS 'Week 1'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=1,l.id,NULL)) AS 'Week 2'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=2,l.id,NULL)) AS 'Week 3'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=3,l.id,NULL)) AS 'Week 4'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=4,l.id,NULL)) AS 'Week 5'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=5,l.id,NULL)) AS 'Week 6'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=6,l.id,NULL)) AS 'Week 7'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=7,l.id,NULL)) AS 'Week 8'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=8,l.id,NULL)) AS 'Week 9'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=9,l.id,NULL)) AS 'Week 10'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=10,l.id,NULL)) AS 'Week 11'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=11,l.id,NULL)) AS 'Week 12'<br />
<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))>=12,l.id,NULL)) AS 'After Term'<br />
<br />
, COUNT(l.id) AS 'Total'<br />
<br />
FROM prefix_user AS u<br />
JOIN prefix_role_assignments AS ra ON u.id = ra.userid<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
JOIN prefix_course_categories as cc ON c.category = cc.id<br />
<br />
LEFT JOIN prefix_logstore_standard_log AS l ON l.userid = u.id AND l.courseid = c.id AND l.crud IN ('c','u')<br />
<br />
WHERE 1<br />
AND ctx.instanceid = c.id<br />
<br />
AND c.id = %%COURSEID%%<br />
AND u.id = %%USERID%%<br />
<br />
GROUP BY l.component<br />
<br />
ORDER BY l.component<br />
</code><br />
<br />
===Faculty/Student Interactions===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
Returns a count of instructor and other-student responses to student activity for the specified time period. This report can help indicate whether students' comments are being responded to, as well as summarizing post activity by students during the specified time.<br />
<br />
'''Note''': This version of the report uses legacy (pre-2.7) logs. See below for the post-2.7 Standard Logs version.<br />
<br />
'''Note''': This should be defined as a "Global" report (visible from within all courses). <br />
<br />
'''Note''': This report can take a long time to run. <br />
<br />
<br />
<code sql><br />
SELECT <br />
<br />
# Identify student<br />
CONCAT('<a target="_blank" href="%%WWWROOT%%/message/index.php?id=' , allstu.id , '">' , allstu.firstname , ' ' , allstu.lastname , '</a>' ) AS 'Student - click to send message'<br />
<br />
, IF((COUNT(DISTINCT IF(fps.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fps.id,NULL) )>0) OR (COUNT(DISTINCT IF(asb.timemodified > (UNIX_TIMESTAMP() - (7*24*60*60)),asb.id,NULL))>0) OR (SELECT COUNT(DISTINCT mfs.id) FROM prefix_message AS mfs WHERE mfs.useridfrom = allstu.id AND mfs.useridto = instr.id AND mfs.timecreated > (UNIX_TIMESTAMP() - (7*24*60*60))),'YES','NO') AS 'Student Participated This week'<br />
<br />
, IF((COUNT(DISTINCT IF(fpi.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpi.id,NULL) )>0) OR (COUNT(DISTINCT IF(asg.timemodified > (UNIX_TIMESTAMP() - (7*24*60*60)),asg.id,NULL))>0) OR (SELECT COUNT(DISTINCT mts.id) FROM prefix_message AS mts WHERE mts.useridfrom = instr.id AND mts.useridto = allstu.id AND mts.timecreated > (UNIX_TIMESTAMP() - (7*24*60*60))),'YES','NO') AS 'Student Contacted This week'<br />
<br />
## Only posts within last 7 days<br />
<br />
# Count posts by student<br />
, COUNT(DISTINCT IF(fps.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fps.id,NULL)) AS 'Forum Stu Posts - 7 days'<br />
<br />
# Count replies to student posts by instructors<br />
, COUNT(DISTINCT IF(fpi.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpi.id,NULL) ) AS 'Forum Instr Replies - 7 days'<br />
<br />
# using link back to student posts on replies, get unique student IDs responded<br />
, COUNT(DISTINCT IF(fpsr.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpsr.id,NULL)) - COUNT(DISTINCT IF(fpi.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpi.id,NULL) ) AS 'Forum Stu Replies - 7 days'<br />
<br />
# all replies<br />
, COUNT(DISTINCT IF(fpsr.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpsr.id,NULL)) AS 'Forum All Replies - 7 days'<br />
<br />
# add in count of graded assignments - 7 days<br />
, COUNT(DISTINCT IF(asb.timemodified > (UNIX_TIMESTAMP() - (7*24*60*60)),asb.id,NULL)) AS 'Assign Submit - 7 days'<br />
, COUNT(DISTINCT IF(asg.timemodified > (UNIX_TIMESTAMP() - (7*24*60*60)),asg.id,NULL)) AS 'Assign Grades - 7 days'<br />
<br />
# Messages between students and instructors - 7 days<br />
, (SELECT COUNT(DISTINCT mfs.id) FROM prefix_message AS mfs WHERE mfs.useridfrom = allstu.id AND mfs.useridto = instr.id AND mfs.timecreated > (UNIX_TIMESTAMP() - (7*24*60*60))) AS 'Msg Stu to Instr - 7 days'<br />
, (SELECT COUNT(DISTINCT mts.id) FROM prefix_message AS mts WHERE mts.useridfrom = instr.id AND mts.useridto = allstu.id AND mts.timecreated > (UNIX_TIMESTAMP() - (7*24*60*60))) AS 'Msg Instr to Stu - 7 days'<br />
<br />
## All posts in course so far<br />
# Count posts by student<br />
, COUNT(DISTINCT fps.id) AS 'Forum Stu Posts - to date'<br />
<br />
# Count replies to student posts by instructors<br />
, COUNT(DISTINCT fpi.id) AS 'Forum Instr Replies - to date'<br />
<br />
# using link back to student posts on replies, get unique student IDs responded<br />
, COUNT(DISTINCT fpsr.id) - COUNT(DISTINCT fpi.id) AS 'Forum Stu Replies - to date'<br />
<br />
# all replies<br />
, COUNT(DISTINCT fpsr.id) AS 'Forum All Replies - to date'<br />
<br />
# add in count of graded assignments - whole course<br />
, COUNT(DISTINCT asb.id) AS 'Assign Submit - to date'<br />
, COUNT(DISTINCT asg.id) AS 'Assign Grades - to date'<br />
<br />
# Messages between students and instructors - to date<br />
, (SELECT COUNT(DISTINCT mfs.id) FROM prefix_message AS mfs WHERE mfs.useridfrom = allstu.id AND mfs.useridto = instr.id ) AS 'Msg Stu to Instr - to date'<br />
, (SELECT COUNT(DISTINCT mts.id) FROM prefix_message AS mts WHERE mts.useridfrom = instr.id AND mts.useridto = allstu.id) AS 'Msg Instr to Stu - to date'<br />
<br />
## JOINS<br />
<br />
# Start by getting all the students in the course<br />
FROM prefix_user AS allstu <br />
JOIN prefix_role_assignments AS ras ON allstu.id = ras.userid AND ras.roleid = 5<br />
JOIN prefix_context AS ctx ON ras.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
JOIN prefix_course_categories as cc ON c.category = cc.id<br />
<br />
# Now we get the forums and forum discussions from this course only<br />
LEFT JOIN prefix_forum AS frm ON frm.course = c.id AND c.id = %%COURSEID%%<br />
LEFT JOIN prefix_forum_discussions AS fd ON fd.course = %%COURSEID%% AND fd.forum = frm.id<br />
<br />
# These are forum discussion posts just by students within specified time<br />
LEFT JOIN prefix_forum_posts AS fps ON fps.userid = allstu.id AND fps.discussion = fd.id<br />
<br />
# Separately, we connect the instructors of the courses<br />
# We can use the context we have already gotten for the students<br />
LEFT JOIN prefix_role_assignments AS rai ON rai.contextid = ctx.id<br />
LEFT JOIN prefix_user AS instr ON instr.id = rai.userid AND rai.roleid =3<br />
<br />
# Now we will connect to posts by instructors that are replies to student posts<br />
# This is a left join, because we don't want to eliminate any students from the list<br />
LEFT JOIN prefix_forum_posts AS fpi ON fpi.discussion = fd.id AND fpi.userid = instr.id AND fpi.parent = fps.id<br />
<br />
# To get identities of only those students who were replied to:<br />
# Connect from instr replies back up to parent posts by students again<br />
# This has to be a LEFT JOIN, we know these posts exist but don't eliminate non-responded students<br />
LEFT JOIN prefix_forum_posts AS fpir ON fpir.id = fpi.parent<br />
<br />
# We also want to know if students are replying to one another<br />
# These are posts that are replies to student posts<br />
# Again, a left join<br />
LEFT JOIN prefix_forum_posts AS fpsr ON fpsr.discussion = fd.id AND fpsr.parent = fps.id<br />
<br />
# get the activity modules<br />
LEFT JOIN prefix_course_modules AS cm ON c.id = cm.course<br />
<br />
# get the assignments<br />
LEFT JOIN prefix_assign AS a ON cm.instance = a.id<br />
LEFT JOIN prefix_assign_submission AS asb ON a.id = asb.assignment AND asb.userid=allstu.id <br />
LEFT JOIN prefix_assign_grades AS asg ON asg.assignment = a.id AND asg.userid = allstu.id AND asg.assignment = asb.assignment <br />
<br />
# We care about messages that involve both the instructor and students of this course<br />
# messages from instructor to students:<br />
# LEFT JOIN prefix_message AS mts ON mts.useridfrom = instr.id AND mts.useridto = allstu.id<br />
# LEFT JOIN prefix_message AS mfs ON mfs.useridfrom = instr.id AND mfs.useridto = allstu.id<br />
<br />
WHERE <br />
c.id = %%COURSEID%% <br />
<br />
# GROUP BY c.shortname , allstu.id<br />
GROUP BY allstu.id<br />
<br />
ORDER BY allstu.lastname<br />
</code><br />
<br />
'''Note''': Post-2.7 Standard Logs version<br />
<br />
<code sql><br />
SELECT <br />
<br />
# Identify student<br />
CONCAT('<a target="_blank" href="%%WWWROOT%%/message/index.php?id=' , allstu.id , '">' , allstu.firstname , ' ' , allstu.lastname , '</a>' ) AS 'Student - click to send message'<br />
<br />
, IF((COUNT(DISTINCT IF(fps.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fps.id,NULL) )>0) OR (COUNT(DISTINCT IF(asb.timemodified > (UNIX_TIMESTAMP() - (7*24*60*60)),asb.id,NULL))>0) OR (SELECT COUNT(DISTINCT mfs.id) FROM prefix_message AS mfs WHERE mfs.useridfrom = allstu.id AND mfs.useridto = instr.id AND mfs.timecreated > (UNIX_TIMESTAMP() - (7*24*60*60))),'YES','NO') AS 'Student Participated This week'<br />
<br />
, IF((COUNT(DISTINCT IF(fpi.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpi.id,NULL) )>0) OR (COUNT(DISTINCT IF(asg.timemodified > (UNIX_TIMESTAMP() - (7*24*60*60)),asg.id,NULL))>0) OR (SELECT COUNT(DISTINCT mts.id) FROM prefix_message AS mts WHERE mts.useridfrom = instr.id AND mts.useridto = allstu.id AND mts.timecreated > (UNIX_TIMESTAMP() - (7*24*60*60))),'YES','NO') AS 'Student Contacted This week'<br />
<br />
## Only posts within last 7 days<br />
<br />
# Count posts by student<br />
, COUNT(DISTINCT IF(fps.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fps.id,NULL)) AS 'Forum Stu Posts - 7 days'<br />
<br />
# Count replies to student posts by instructors<br />
, COUNT(DISTINCT IF(fpi.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpi.id,NULL) ) AS 'Forum Instr Replies - 7 days'<br />
<br />
# using link back to student posts on replies, get unique student IDs responded<br />
, COUNT(DISTINCT IF(fpsr.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpsr.id,NULL)) - COUNT(DISTINCT IF(fpi.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpi.id,NULL) ) AS 'Forum Stu Replies - 7 days'<br />
<br />
# all replies<br />
, COUNT(DISTINCT IF(fpsr.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpsr.id,NULL)) AS 'Forum All Replies - 7 days'<br />
<br />
# add in count of graded assignments - 7 days<br />
, COUNT(DISTINCT IF(asb.timemodified > (UNIX_TIMESTAMP() - (7*24*60*60)),asb.id,NULL)) AS 'Assign Submit - 7 days'<br />
, COUNT(DISTINCT IF(asg.timemodified > (UNIX_TIMESTAMP() - (7*24*60*60)),asg.id,NULL)) AS 'Assign Grades - 7 days'<br />
<br />
# Messages between students and instructors - 7 days<br />
, (SELECT COUNT(DISTINCT mfs.id) FROM prefix_message AS mfs WHERE mfs.useridfrom = allstu.id AND mfs.useridto = instr.id AND mfs.timecreated > (UNIX_TIMESTAMP() - (7*24*60*60))) AS 'Msg Stu to Instr - 7 days'<br />
, (SELECT COUNT(DISTINCT mts.id) FROM prefix_message AS mts WHERE mts.useridfrom = instr.id AND mts.useridto = allstu.id AND mts.timecreated > (UNIX_TIMESTAMP() - (7*24*60*60))) AS 'Msg Instr to Stu - 7 days'<br />
<br />
## All posts in course so far<br />
# Count posts by student<br />
, COUNT(DISTINCT fps.id) AS 'Forum Stu Posts - to date'<br />
<br />
# Count replies to student posts by instructors<br />
, COUNT(DISTINCT fpi.id) AS 'Forum Instr Replies - to date'<br />
<br />
# using link back to student posts on replies, get unique student IDs responded<br />
, COUNT(DISTINCT fpsr.id) - COUNT(DISTINCT fpi.id) AS 'Forum Stu Replies - to date'<br />
<br />
# all replies<br />
, COUNT(DISTINCT fpsr.id) AS 'Forum All Replies - to date'<br />
<br />
# add in count of graded assignments - whole course<br />
, COUNT(DISTINCT asb.id) AS 'Assign Submit - to date'<br />
, COUNT(DISTINCT asg.id) AS 'Assign Grades - to date'<br />
<br />
# Messages between students and instructors - to date<br />
, (SELECT COUNT(DISTINCT mfs.id) FROM prefix_message AS mfs WHERE mfs.useridfrom = allstu.id AND mfs.useridto = instr.id ) AS 'Msg Stu to Instr - to date'<br />
, (SELECT COUNT(DISTINCT mts.id) FROM prefix_message AS mts WHERE mts.useridfrom = instr.id AND mts.useridto = allstu.id) AS 'Msg Instr to Stu - to date'<br />
<br />
## JOINS<br />
<br />
# Start by getting all the students in the course<br />
FROM prefix_user AS allstu <br />
JOIN prefix_role_assignments AS ras ON allstu.id = ras.userid AND ras.roleid = 5<br />
JOIN prefix_context AS ctx ON ras.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
JOIN prefix_course_categories as cc ON c.category = cc.id<br />
<br />
# Now we get the forums and forum discussions from this course only<br />
JOIN prefix_forum AS frm ON frm.course = c.id AND c.id = %%COURSEID%%<br />
JOIN prefix_forum_discussions AS fd ON fd.course = %%COURSEID%% AND fd.forum = frm.id<br />
<br />
# These are forum discussion posts just by students within specified time<br />
LEFT JOIN prefix_forum_posts AS fps ON fps.userid = allstu.id AND fps.discussion = fd.id<br />
<br />
# Separately, we connect the instructors of the courses<br />
# We can use the context we have already gotten for the students<br />
JOIN prefix_role_assignments AS rai ON rai.contextid = ctx.id<br />
JOIN prefix_user AS instr ON instr.id = rai.userid AND rai.roleid =3<br />
<br />
# Now we will connect to posts by instructors that are replies to student posts<br />
# This is a left join, because we don't want to eliminate any students from the list<br />
LEFT JOIN prefix_forum_posts AS fpi ON fpi.discussion = fd.id AND fpi.userid = instr.id AND fpi.parent = fps.id<br />
<br />
# To get identities of only those students who were replied to:<br />
# Connect from instr replies back up to parent posts by students again<br />
# This has to be a LEFT JOIN, we know these posts exist but don't eliminate non-responded students<br />
LEFT JOIN prefix_forum_posts AS fpir ON fpir.id = fpi.parent<br />
<br />
# We also want to know if students are replying to one another<br />
# These are posts that are replies to student posts<br />
# Again, a left join<br />
LEFT JOIN prefix_forum_posts AS fpsr ON fpsr.discussion = fd.id AND fpsr.parent = fps.id<br />
<br />
# get the activity modules<br />
JOIN prefix_course_modules AS cm ON c.id = cm.course<br />
<br />
# get the assignments<br />
JOIN prefix_assign AS a ON cm.instance = a.id<br />
LEFT JOIN prefix_assign_submission AS asb ON a.id = asb.assignment AND asb.userid=allstu.id <br />
LEFT JOIN prefix_assign_grades AS asg ON asg.assignment = a.id AND asg.userid = allstu.id AND asg.assignment = asb.assignment <br />
<br />
WHERE <br />
c.id = %%COURSEID%% <br />
<br />
# GROUP BY c.shortname , allstu.id<br />
GROUP BY allstu.id<br />
<br />
ORDER BY allstu.lastname<br />
</code><br />
<br />
===Student Resource Usage===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
Displays usage by students of all activities and resources in the current course by activity. Only activities and sections which are visible in the course are included. This version requires the new "Standard Logs" from Moodle 2.7+.<br />
<br />
'''Note''': This should be defined as a "Global" report (visible from within all courses). <br />
<br />
<code sql><br />
SELECT <br />
cs.section AS 'Week'<br />
, cs.name AS 'Section Name'<br />
, m.name AS 'item type'<br />
<br />
, CONCAT(<br />
COALESCE(a.name, ''), <br />
COALESCE(b.name,''), <br />
COALESCE(cert.name,''), <br />
COALESCE(chat.name,''), <br />
COALESCE(choice.name,''), <br />
COALESCE(data.name,''), <br />
COALESCE(feedback.name,''), <br />
COALESCE(folder.name,''), <br />
COALESCE(forum.name,''), <br />
COALESCE(glossary.name,''), <br />
COALESCE(imscp.name,''), <br />
COALESCE(lesson.name,''), <br />
COALESCE(p.name,''),<br />
COALESCE(questionnaire.name,''), <br />
COALESCE(quiz.name,''), <br />
COALESCE(cr.name,''), <br />
COALESCE(scorm.name,''), <br />
COALESCE(survey.name,''), <br />
COALESCE(url.name,''), <br />
COALESCE(wiki.name,''), <br />
COALESCE(workshop.name,''), <br />
COALESCE(kalvidassign.name,''), <br />
COALESCE(attendance.name,''), <br />
COALESCE(checklist.name,''), <br />
COALESCE(flashcard.name,''), <br />
COALESCE(lti.name,''), <br />
COALESCE(oublog.name,''), <br />
COALESCE(ouwiki.name,''), <br />
COALESCE(subpage.name,''), <br />
COALESCE(journal.name,''), <br />
COALESCE(lightboxgallery.name,''), <br />
COALESCE(elluminate.name,''), <br />
COALESCE(adaptivequiz.name,''), <br />
COALESCE(hotpot.name,''), <br />
COALESCE(wiziq.name,''), <br />
COALESCE(turnitintooltwo.name,''), <br />
COALESCE(kvr.name,'')<br />
) AS 'item name'<br />
<br />
<br />
, SUM(IF(l.crud IN ('r'),1,0)) AS 'total views'<br />
, SUM(IF(l.crud IN ('c','u'),1,0)) AS 'total submissions'<br />
, COUNT(DISTINCT IF(l.crud IN ('r'),u.id,NULL)) AS 'count of students who viewed'<br />
, COUNT(DISTINCT IF(l.crud IN ('c','u'),u.id,NULL)) AS 'count of students who submitted'<br />
<br />
FROM prefix_user AS u<br />
JOIN prefix_role_assignments AS ra ON u.id = ra.userid<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
JOIN prefix_course_categories as cc ON c.category = cc.id<br />
<br />
JOIN prefix_course_sections AS cs ON cs.course = c.id AND cs.section <= 14 #AND cs.section > 0<br />
LEFT JOIN prefix_course_modules AS cm ON cm.course = c.id AND cm.section = cs.id<br />
JOIN prefix_modules AS m ON m.id = cm.module AND m.name NOT LIKE 'label'<br />
<br />
LEFT JOIN prefix_assign AS a ON a.id = cm.instance AND m.name = 'assign'<br />
LEFT JOIN prefix_book AS b ON b.id = cm.instance AND m.name = 'book'<br />
LEFT JOIN prefix_certificate AS cert ON cert.id = cm.instance AND m.name = 'certificate'<br />
LEFT JOIN prefix_chat AS chat ON chat.id = cm.instance AND m.name = 'chat'<br />
LEFT JOIN prefix_choice AS choice ON choice.id = cm.instance AND m.name = 'choice'<br />
LEFT JOIN prefix_data AS data ON data.id = cm.instance AND m.name = 'data'<br />
LEFT JOIN prefix_feedback AS feedback ON feedback.id = cm.instance AND m.name = 'feedback'<br />
LEFT JOIN prefix_folder AS folder ON folder.id = cm.instance AND m.name = 'folder'<br />
LEFT JOIN prefix_forum AS forum ON forum.id = cm.instance AND m.name = 'forum'<br />
LEFT JOIN prefix_glossary AS glossary ON glossary.id = cm.instance AND m.name = 'glossary'<br />
LEFT JOIN prefix_imscp AS imscp ON imscp.id = cm.instance AND m.name = 'imscp'<br />
LEFT JOIN prefix_lesson AS lesson ON lesson.id = cm.instance AND m.name = 'lesson'<br />
LEFT JOIN prefix_page AS p ON p.id = cm.instance AND m.name = 'page'<br />
LEFT JOIN prefix_questionnaire AS questionnaire ON questionnaire.id = cm.instance AND m.name = 'questionnaire'<br />
LEFT JOIN prefix_quiz AS quiz ON quiz.id = cm.instance AND m.name = 'quiz'<br />
LEFT JOIN prefix_resource AS cr ON cr.id = cm.instance AND m.name = 'resource'<br />
LEFT JOIN prefix_scorm AS scorm ON scorm.id = cm.instance AND m.name = 'scorm'<br />
LEFT JOIN prefix_survey AS survey ON survey.id = cm.instance AND m.name = 'survey'<br />
LEFT JOIN prefix_url AS url ON url.id = cm.instance AND m.name = 'url'<br />
LEFT JOIN prefix_wiki AS wiki ON wiki.id = cm.instance AND m.name = 'wiki'<br />
LEFT JOIN prefix_workshop AS workshop ON workshop.id = cm.instance AND m.name = 'workshop'<br />
LEFT JOIN prefix_kalvidassign AS kalvidassign ON kalvidassign.id = cm.instance AND m.name = 'kalvidassign'<br />
LEFT JOIN prefix_kalvidres AS kvr ON kvr.id = cm.instance AND m.name = 'kalvidres'<br />
LEFT JOIN prefix_attendance AS attendance ON attendance.id = cm.instance AND m.name = 'attendance'<br />
LEFT JOIN prefix_checklist AS checklist ON checklist.id = cm.instance AND m.name = 'checklist'<br />
LEFT JOIN prefix_flashcard AS flashcard ON flashcard.id = cm.instance AND m.name = 'flashcard'<br />
LEFT JOIN prefix_lti AS lti ON lti.id = cm.instance AND m.name = 'lti'<br />
LEFT JOIN prefix_oublog AS oublog ON oublog.id = cm.instance AND m.name = 'oublog'<br />
LEFT JOIN prefix_ouwiki AS ouwiki ON ouwiki.id = cm.instance AND m.name = 'ouwiki'<br />
LEFT JOIN prefix_subpage AS subpage ON subpage.id = cm.instance AND m.name = 'subpage'<br />
LEFT JOIN prefix_journal AS journal ON journal.id = cm.instance AND m.name = 'journal'<br />
LEFT JOIN prefix_lightboxgallery AS lightboxgallery ON lightboxgallery.id = cm.instance AND m.name = 'lightboxgallery'<br />
LEFT JOIN prefix_elluminate AS elluminate ON elluminate.id = cm.instance AND m.name = 'elluminate'<br />
LEFT JOIN prefix_adaptivequiz AS adaptivequiz ON adaptivequiz.id = cm.instance AND m.name = 'adaptivequiz'<br />
LEFT JOIN prefix_hotpot AS hotpot ON hotpot.id = cm.instance AND m.name = 'hotpot'<br />
LEFT JOIN prefix_wiziq AS wiziq ON wiziq.id = cm.instance AND m.name = 'wiziq'<br />
LEFT JOIN prefix_turnitintooltwo AS turnitintooltwo ON turnitintooltwo.id = cm.instance AND m.name = 'turnitintooltwo'<br />
<br />
LEFT JOIN prefix_logstore_standard_log AS l ON l.userid = u.id AND l.courseid = c.id<br />
<br />
<br />
WHERE ra.roleid =5<br />
AND ctx.instanceid = c.id<br />
AND cs.visible = 1<br />
AND cm.visible = 1<br />
<br />
AND c.id = %%COURSEID%%<br />
<br />
GROUP BY cm.id<br />
<br />
ORDER BY cs.section<br />
</code><br />
<br />
===Module activity (Hits) between dates===<br />
<code sql><br />
SELECT module, COUNT( * ) <br />
FROM prefix_logstore_standard_log AS l<br />
WHERE (FROM_UNIXTIME( l.`timecreated` ) BETWEEN '2018-10-01 00:00:00' AND '2019-09-31 00:00:00')<br />
GROUP BY module<br />
</code><br />
<br />
===Module activity (Instances and Hits) for each academic year===<br />
<code sql><br />
SELECT name<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_logstore_standard_log AS l<br />
WHERE (FROM_UNIXTIME(l.`timecreated`) BETWEEN '2017-10-01 00:00:00' AND '2018-09-31 00:00:00')<br />
AND l.module = m.name AND l.action = 'add'<br />
) AS "Added 2017"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_logstore_standard_log AS l<br />
WHERE (FROM_UNIXTIME(l.`timecreated`) BETWEEN '2017-10-01 00:00:00' AND '2018-09-31 00:00:00')<br />
AND l.module = m.name<br />
) AS "Used 2017"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_logstore_standard_log AS l<br />
WHERE (FROM_UNIXTIME(l.`timecreated`) BETWEEN '2018-10-01 00:00:00' AND '2019-09-31 00:00:00')<br />
AND l.module = m.name AND l.action = 'add'<br />
) AS "Added 2018"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_logstore_standard_log AS l<br />
WHERE (FROM_UNIXTIME(l.`timecreated`) BETWEEN '2018-10-01 00:00:00' AND '2019-09-31 00:00:00')<br />
AND l.module = m.name<br />
) AS "Used 2018"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_logstore_standard_log AS l<br />
WHERE (FROM_UNIXTIME(l.`timecreated`) BETWEEN '2019-10-01 00:00:00' AND '2020-09-31 00:00:00')<br />
AND l.module = m.name AND l.action = 'add'<br />
) AS "Added 2019"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_logstore_standard_log AS l<br />
WHERE (FROM_UNIXTIME(l.`timecreated`) BETWEEN '2019-10-01 00:00:00' AND '2020-09-31 00:00:00')<br />
AND l.module = m.name<br />
) AS "Used 2019"<br />
<br />
FROM mdl_modules AS m<br />
</code><br />
<br />
===Unique user sessions per day and month + graph===<br />
The "graph" column is used when displaying a graph (which needs at least three columns to pick from)<br />
<code sql><br />
SELECT COUNT(DISTINCT userid) AS "Unique User Logins"<br />
,DATE_FORMAT(FROM_UNIXTIME(timecreated), "%y /%m / %d") AS "Year / Month / Day", "Graph" <br />
FROM `mdl_logstore_standard_log` <br />
WHERE action LIKE 'loggedin'<br />
#AND timecreated > UNIX_TIMESTAMP('2015-01-01 00:00:00') # optional start date<br />
#AND timecreated <= UNIX_TIMESTAMP('2015-01-31 23:59:00') # optional end date<br />
GROUP BY MONTH(FROM_UNIXTIME(timecreated)), DAY(FROM_UNIXTIME(timecreated))<br />
ORDER BY MONTH(FROM_UNIXTIME(timecreated)), DAY(FROM_UNIXTIME(timecreated))<br />
</code><br />
<br />
And...<br />
<br />
Counting user's global and unique hits per day + counting individual usage of specific activities and resources (on that day),<br />
<br />
And since I am using phpMyAdmin's "Display Graph" feature (at the bottom of the query's output page), I have scaled down the "User Hits" by 10 to fit the graph. that's it.<br />
<code sql><br />
SELECT DATE_FORMAT(FROM_UNIXTIME(timecreated), "%y-%m-%d") AS "Datez"<br />
,COUNT(DISTINCT userid) AS "Unique Users"<br />
,ROUND(COUNT(*)/10) "User Hits (K)"<br />
,SUM(IF(component='mod_quiz',1,0)) "Quizzes"<br />
,SUM(IF(component='mod_forum' or component='mod_forumng',1,0)) "Forums"<br />
,SUM(IF(component='mod_assign',1,0)) "Assignments"<br />
,SUM(IF(component='mod_oublog',1,0)) "Blogs"<br />
,SUM(IF(component='mod_resource',1,0)) "Files (Resource)"<br />
,SUM(IF(component='mod_url',1,0)) "Links (Resource)"<br />
,SUM(IF(component='mod_page',1,0)) "Pages (Resource)"<br />
<br />
FROM `mdl_logstore_standard_log` <br />
WHERE 1=1<br />
AND timecreated > UNIX_TIMESTAMP('2015-03-01 00:00:00') # optional START DATE<br />
AND timecreated <= UNIX_TIMESTAMP('2015-05-31 23:59:00') # optional END DATE<br />
GROUP BY MONTH(FROM_UNIXTIME(timecreated)), DAY(FROM_UNIXTIME(timecreated))<br />
ORDER BY MONTH(FROM_UNIXTIME(timecreated)), DAY(FROM_UNIXTIME(timecreated))<br />
</code><br />
<br />
===System wide, daily unique user hits for the last 7 days===<br />
<code sql><br />
SELECT<br />
DATE_FORMAT(FROM_UNIXTIME(l.timecreated), '%m%d') 'Day'<br />
,COUNT(DISTINCT l.userid) AS 'Distinct Users Hits'<br />
,COUNT( l.userid) AS 'Users Hits'<br />
<br />
FROM prefix_logstore_standard_log AS l<br />
WHERE l.courseid > 1<br />
AND FROM_UNIXTIME(l.timecreated) >= DATE_SUB(NOW(), INTERVAL 7 DAY)<br />
GROUP BY DAY(FROM_UNIXTIME(timecreated))<br />
</code><br />
<br />
===User detailed activity in course modules===<br />
Considering only several modules: url, resource, forum, quiz, questionnaire.<br />
<br />
<code sql><br />
SELECT u.id, ra.roleid,<br />
CONCAT(u.lastname, ' ', u.firstname) AS 'Student'<br />
,COUNT(l.id) AS 'Actions'<br />
,l.component "Module type"<br />
,l.objectid "Module ID"<br />
,CASE <br />
WHEN l.component = 'mod_url' THEN (SELECT u.name FROM prefix_url AS u WHERE u.id = l.objectid )<br />
WHEN l.component = 'mod_resource' THEN (SELECT r.name FROM prefix_resource AS r WHERE r.id = l.objectid )<br />
WHEN l.component = 'mod_forum' THEN (SELECT f.name FROM prefix_forum AS f WHERE f.id = l.objectid )<br />
WHEN l.component = 'mod_quiz' THEN (SELECT q.name FROM prefix_quiz AS q WHERE q.id = l.objectid )<br />
WHEN l.component = 'mod_questionnaire' THEN (SELECT q.name FROM prefix_questionnaire AS q WHERE q.id = l.objectid )<br />
END AS 'Module name'<br />
<br />
,(SELECT GROUP_CONCAT(g.name) FROM prefix_groups AS g<br />
JOIN prefix_groups_members AS m ON g.id = m.groupid WHERE g.courseid = l.courseid AND m.userid = u.id) "user_groups"<br />
<br />
,(SELECT s.name <br />
FROM prefix_course_modules AS cm <br />
JOIN prefix_course_sections AS s ON s.course = cm.course AND s.id = cm.section <br />
WHERE cm.id = l.contextinstanceid) AS "Section name"<br />
<br />
FROM prefix_logstore_standard_log AS l <br />
JOIN prefix_user AS u ON u.id = l.userid<br />
JOIN prefix_role_assignments AS ra ON ra.userid = l.userid <br />
AND ra.contextid = (SELECT id FROM prefix_context WHERE instanceid = l.courseid AND contextlevel = 50) <br />
WHERE l.courseid = %%COURSEID%%<br />
AND l.component IN ('mod_url', 'mod_resource', 'mod_forum', 'mod_quiz', 'mod_questionnaire') <br />
%%FILTER_STARTTIME:l.timecreated:>%% %%FILTER_ENDTIME:l.timecreated:<%%<br />
<br />
GROUP BY u.id, l.component<br />
ORDER BY u.lastname, u.firstname<br />
</code><br />
<br />
===What teachers and courses considered active?===<br />
This report display several calculations and parameters that help the Online academic training team find teachers that might need more support getting their courses more supporting of online learning pedagogical methodologies. <br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',<br />
course.id,'">',course.fullname,'</a>') AS Course <br />
<br />
#,course.shortname<br />
<br />
,CASE <br />
WHEN course.fullname LIKE '%2012%' THEN '2012'<br />
WHEN course.fullname LIKE '%2013%' THEN '2013' <br />
WHEN course.fullname LIKE '%2014%' THEN '2014'<br />
WHEN course.fullname LIKE '%2015%' THEN '2015'<br />
END AS Year<br />
<br />
,CASE <br />
WHEN course.fullname LIKE '%semester a%' THEN 'Spring semester'<br />
WHEN course.fullname LIKE '%semester b%' THEN 'Fall semester'<br />
WHEN course.fullname LIKE '%semester s%' THEN 'Summer semester'<br />
END AS Semester<br />
<br />
,IF(course.startdate>0, DATE_FORMAT(FROM_UNIXTIME(startdate), '%d-%m-%Y'), 'no date') AS "Course Start Date" <br />
<br />
,(SELECT COUNT( ra.userid ) AS Users<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = course.id<br />
) AS Students<br />
<br />
,(SELECT COUNT( ra.userid ) AS Users<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 4 AND ctx.instanceid = course.id<br />
) AS "Assistant teacher"<br />
<br />
,(SELECT COUNT( ra.userid ) AS Users<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 3 AND ctx.instanceid = course.id<br />
) AS Teachers<br />
<br />
# Uncomment to use the new Moodle 2.8+ logstore<br />
#,(SELECT COUNT(*) FROM mdl_logstore_standard_log AS l WHERE l.courseid = course.id) AS Hits<br />
<br />
#,(SELECT COUNT(*)<br />
#FROM mdl_logstore_standard_log AS l<br />
#JOIN mdl_role_assignments AS ra ON ra.userid= l.userid AND ra.roleid = 5 AND ra.contextid = (SELECT id FROM mdl_context WHERE instanceid = l.courseid AND contextlevel = 50) <br />
#WHERE l.courseid = course.id ) AS "Student HITs"<br />
<br />
#,(SELECT COUNT(*)<br />
#FROM mdl_logstore_standard_log AS l<br />
#JOIN mdl_role_assignments AS ra ON ra.userid= l.userid AND ra.roleid = 3 AND ra.contextid = (SELECT id FROM mdl_context WHERE instanceid = l.courseid AND contextlevel = 50) <br />
#WHERE l.courseid = course.id ) AS "Teacher HITs"<br />
<br />
,(SELECT COUNT(*) FROM mdl_log AS l WHERE l.course = course.id) AS Hits<br />
<br />
,(SELECT COUNT(*)<br />
FROM mdl_log AS l<br />
JOIN mdl_context AS con ON con.instanceid= l.course AND con.contextlevel=50<br />
JOIN mdl_role_assignments AS ra ON ra.contextid= con.id AND ra.userid= l.userid AND ra.roleid = 5 <br />
WHERE l.course = course.id) AS "Students HITs"<br />
<br />
,(SELECT COUNT(*)<br />
FROM mdl_log AS l<br />
JOIN mdl_context AS con ON con.instanceid= l.course AND con.contextlevel=50<br />
JOIN mdl_role_assignments AS ra ON ra.contextid= con.id AND ra.userid= l.userid AND ra.roleid = 3 <br />
WHERE l.course = course.id) AS "Teachers HITs"<br />
<br />
,(SELECT GROUP_CONCAT( CONCAT( u.firstname, " ", u.lastname ) ) <br />
FROM prefix_course c<br />
JOIN prefix_context con ON con.instanceid = c.id<br />
JOIN prefix_role_assignments ra ON con.id = ra.contextid AND con.contextlevel = 50<br />
JOIN prefix_role r ON ra.roleid = r.id<br />
JOIN prefix_user u ON u.id = ra.userid<br />
WHERE r.id = 3 AND c.id = course.id<br />
GROUP BY c.id<br />
) AS Teachers<br />
<br />
,(SELECT COUNT(*) FROM prefix_course_modules cm WHERE cm.course = course.id) Modules<br />
<br />
,(SELECT COUNT(DISTINCT cm.module) FROM prefix_course_modules cm <br />
WHERE cm.course = course.id) UniqueModules<br />
<br />
,(SELECT GROUP_CONCAT(DISTINCT m.name) <br />
FROM prefix_course_modules cm <br />
JOIN mdl_modules as m ON m.id = cm.module<br />
WHERE cm.course = course.id) UniqueModuleNames<br />
<br />
,(SELECT COUNT(*) FROM mdl_course_modules cm JOIN mdl_modules as m ON m.id = cm.module <br />
WHERE cm.course = course.id AND m.name IN ( 'ouwiki', 'wiki') ) "Num Wikis"<br />
<br />
,(SELECT COUNT(*) FROM mdl_course_modules cm JOIN mdl_modules as m ON m.id = cm.module <br />
WHERE cm.course = course.id AND m.name IN ( 'oublog') ) "Num Blogs"<br />
<br />
,(SELECT COUNT(*) FROM mdl_course_modules cm JOIN mdl_modules as m ON m.id = cm.module <br />
WHERE cm.course = course.id AND m.name IN ( 'forum', 'forumng') ) "Num Forums"<br />
<br />
,(SELECT COUNT(*) FROM prefix_course_modules cm JOIN mdl_modules as m ON m.id = cm.module <br />
WHERE cm.course = course.id AND m.name IN ('resource', 'folder', 'url', 'tab', 'file', 'book', 'page') ) Resources<br />
<br />
,(SELECT COUNT(*) FROM prefix_course_modules cm JOIN mdl_modules as m ON m.id = cm.module <br />
WHERE cm.course = course.id AND m.name IN ('forum', 'forumng', 'oublog', 'page', 'file', 'url', 'wiki' , 'ouwiki') ) "Basic Activities"<br />
<br />
,(SELECT COUNT(*) FROM prefix_course_modules cm JOIN mdl_modules as m ON m.id = cm.module <br />
WHERE cm.course = course.id AND m.name IN ('advmindmap', 'assign', 'attendance', 'book', 'choice', 'folder', 'tab', 'glossary', 'questionnaire', 'quiz', 'label' ) ) "Avarage Activities"<br />
<br />
,(SELECT COUNT(*) FROM prefix_course_modules cm JOIN mdl_modules as m ON m.id = cm.module <br />
WHERE cm.course = course.id AND m.name IN ('elluminate', 'game', 'workshop') ) "Advanced Activities"<br />
<br />
FROM prefix_course AS course<br />
<br />
#WHERE course.shortname LIKE '%2015%'<br />
#WHERE 1=1<br />
#%%FILTER_SEARCHTEXT:course.shortname:~%%<br />
<br />
WHERE course.fullname LIKE '%2015%' <br />
<br />
HAVING Modules > 2<br />
ORDER BY UniqueModules DESC<br />
</code><br />
<br />
===Weekly attendance report===<br />
This report display weekly report in format HH:M:SS This MySQL query works together with AttendaceRegister module, and gather Log information from Attendanceregister_log table. <br />
<code sql><br />
SELECT u.username, SEC_TO_TIME (SUM(arsess.duration)) AS weekly_online_attendance, FROM_UNIXTIME (arsess.logout) AS Last_Logout<br />
FROM prefix_attendanceregister_session AS arsess<br />
JOIN prefix_user AS u ON arsess.userid = u.id<br />
<br />
WHERE (((arsess.logout) BETWEEN UNIX_TIMESTAMP(DATE_SUB(CURDATE(), INTERVAL 7 DAY)) AND UNIX_TIMESTAMP(CURDATE())))<br />
<br />
GROUP BY arsess.userid<br />
</code><br />
<br />
===How many distinct users connected to Moodle using the app by month===<br />
https://moodle.org/mod/forum/discuss.php?d=336086#p1354194 by <br />
Iñigo Zendegi Urzelai<br />
<code sql><br />
SELECT <br />
to_char(to_timestamp("timecreated"),'YYYY') as year, <br />
to_char(to_timestamp("timecreated"),'MM') as month, <br />
count(distinct userid) as distinct_users<br />
<br />
FROM prefix_logstore_standard_log l<br />
WHERE l.origin='ws'<br />
GROUP BY to_char(to_timestamp("timecreated"),'YYYY'), to_char(to_timestamp("timecreated"),'MM') <br />
ORDER BY to_char(to_timestamp("timecreated"),'YYYY'), to_char(to_timestamp("timecreated"),'MM');<br />
</code><br />
<br />
==Course Reports==<br />
===Most Active courses===<br />
<code sql><br />
SELECT count(l.userid) AS Views<br />
FROM `mdl_logstore_standard_log` l, `mdl_user` u, `mdl_role_assignments` r<br />
WHERE l.courseid=35<br />
AND l.userid = u.id<br />
AND (l.timecreated > UNIX_TIMESTAMP('2015-01-01 00:00:00') AND l.timecreated <= UNIX_TIMESTAMP('2015-01-31 23:59:59'))AND r.contextid= (<br />
SELECT id<br />
FROM mdl_context<br />
WHERE contextlevel=50 AND instanceid=l.courseid<br />
)<br />
AND r.roleid=5<br />
AND r.userid = u.id<br />
</code><br />
<br />
===Active courses, advanced===<br />
Including: Teacher's name, link to the course, All types of log activities, special YEAR generated field, Activities and Resource count, enrolled Student count<br />
<code sql><br />
SELECT COUNT(l.id) hits, concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS Course <br />
<br />
,(SELECT CONCAT(u.firstname,' ', u.lastname) AS Teacher<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS Teacher<br />
<br />
,CASE <br />
WHEN c.fullname LIKE '%תשע' THEN 'תשע'<br />
WHEN c.fullname LIKE '%תשעא' THEN 'תשעא'<br />
WHEN c.fullname LIKE '%תשעב' THEN 'תשעב'<br />
END AS Year<br />
<br />
,(SELECT count(*) FROM prefix_course_modules cm WHERE cm.course = l.course) Modules<br />
<br />
,(SELECT Count( ra.userid ) AS Users FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = c.id) AS Students<br />
<br />
FROM prefix_log l <br />
INNER JOIN prefix_course c ON l.course = c.id<br />
GROUP BY c.id<br />
#The following line restricts the courses returned to those having more than 2 modules. Adjust based on your needs.<br />
HAVING Modules > 2<br />
ORDER BY Year DESC, hits DESC<br />
</code><br />
<br />
=== Least active or probably empty courses===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
It is difficult to know sometimes when a course is actually empty or was never really in use. Other than the simple case where the course was created and never touched again, in which case the course timecreated and timemodified will be the same, many courses created as shells for teachers or other users may be used once or a few times and have few or no test users enrollments in them. This query helps you see the range of such courses, showing you how many days if any it was used after initial creation, and how many user are enrolled. It denotes a course never ever modified by "-1" instead of "0" so you can sort those to the top. By default it limits this to courses used within 60 days of creation, and to courses with 3 or less enrollments (for example, teacher and assistant and test student account only.) You can easily adjust these numbers. The query includes a link to the course as well. <br />
<br />
<code sql><br />
SELECT<br />
c.fullname,<br />
CONCAT('<a target="_blank" href="%%WWWROOT%%/course/view.php',CHAR(63),'id=',c.id,'">',c.shortname,'</a>') AS 'CourseLink',<br />
DATE_FORMAT(FROM_UNIXTIME(c.timecreated), '%Y-%m-%d %H:%i') AS 'Timecreated',<br />
DATE_FORMAT(FROM_UNIXTIME(c.timemodified), '%Y-%m-%d %H:%i') AS 'Timemodified',<br />
CASE<br />
WHEN c.timecreated = c.timemodified THEN '-1'<br />
ELSE DATEDIFF(FROM_UNIXTIME(c.timemodified),FROM_UNIXTIME(c.timecreated))<br />
END AS 'DateDifference',<br />
COUNT(ue.id) AS Enroled<br />
FROM prefix_course AS c<br />
JOIN prefix_enrol AS en ON en.courseid = c.id<br />
LEFT JOIN prefix_user_enrolments AS ue ON ue.enrolid = en.id<br />
WHERE DATEDIFF(FROM_UNIXTIME(c.timemodified),FROM_UNIXTIME(c.timecreated) ) < 60<br />
GROUP BY c.id<br />
HAVING COUNT(ue.id) <= 3<br />
ORDER BY c.fullname<br />
</code><br />
<br />
===Count unique teachers with courses that use at least X module (Moodle19)===<br />
You can remove the outer "SELECT COUNT(*) FROM (...) AS ActiveTeachers" SQL query and get the list of the Teachers and Courses.<br />
<code sql><br />
SELECT COUNT(*)<br />
FROM (SELECT c.id AS CourseID, c.fullname AS Course, ra.roleid AS RoleID, CONCAT(u.firstname, ' ', u.lastname) AS Teacher<br />
,(SELECT COUNT(*) FROM prefix_course_modules cm WHERE cm.course = c.id) AS Modules<br />
FROM prefix_course AS c<br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid AND ctx.contextlevel = 50 <br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE ra.roleid = 3 <br />
GROUP BY u.id<br />
HAVING Modules > 5) AS ActiveTeachers<br />
</code><br />
<br />
===RESOURCE count for each COURSE===<br />
<code sql><br />
SELECT COUNT(l.id) count, l.course, c.fullname coursename<br />
FROM prefix_resource l INNER JOIN prefix_course c on l.course = c.id<br />
GROUP BY course<br />
ORDER BY count DESC<br />
</code><br />
<br />
===Common resource types count for each Category (Moodle19)===<br />
Including sub-categories in total count.<br />
<code sql><br />
SELECT mcc.id AS mccid, CONCAT( LPAD( '', mcc.depth, '.' ) , mcc.name ) AS Category<br />
,(SELECT COUNT( * ) <br />
FROM prefix_resource AS r<br />
JOIN prefix_course AS c ON c.id = r.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%', mccid, '%' ) AND r.TYPE = 'file' AND r.reference LIKE 'http://%'<br />
) AS Links<br />
<br />
,(SELECT COUNT( * ) <br />
FROM prefix_resource AS r<br />
JOIN prefix_course AS c ON c.id = r.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%', mccid, '%' ) AND r.TYPE = 'file' AND r.reference NOT LIKE 'http://%'<br />
) AS Files<br />
<br />
,(SELECT COUNT( * ) <br />
FROM prefix_resource AS r<br />
JOIN prefix_course AS c ON c.id = r.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%', mccid, '%' ) AND r.TYPE = 'directory' <br />
) AS Folders<br />
<br />
,(SELECT COUNT( * ) <br />
FROM prefix_resource AS r<br />
JOIN prefix_course AS c ON c.id = r.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%', mccid, '%' ) AND r.TYPE = 'html' <br />
) AS Pages<br />
<br />
,(SELECT COUNT(*) <br />
FROM stats_log_context_role_course <br />
WHERE roleid = 5 AND module = 'resource' AND category = mcc.id<br />
) AS Hits<br />
<br />
FROM prefix_course_categories AS mcc<br />
ORDER BY mcc.path<br />
</code><br />
Where "stats_log_context_role_course" (in the above SQL query) is a VIEW generated by:<br />
<code sql><br />
CREATE VIEW stats_log_context_role_course AS<br />
SELECT l.course, c.category, cc.path, l.module, l.action, ra.userid, ra.roleid<br />
FROM prefix_log AS l<br />
JOIN prefix_context AS context ON context.instanceid = l.course AND context.contextlevel = 50<br />
JOIN prefix_role_assignments AS ra ON ra.userid = l.userid AND ra.contextid = context.id<br />
JOIN prefix_course AS c ON c.id = l.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
</code><br />
<br />
Same query but for Moodle2+<br />
<code sql><br />
SELECT mcc.id AS mccid, CONCAT( LPAD( '', mcc.depth, '.' ) , mcc.name ) AS Category,<br />
mcc.path,<br />
<br />
(SELECT COUNT(*) <br />
FROM prefix_url AS u<br />
JOIN prefix_course AS c ON c.id = u.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%/', mccid, '%' )<br />
) AS URLs,<br />
<br />
(SELECT COUNT(*) <br />
FROM prefix_folder AS f<br />
JOIN prefix_course AS c ON c.id = f.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%/', mccid, '%' )<br />
) AS FOLDERs,<br />
<br />
(SELECT COUNT(*) <br />
FROM prefix_page AS p<br />
JOIN prefix_course AS c ON c.id = p.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%/', mccid, '%' )<br />
) AS PAGEs,<br />
<br />
(SELECT COUNT(*) <br />
FROM prefix_book AS b<br />
JOIN prefix_course AS c ON c.id = b.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%/', mccid, '%' )<br />
) AS BOOKs,<br />
<br />
(SELECT COUNT(*) <br />
FROM prefix_label AS l<br />
JOIN prefix_course AS c ON c.id = l.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%/', mccid, '%' )<br />
) AS LABELs,<br />
<br />
(SELECT COUNT(*) <br />
FROM prefix_tab AS t<br />
JOIN prefix_course AS c ON c.id = t.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%/', mccid, '%' )<br />
) AS TABs<br />
<br />
FROM prefix_course_categories AS mcc<br />
ORDER BY mcc.path<br />
</code><br />
<br />
===Detailed Resource COUNT by Teacher in each course===<br />
<br />
Including (optional) filter by: year, semester and course id.<br />
<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS CourseID<br />
, c.id<br />
,( SELECT DISTINCT CONCAT(u.firstname,' ',u.lastname)<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_user AS u ON ra.userid = u.id<br />
JOIN prefix_context AS ctx ON ctx.id = ra.contextid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id AND ctx.contextlevel = 50 LIMIT 1) AS Teacher<br />
<br />
, (CASE <br />
WHEN c.fullname LIKE '%תשעב%' THEN '2012' <br />
WHEN c.fullname LIKE '%תשעא%' THEN '2011'<br />
END ) as Year<br />
, (CASE <br />
WHEN c.fullname LIKE '%סמסטר א%' THEN 'Semester A' <br />
WHEN c.fullname LIKE '%סמסטר ב%' THEN 'Semester B'<br />
WHEN c.fullname LIKE '%סמסטר ק%' THEN 'Semester C'<br />
END ) as Semester<br />
,COUNT(c.id) AS Total<br />
,(SELECT count(*) FROM prefix_course_modules AS cm WHERE cm.course = c.id AND cm.module= 20) AS TABs<br />
,(SELECT count(*) FROM prefix_course_modules AS cm WHERE cm.course = c.id AND cm.module= 33) AS BOOKs<br />
<br />
FROM `prefix_resource` as r <br />
JOIN `prefix_course` AS c on c.id = r.course<br />
#WHERE type= 'file' and reference NOT LIKE 'http://%' <br />
<br />
#WHERE 1=1<br />
#%%FILTER_YEARS:c.fullname%%<br />
#AND c.fullname LIKE '%2013%'<br />
<br />
GROUP BY course<br />
ORDER BY COUNT(c.id) DESC<br />
</code><br />
<br />
===Courses that are defined as using GROUPs===<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/group/index.php?id=',c.id,'">',c.fullname,'</a>') AS Course<br />
,(SELECT count(*) FROM prefix_course_modules cm WHERE cm.course = c.id) Modules<br />
,(SELECT count(*) FROM prefix_groups g WHERE g.courseid = c.id) Groups<br />
FROM `prefix_course` AS c<br />
WHERE groupmode > 0<br />
</code><br />
<br />
===Courses with Groups===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
List of all courses with Groups in them (groupmode > 0). You can also use groupmode=1 to list just Separate type groups or groupmode=2 to list Visible type groups.<br />
<br />
<code sql><br />
SELECT c.shortname, g.name, c.groupmode<br />
FROM prefix_course AS c<br />
JOIN prefix_groups AS g ON c.id = g.courseid<br />
WHERE c.groupmode > 0<br />
</code><br />
<br />
===Users enrolled in a course with groups but not assigned a group ===<br />
<br />
Displays by course all enrolled users that have not been assigned a group in courses that have groups. NOTE: This needs to be optimized.<br />
<br />
<code sql><br />
SELECT DISTINCT<br />
user2.firstname AS Firstname,<br />
user2.lastname AS Lastname,<br />
user2.email AS Email,<br />
user2.city AS City,<br />
course.fullname AS Course<br />
,(SELECT shortname FROM prefix_role WHERE id=en.roleid) AS ROLE<br />
,(SELECT name FROM prefix_role WHERE id=en.roleid) AS RoleName<br />
<br />
FROM prefix_course AS course <br />
JOIN prefix_enrol AS en ON en.courseid = course.id<br />
JOIN prefix_user_enrolments AS ue ON ue.enrolid = en.id<br />
JOIN prefix_user AS user2 ON ue.userid = user2.id<br />
JOIN prefix_groups AS g ON g.courseid = course.id<br />
<br />
WHERE ue.enrolid NOT IN (select userid from prefix_groups_members WHERE g.id=groupid)<br />
<br />
ORDER BY Course, Lastname<br />
</code><br />
<br />
===Groups in course with member list===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
List the groups in a course (replace the # by the course id number) with the members of each group.<br />
<br />
<code sql><br />
SELECT c.shortname, g.name AS Groupname, u.username<br />
FROM prefix_course AS c<br />
JOIN prefix_groups AS g ON g.courseid = c.id<br />
JOIN prefix_groups_members AS m ON g.id = m.groupid<br />
JOIN prefix_user AS u ON m.userid = u.id<br />
WHERE c.id = #<br />
</code><br />
<br />
Note: if you are using Configurable Reports block and want to perform this query on the current course you are in, then you can use a WHERE clause like this:<br />
<code sql><br />
WHERE c.id = %%COURSEID%%<br />
</code><br />
<br />
===Group Export===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
There's a [[Import_groups|group import]] function, but no export. Use this to give you a report with the proper column order and headings to export to a csv file you can then import into another course to replicate the groups. This is a simple version with just the main fields: groupname, description, enrolment key.<br />
<br />
<code sql><br />
SELECT g.name AS groupname, g.description, g.enrolmentkey<br />
FROM prefix_groups AS g <br />
JOIN prefix_course as c ON g.courseid = c.id<br />
WHERE c.id = #<br />
</code><br />
Note: if you are using Configurable Reports block and want to perform this query on the current course you are in, then you can use a WHERE clause like this:<br />
<code sql><br />
WHERE c.id = %%COURSEID%%<br />
</code><br />
<br />
===List all Courses in and below a certain category===<br />
Use this SQL code to retrieve all courses that exist in or under a set category.<br />
<br />
$s should be the id of the category you want to know about...<br />
<code sql><br />
SELECT prefix_course. * , prefix_course_categories. *<br />
FROM prefix_course, prefix_course_categories<br />
WHERE prefix_course.category = prefix_course_categories.id<br />
AND (<br />
prefix_course_categories.path LIKE '%/$s/%'<br />
OR prefix_course_categories.path LIKE '%/$s'<br />
)<br />
</code><br />
<br />
===List all Categories in one level below a certain category===<br />
Use this PHP code to retrieve a list of all categories below a certain category.<br />
<br />
$s should be the id of the top level category you are interested in.<br />
<code php><br />
<?php<br />
<br />
require_once('./config.php');<br />
<br />
$parent_id = $s;<br />
<br />
$categories= array();<br />
<br />
$categories = get_categories($parent_id);<br />
<br />
echo '<ol>';<br />
foreach ($categories as $category)<br />
{<br />
echo '<li><a href="'.$CFG->wwwroot.'/course/category.php?id='.$category->id.'">'.$category->name.'</a></li>';<br />
}<br />
echo '</ol>';<br />
<br />
?><br />
</code><br />
<br />
===Blog activity per Course (not including VIEW)===<br />
Filter activity logging to some specific Course Categories!<br />
+ link course name to actual course (for quick reference)<br />
(you can change %blog% to %wiki% to filter down all wiki activity or any other module you wish)<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',cm.course,'">',c.fullname,'</a>') as CourseID<br />
,m.name ,count(cm.id) as counter <br />
,(SELECT Count( ra.userid ) AS Users<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5<br />
AND ctx.instanceid = c.id<br />
) AS Students<br />
, ( SELECT count(id) FROM prefix_log WHERE `module` LIKE '%blog%' AND course = c.id AND action NOT LIKE '%view%' ) as BlogActivity<br />
FROM `prefix_course_modules` as cm JOIN prefix_modules as m ON cm.module=m.id JOIN prefix_course as c ON cm.course = c.id <br />
WHERE m.name LIKE '%blog%' AND c.category IN ( 8,13,15)<br />
GROUP BY cm.course,cm.module order by counter desc<br />
</code><br />
<br />
===Student's posts content in all course blogs (oublog)===<br />
<code sql><br />
SELECT <br />
b.name <br />
,op.title<br />
,op.message<br />
,( SELECT CONCAT(u.firstname, ' ',u.lastname) FROM prefix_user AS u WHERE u.id = oi.userid) AS "Username"<br />
<br />
FROM prefix_oublog_posts AS op<br />
JOIN prefix_oublog_instances AS oi ON oi.id = op.oubloginstancesid <br />
JOIN prefix_oublog as b ON b.id = oi.oublogid<br />
JOIN prefix_course AS c ON b.course = c.id<br />
<br />
WHERE c.id = %%COURSEID%%<br />
</code><br />
<br />
===All Courses which uploaded a Syllabus file===<br />
+ under specific Category<br />
+ show first Teacher in that course<br />
+ link Course's fullname to actual course<br />
<code sql><br />
SELECT<br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') as Course<br />
,c.shortname,r.name<br />
,(SELECT CONCAT(u.firstname,' ', u.lastname) as Teacher<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user as u ON u.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) as Teacher<br />
FROM prefix_resource as r <br />
JOIN prefix_course as c ON r.course = c.id<br />
WHERE ( r.name LIKE '%סילבוס%' OR r.name LIKE '%סילאבוס%' OR r.name LIKE '%syllabus%' OR r.name LIKE '%תכנית הקורס%' ) <br />
AND c.category IN (10,18,26,13,28)<br />
</code><br />
<br />
===Site-wide completed SCORM activities by Course name===<br />
This report will list all completed attempts for all SCORM activities. It is ordered first by Course name, then student's last name, then student's first name, then attempt number. Please note: the FROM_UNIXTIME command is for MySQL.<br />
<code sql><br />
SELECT u.firstname First,u.lastname Last,c.fullname Course, st.attempt Attempt,st.value Status,FROM_UNIXTIME(st.timemodified,"%m-%d-%Y") Date <br />
FROM prefix_scorm_scoes_track AS st <br />
JOIN prefix_user AS u ON st.userid=u.id<br />
JOIN prefix_scorm AS sc ON sc.id=st.scormid<br />
JOIN prefix_course AS c ON c.id=sc.course<br />
WHERE st.value='completed' <br />
ORDER BY c.fullname, u.lastname,u.firstname, st.attempt<br />
</code><br />
===All users enrolled in a course without a role===<br />
Identifies All users that are enrolled in a course but are not assigned a role.<br />
<code sql><br />
SELECT<br />
user.firstname AS Firstname,<br />
user.lastname AS Lastname,<br />
user.idnumber Employee_ID,<br />
course.fullname AS Course<br />
<br />
FROM prefix_course AS course <br />
JOIN prefix_enrol AS en ON en.courseid = course.id<br />
JOIN prefix_user_enrolments AS ue ON ue.enrolid = en.id<br />
JOIN prefix_user as user ON user.id = ue.userid<br />
<br />
WHERE user.id NOT IN (<br />
SELECT u.id<br />
FROM prefix_course AS c<br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid<br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN prefix_role AS r ON r.id = ra.roleid<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE c.id=course.id<br />
)<br />
ORDER BY Course, Lastname, Firstname<br />
<br />
</code><br />
<br />
===List course resources accumulative file size and count===<br />
This is the main (first) report, which has a link (alias) to a second report (the following on this page) which list each file in the course.<br />
<code sql><br />
SELECT c.id "CourseID", context.id "ContextID"<br />
,CONCAT('<a target="_new" href="%%WWWROOT%%/course/view.php?id=', c.id, '">', c.fullname ,'</a>') AS "Course Name"<br />
, COUNT(*) "Course Files" , ROUND( SUM( f.filesize ) /1048576 ) AS file_size_MB<br />
,CONCAT('<a target="_new" href="%%WWWROOT%%/blocks/configurable_reports/viewreport.php?alias=coursefiles&courseid=1&filter_courses=', c.id, '">List files</a>') AS "List Files"<br />
<br />
FROM mdl_files AS f<br />
JOIN mdl_context AS context ON context.id = f.contextid<br />
JOIN mdl_course AS c ON c.id = (<br />
SELECT instanceid<br />
FROM mdl_context<br />
WHERE id = SUBSTRING_INDEX( SUBSTRING_INDEX( context.path, '/' , -2 ) , '/', 1 ) )<br />
WHERE filesize >0<br />
GROUP BY c.id<br />
</code><br />
<br />
With this report, you will have to define "alias" report property to "coursefiles" for it to be able to be called from the above report.<br />
And also setup (add) a FILTER_COURSES filter. <br />
<code sql><br />
SELECT <br />
id ,CONCAT('<a target="_new" href="%%WWWROOT%%/pluginfile.php/', contextid, '/', component, '/', filearea, '/', itemid, '/', filename, '">', filename,'</a>') AS "File"<br />
,filesize, mimetype ,author, license, timecreated, component, filearea, filepath<br />
<br />
FROM mdl_files AS f<br />
WHERE filesize >0<br />
AND f.contextid<br />
IN ( SELECT id<br />
FROM mdl_context<br />
WHERE path <br />
LIKE ( SELECT CONCAT('%/',id,'/%')<br />
AS contextquery<br />
FROM mdl_context<br />
WHERE 1=1<br />
%%FILTER_COURSES:instanceid%%<br />
AND contextlevel = 50<br />
)<br />
)<br />
</code><br />
<br />
===Which courses has redundant topics===<br />
This report list several "active topics" calculations, per course. which should give an administrator some indications for which topics/sections/weeks are filled with resources and activities and which ones are empty and not used (usually, at the end of the course).<br />
<br />
The following, second SQL query, could be used to "trim" down those redundant course topics/sections/weeks by updating the course format's numsection (Number of sections) setting. (It's a per course format setting!)<br />
<br />
<code sql><br />
SELECT id, format,<br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">', c.fullname,'</a>') AS Course <br />
<br />
,(SELECT value FROM `mdl_course_format_options` WHERE `courseid` = c.id AND `format` = c.format AND `name` = 'numsections' ) AS "numsections"<br />
,(SELECT COUNT(*) FROM `mdl_course_sections` WHERE `course` = c.id AND `sequence` != '' ) AS "Non empty sections count"<br />
,(SELECT COUNT(*) FROM `mdl_course_sections` WHERE `course` = c.id ) AS "Total section count"<br />
,(SELECT COUNT(*) FROM `mdl_course_sections` WHERE `course` = c.id AND sequence IS NOT NULL) AS "Non NULL sections count"<br />
,(SELECT COUNT(*) FROM `mdl_course_sections` WHERE `course` = c.id AND name != '') AS "Non empty section Name count"<br />
,(SELECT COUNT(*) FROM mdl_course_modules cm WHERE cm.course = c.id) "Modules count"<br />
<br />
FROM mdl_course AS c<br />
</code><br />
<br />
The following SQL REPLACE query is used for "fixing" (updating) the "numsections" of a specific course format "onetopics" (you can always change it, or discard it to use this SQL REPLACE on all course formats) <br />
<code sql><br />
REPLACE INTO `mdl_course_format_options` (`id`, `courseid`, `format`, `sectionid`, `name`, `value`) <br />
SELECT NULL, c.id, 'onetopic', '0', 'numsections', (SELECT COUNT(*) FROM `mdl_course_sections` WHERE `course` = c.id AND name != '')<br />
FROM `mdl_course` c where format = 'onetopic'<br />
</code><br />
<br />
===Hidden Courses with Students Enrolled===<br />
Contributed by Eric Strom<br />
<br />
This query identifies courses with student enrollment that are currently hidden from students. Includes the defined course start date, count of students and instructors, and a clickable email link of instructor (first found record if more than one).<br />
<br />
<code sql><br />
SELECT c.visible AS Visible, <br />
DATE(FROM_UNIXTIME(c.startdate)) AS StartDate, <br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php',CHAR(63),'id=',<br />
c.id,'">',c.idnumber,'</a>') AS Course_ID,<br />
<br />
(SELECT COUNT( ra.userid ) FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = c.id) AS Students,<br />
<br />
(SELECT COUNT( ra.userid ) FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id) AS Instructors,<br />
<br />
(SELECT DISTINCT concat('<a href="mailto:',u.email,'">',u.email,'</a>')<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_user AS u ON ra.userid = u.id<br />
JOIN prefix_context AS ctx ON ctx.id = ra.contextid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id AND ctx.contextlevel = 50 LIMIT 1) AS 'Instructor_Email', <br />
<br />
now() AS Report_Timestamp<br />
<br />
FROM prefix_course AS c <br />
WHERE c.visible = 0 AND (SELECT COUNT( ra.userid ) FROM prefix_role_assignments AS ra JOIN prefix_context AS ctx ON ra.contextid = ctx.id WHERE ra.roleid = 5 AND ctx.instanceid = c.id) > 0<br />
ORDER BY StartDate, Instructor_Email, Course_ID<br />
</code><br />
<br />
<br />
==Course Design Reports==<br />
<br />
These are reports which summarize course design aspects, such as activity and resource modules per section, types of activities used, etc.<br />
<br />
===Course Content/Week===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
This report assumes that the first 14 sections in a course, not including the "0" or "Welcome" section, correspond to weeks (with "Subsections" given numbers much higher in the sequence). Of those sections, each is checked to count the number of:<br />
<br />
Forums<br />
Graded Activities (may include Forums)<br />
Resources (not including a Label)<br />
<br />
Totals of each of these types of content elements per section are provided.<br />
<br />
'''Note''': Only visible resources and activities are counted.<br />
'''Note''': this is a "Global" report. Run it within a course to see a summary of the contents of that course.<br />
<br />
<code sql><br />
SELECT<br />
<br />
cs.section AS 'Week'<br />
, cs.name AS 'Section Name'<br />
<br />
, COUNT(DISTINCT IF((gi.id IS NULL) AND (m.name NOT LIKE 'label'),cm.id,NULL)) AS 'Ungraded Resources'<br />
<br />
, COUNT(DISTINCT IF(m.name LIKE 'forum', cm.id, NULL)) AS 'Forums'<br />
<br />
, COUNT(DISTINCT IF(gi.id, cm.id, NULL)) AS 'Graded Activities'<br />
<br />
FROM prefix_course AS c<br />
JOIN prefix_course_sections AS cs ON cs.course = c.id AND cs.section <= 14 AND cs.section > 0<br />
LEFT JOIN prefix_course_modules AS cm ON cm.course = c.id AND cm.section = cs.id <br />
JOIN prefix_modules AS m ON m.id = cm.module<br />
LEFT JOIN prefix_grade_items AS gi ON gi.courseid = c.id AND gi.itemmodule = m.name AND gi.iteminstance = cm.instance<br />
<br />
WHERE <br />
cs.visible = 1<br />
AND cm.visible = 1<br />
AND c.id = %%COURSEID%%<br />
<br />
GROUP BY cs.section<br />
ORDER BY cs.section<br />
<br />
</code><br />
<br />
===Assignments and Weights===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
Returns a list of grade book categories for the current course, grade book weightings, the first type of assignment included in the category, a count of different assignment types for each category, and a count of assignments for each category.<br />
<br />
Categories with weights of 0 are not included in this report.<br />
<br />
Only visible activities are included in this report.<br />
<br />
'''Note''': This is designed to be a "Global" report in Configurable Reports.<br />
<code sql><br />
SELECT<br />
<br />
IF(gc.parent IS NOT NULL, gc.fullname, 'None') AS 'Grade Book Category'<br />
, IF(gc.parent IS NOT NULL, ROUND(gic.aggregationcoef, 2), ROUND(SUM(DISTINCT gi.aggregationcoef), 2)+ROUND(SUM(DISTINCT mgi.aggregationcoef), 2)) AS 'Category weight'<br />
<br />
, CONCAT_WS(', ',GROUP_CONCAT(DISTINCT gi.itemmodule SEPARATOR ', '), IF(mgi.id, 'manual',NULL)) AS 'Activity Types'<br />
, COUNT(DISTINCT gi.itemmodule) + IF(mgi.id,1,0) AS 'Different Activity Types'<br />
, CONCAT_WS('<br>', GROUP_CONCAT(DISTINCT gi.itemname ORDER BY gi.itemname SEPARATOR '<br>'), GROUP_CONCAT(DISTINCT mgi.itemname ORDER BY mgi.itemname SEPARATOR '<br>')) AS 'Activity Names'<br />
, COUNT(DISTINCT IF(gi.id, cm.id, NULL)) + COUNT(DISTINCT mgi.id) AS 'Activity Count'<br />
<br />
FROM prefix_course AS c<br />
<br />
#get grade categories<br />
LEFT JOIN prefix_grade_categories AS gc ON gc.courseid = c.id <br />
# back from categories to grade items to get aggregations and weights<br />
JOIN prefix_grade_items AS gic ON gic.courseid = c.id AND gic.itemtype = 'category' AND gic.aggregationcoef != 0 AND (LOCATE(gic.iteminstance, gc.path) OR (gc.parent IS NULL))<br />
<br />
# attach activities to course<br />
JOIN prefix_course_modules AS cm ON cm.course = c.id <br />
# attach grade items to activities<br />
LEFT JOIN prefix_grade_items AS gi ON gi.courseid = c.id AND gi.iteminstance = cm.instance AND gi.itemtype = 'mod' AND gi.categoryid = gc.id AND gi.hidden != 1<br />
<br />
# attach manual grade items to course-- they don't have modules<br />
LEFT JOIN prefix_grade_items AS mgi ON mgi.courseid = c.id and mgi.itemtype = 'manual' AND mgi.categoryid = gc.id<br />
<br />
WHERE <br />
cm.visible = 1<br />
AND c.id = %%COURSEID%%<br />
<br />
GROUP BY gc.id<br />
ORDER BY gc.id<br />
<br />
</code><br />
<br />
===Pre-Term Course Review===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
Provides an overview of the readiness of ONLINE, HYBRID, and BLENDED courses in the Staging category and all subcategories. Links to each course are provided. Other details:<br />
<br />
# "Required blocks" include Instructor Block (mooprofile), Activities, and the Research block.<br />
# "Instructor Details" block is not the "Instructor" block (mooprofile) automatically provided by the system. It is an optional block that can be edited by the instructor. If not edited to remove boilerplate text, it should be hidden.<br />
# All courses should be in the "Collapsed Topics" format with the "Weeks" structure.<br />
# "Weeks defined in course settings" is taken from our SIS when the course shells are created, but can be edited by faculty. "# of weeks named and visible" should usually match or exceed this value.<br />
# We recommend that each week contain at least one forum, at least one graded activity, and at least one ungraded resource.<br />
# "Syllabus updated" date is for the first attached file found with the text "syllabus" in the name. The "Days ago" calculation is included for convenience.<br />
<br />
'''Note''': At our institution, we construct categories each term, and insert a text string "staging" in the Category ID for pre-term courses during the preparation or "staging" phase of course development. We remove this text string (and change it to "production") when courses go live at the start of the new term.<br />
<br />
<code sql><br />
SELECT CONCAT('<a target="_blank" href="%%WWWROOT%%/course/view.php',CHAR(63),'id=',c.id,'">',c.shortname,'</a>') AS Course<br />
<br />
#,RIGHT(c.idnumber,2) AS Type # Specific to GSC "Instructional Method" storage<br />
<br />
#, substring_index(substr(c.shortname FROM locate('.',c.shortname)+1),'-',1) AS Section # Specific to GSC<br />
<br />
,(SELECT CONCAT('<a target="_blank" href="%%WWWROOT%%/user/view.php',CHAR(63),'id=',u.id,'">',u.lastname,', ', u.firstname,'</a>')<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS 'Instructor' <br />
<br />
,(SELECT IF((u2.description IS NULL) OR (u2.description LIKE ''),'NO', 'YES')<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u2 ON u2.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS 'Profile Has Bio'<br />
<br />
,(SELECT IF(u3.picture > 0,'YES','NO')<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u3 ON u3.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS 'Profile Has Picture'<br />
<br />
, IF(((bpi.visible IS NULL) OR (bpi.visible !=0)) AND ((bpm.visible IS NULL) OR (bpm.visible !=0)) AND ((bpa.visible IS NULL) OR (bpa.visible !=0)) AND ((bpr.visible IS NULL) OR (bpr.visible !=0)),'YES','NO') AS 'Required blocks visible'<br />
#, IF((bpm.visible IS NULL) OR (bpm.visible !=0),'YES','NO') AS 'Messages block visible'<br />
#, IF((bpa.visible IS NULL) OR (bpa.visible !=0),'YES','NO') AS 'activities block visible'<br />
#, IF((bpr.visible IS NULL) OR (bpr.visible !=0),'YES','NO') AS 'research block visible'<br />
<br />
#, IF(SUM(IF(bi.configdata LIKE 'Tzo4OiJzdGRDbGFzcyI6Mzp7czo1OiJ0aXRsZSI7czoxODoiSW5zdHJ1Y3RvciBEZXRhaWxzI%',1,0)) AND (bip.visible !=0),'YES','') AS 'Instructor Details Block visible' # This is a hack based on UUencoded string data from the title of HTML "Instructor Details" block<br />
<br />
#, IF(bi.configdata LIKE '%ZGl0IHRoaXMgYmxvY2s%','NO','') AS 'Instructor Details Block Updated' # HTML block has string 'dit this block'<br />
<br />
#, IF(COUNT(bi.id) - SUM(IF(bi.configdata LIKE 'Tzo4OiJzdGRDbGFzcyI6Mzp7czo1OiJ0aXRsZSI7czoxODoiSW5zdHJ1Y3RvciBEZXRhaWxzI%',1,0)),'YES','') AS 'possible extra instructor blocks' #looking for any HTML block with "instructor" in the title<br />
<br />
, IF(c.format='topcoll','YES', c.format) AS 'Collapsed Topics course format' # change this if you want to test for a different format<br />
, IF(cfo.value = 2, 'YES','NO') AS 'weeks structure'<br />
<br />
, cfw.value AS 'weeks defined in course settings'<br />
<br />
, COUNT(DISTINCT IF(((cs.name IS NOT NULL) AND (cs.visible = 1) AND (cs.section != '0') AND (cs.sequence IS NOT NULL)),cs.id,NULL)) AS '# of weeks named & visible (includes orphans)'<br />
<br />
, COUNT(DISTINCT IF(m.name LIKE 'forum', cm.id, NULL)) AS 'Forums'<br />
, COUNT(DISTINCT IF(m.name LIKE 'forum' ,cs.id , NULL)) AS 'Weeks with Forum'<br />
<br />
, COUNT(DISTINCT IF(gi.id, cm.id, NULL)) AS 'Activities'<br />
, COUNT(DISTINCT IF(gi.id, cs.id, NULL)) AS 'Weeks with Activities'<br />
, COUNT(DISTINCT mgi.id) AS 'Manual Grade Items'<br />
<br />
, COUNT(DISTINCT IF((gi.id IS NULL) AND (m.name NOT IN ('forum','label')),cm.id,NULL)) AS 'Resources'<br />
, COUNT(DISTINCT IF((gi.id IS NULL) AND (m.name NOT IN ('forum','label')), cs.id, NULL)) AS 'Weeks with Resources'<br />
<br />
# Here are some other things you could check for per course<br />
#,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm JOIN prefix_modules AS m ON cm.module = m.id WHERE cm.course = c.id AND m.name LIKE '%forum%') AS Forums<br />
<br />
#,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm JOIN prefix_modules AS m ON cm.module = m.id WHERE cm.course = c.id AND m.name LIKE '%quiz%') AS Quizzes<br />
<br />
#,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm JOIN prefix_modules AS m ON cm.module = m.id WHERE cm.course = c.id AND m.name LIKE '%assign%') AS Assignments<br />
<br />
#,(SELECT COUNT(prefix_resource.id) FROM prefix_resource JOIN prefix_course ON prefix_course.id = prefix_resource.course WHERE c.id = prefix_resource.course) AS Files<br />
<br />
#,(SELECT COUNT(prefix_url.id) FROM prefix_url JOIN prefix_course ON prefix_course.id = prefix_url.course WHERE c.id = prefix_url.course) AS Links<br />
<br />
,(SELECT FROM_UNIXTIME(MAX(prefix_resource.timemodified))<br />
FROM prefix_resource<br />
JOIN prefix_course ON prefix_course.id = prefix_resource.course WHERE c.id = prefix_resource.course AND prefix_resource.name LIKE '%syllabus%') AS SyllabusDate<br />
<br />
,(SELECT TO_DAYS(NOW())-TO_DAYS(FROM_UNIXTIME(MAX(prefix_resource.timemodified)))<br />
FROM prefix_resource<br />
JOIN prefix_course ON prefix_course.id = prefix_resource.course WHERE c.id = prefix_resource.course AND prefix_resource.name LIKE '%syllabus%') AS DaysAgo<br />
<br />
, IF(COUNT(DISTINCT IF(f.type LIKE 'news', f.id,NULL)),'YES','NO' ) AS 'Announcement Forum Visible'<br />
<br />
, IF(COUNT(DISTINCT IF(f.type LIKE 'news', fd.id,NULL)),'YES','NO' ) AS 'Announcement posted'<br />
<br />
FROM prefix_course AS c<br />
LEFT JOIN prefix_course_categories as cc ON c.category = cc.id<br />
LEFT JOIN prefix_context AS ctxx ON c.id = ctxx.instanceid <br />
<br />
LEFT JOIN prefix_block_positions AS bpi ON bpi.contextid = ctxx.id AND bpi.blockinstanceid = '43692' # mooprofile<br />
LEFT JOIN prefix_block_positions AS bpm ON bpm.contextid = ctxx.id AND bpm.blockinstanceid = '43962' # messages<br />
LEFT JOIN prefix_block_positions AS bpa ON bpa.contextid = ctxx.id AND bpa.blockinstanceid = '43963' # activities<br />
LEFT JOIN prefix_block_positions AS bpr ON bpr.contextid = ctxx.id AND bpr.blockinstanceid = '38368' # html research help<br />
<br />
LEFT JOIN prefix_course_sections AS cs ON cs.course = c.id AND cs.visible = 1 AND cs.sequence IS NOT NULL<br />
LEFT JOIN prefix_course_modules AS cm ON cm.course = c.id AND cm.section = cs.id <br />
LEFT JOIN prefix_modules AS m ON m.id = cm.module<br />
LEFT JOIN prefix_grade_items AS gi ON gi.courseid = c.id AND gi.itemmodule = m.name AND gi.iteminstance = cm.instance<br />
<br />
LEFT JOIN prefix_forum AS f ON f.course = c.id AND cm.instance = f.id AND cm.visible = 1<br />
LEFT JOIN prefix_forum_discussions AS fd ON fd.forum = f.id<br />
<br />
# attach manual grade items to course-- they don't have modules<br />
LEFT JOIN prefix_grade_items AS mgi ON mgi.courseid = c.id and mgi.itemtype = 'manual'<br />
<br />
LEFT JOIN prefix_course_format_options AS cfo ON cfo.courseid = c.id AND cfo.name = 'layoutstructure'<br />
LEFT JOIN prefix_course_format_options AS cfw ON cfw.courseid = c.id AND cfw.name = 'numsections'<br />
<br />
LEFT JOIN prefix_block_instances AS bi ON bi.parentcontextid = ctxx.id AND bi.blockname = 'html' AND (bi.configdata LIKE '%SW5zdHJ1Y3Rvc%' or bi.configdata LIKE '%bnN0cnVjdG9y%')<br />
LEFT JOIN prefix_block_positions AS bip ON bip.blockinstanceid = bi.id<br />
<br />
WHERE RIGHT(c.idnumber,2) IN ('OL', 'BL', 'HY') <br />
# AND substring(cc.path,2,2) IN ('26') # Staging<br />
#AND substring(cc.path,2,3) IN ('158') # UG<br />
AND cc.idnumber LIKE '%staging%'<br />
AND ctxx.contextlevel = 50<br />
<br />
GROUP BY c.shortname<br />
</code><br />
<br />
===Module instances + Module HITs by role teacher and student in course===<br />
<code sql><br />
SELECT <br />
m.name AS "Module name"<br />
, COUNT(*) AS "Module count"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_log AS l <br />
WHERE l.course = cm.course AND l.module = m.name ) AS "Hits"<br />
<br />
,(SELECT COUNT(*)<br />
FROM prefix_log AS l<br />
JOIN prefix_context AS con ON con.instanceid= l.course AND con.contextlevel=50<br />
JOIN prefix_role_assignments AS ra ON ra.contextid= con.id AND ra.userid= l.userid AND ra.roleid = 5 <br />
WHERE l.course = cm.course AND l.module = m.name) AS "Students HITs"<br />
<br />
,(SELECT COUNT(*)<br />
FROM prefix_log AS l<br />
JOIN prefix_context AS con ON con.instanceid= l.course AND con.contextlevel=50<br />
JOIN prefix_role_assignments AS ra ON ra.contextid= con.id AND ra.userid= l.userid AND ra.roleid = 3 <br />
WHERE l.course = cm.course AND l.module = m.name) AS "Teachers HITs"<br />
<br />
FROM mdl_course_modules AS cm<br />
JOIN mdl_modules AS m on m.id = cm.module<br />
WHERE cm.course = '%%COURSEID%%'<br />
GROUP BY cm.module<br />
</code><br />
<br />
===Course Syllabus===<br />
Contributed by Elizabeth Dalton, Granite State College / Moodle HQ<br />
<br />
This report requires ELIS. It runs from within a course and constructs a course syllabus based on content in the course and in the ELIS entries related to the course (Class Instance, Course Description, and Program). It is a proof-of-concept of an automated syllabus production tool. Fields such as "Course Policies" and "Teaching Philosophy" are added to the Class Instance records, and instructors enter them there. The Instructor Bio is pulled from the User Profile of all users with the Teacher role in the course.<br />
<br />
<code sql><br />
SELECT <br />
<br />
c.fullname AS 'fullname'<br />
, ec.idnumber AS 'elis-id'<br />
, DATE_FORMAT(FROM_UNIXTIME(ec.startdate), '%b %e, %Y') AS 'start'<br />
, DATE_FORMAT(FROM_UNIXTIME(ec.enddate), '%b %e, %Y') AS 'end'<br />
, ecd.name AS 'longname'<br />
, ecd.code AS 'coursecode'<br />
, ecd.credits AS 'coursecredits'<br />
, ecd.syllabus AS 'description'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'learning-outcomes'<br />
WHERE ctxecd.id = eft.contextid) AS 'outcomes'<br />
<br />
,(SELECT CONCAT('<a target="_blank" href="%%WWWROOT%%/user/view.php',CHAR(63),'id=',u.id,'">',u.firstname,' ', u.lastname,'</a> ', u.email)<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS 'Instructor' <br />
<br />
, (SELECT efc.data<br />
FROM prefix_local_eliscore_fld_data_char AS efc<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = efc.fieldid AND ef.shortname = 'term-code'<br />
WHERE ctxci.id = efc.contextid) AS 'termcode'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'prerequisites'<br />
WHERE ctxecd.id = eft.contextid) AS 'prerequisites'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'textbooks'<br />
WHERE ctxci.id = eft.contextid) AS 'textbooks'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'other-class-materials'<br />
WHERE ctxci.id = eft.contextid) AS 'other-class-materials'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'course-policies'<br />
WHERE ctxci.id = eft.contextid) AS 'course-policies'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'teaching-philosophy'<br />
WHERE ctxci.id = eft.contextid) AS 'teaching-philosophy'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'course-methods'<br />
WHERE ctxci.id = eft.contextid) AS 'course-methods'<br />
<br />
,(SELECT u2.description<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u2 ON u2.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS 'Bio'<br />
<br />
,(SELECT<br />
<br />
GROUP_CONCAT(DISTINCT CONCAT(<br />
<br />
'<tr><td style="border: solid #000 .5px">',IF(gc.parent IS NOT NULL, gc.fullname, 'None')<br />
, ' </td><td style="border: solid #000 .5px"> '<br />
,IF(gc.parent IS NOT NULL, ROUND(gic.aggregationcoef, 2), ROUND( gi.aggregationcoef, 2)+ROUND(mgi.aggregationcoef, 2))<br />
<br />
) SEPARATOR '</td></tr>')<br />
#get grade categories<br />
FROM prefix_grade_categories AS gc <br />
# back from categories to grade items to get aggregations and weights<br />
LEFT JOIN prefix_grade_items AS gic ON gic.courseid = gc.courseid AND gic.itemtype = 'category' AND gic.aggregationcoef != 0 AND (LOCATE(gic.iteminstance, gc.path) OR (gc.parent IS NULL))<br />
# attach grade items to activities<br />
LEFT JOIN prefix_grade_items AS gi ON gi.courseid = gc.courseid AND gi.itemtype = 'mod' AND gi.categoryid = gc.id AND gi.hidden != 1<br />
# attach manual grade items to course-- they don't have modules<br />
LEFT JOIN prefix_grade_items AS mgi ON mgi.courseid = gc.courseid and mgi.itemtype = 'manual' AND mgi.categoryid = gc.id<br />
WHERE gc.courseid = c.id ) AS 'grade categories'<br />
<br />
, '<table width = "50%" >' AS 'table start'<br />
, '<table width = "100%" >' AS 'table start 2'<br />
, '</table>' AS 'table end'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'activities-schedule'<br />
WHERE ctxci.id = eft.contextid) AS 'activities'<br />
<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'schedule'<br />
WHERE ctxci.id = eft.contextid) AS 'schedule'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'grading-scale'<br />
WHERE ctxepm.id = eft.contextid) AS 'gradescale'<br />
<br />
FROM<br />
prefix_course AS c <br />
<br />
# connect moodle course to ELIS class instance<br />
LEFT JOIN prefix_local_elisprogram_cls_mdl AS ecm ON ecm.moodlecourseid = c.id<br />
LEFT JOIN prefix_local_elisprogram_cls AS ec ON ec.id = ecm.classid<br />
# class instance context<br />
LEFT JOIN prefix_context AS ctxci ON ctxci.instanceid = ec.id AND ctxci.contextlevel = '14'<br />
<br />
# connect ELIS class instance to ELIS course description<br />
LEFT JOIN prefix_local_elisprogram_crs AS ecd ON ecd.id = ec.courseid<br />
# course description context<br />
LEFT JOIN prefix_context AS ctxecd ON ctxecd.instanceid = ecd.id AND ctxecd.contextlevel = '13'<br />
<br />
#connect ELIS program to ELIS Course Description<br />
LEFT JOIN prefix_local_elisprogram_pgm_crs AS epc ON epc.courseid = ecd.id<br />
LEFT JOIN prefix_local_elisprogram_pgm AS epm ON epm.id = epc.curriculumid<br />
# course program context<br />
LEFT JOIN prefix_context AS ctxepm ON ctxepm.instanceid = epm.id AND ctxepm.contextlevel = '11'<br />
<br />
WHERE<br />
<br />
c.id = %%COURSEID%%<br />
</code><br />
<br />
===Course Activities Helper===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
This report provides a list of the graded activities in a course.<br />
* '''Note''': Only graded activities are displayed.<br />
* '''Note''': This is a "Global" report. Run it within a course to see a summary of the contents of that course.<br />
* '''Note''': This report assumes that course sections each last one week.<br />
<br />
<code sql><br />
# 303 Course Activities Helper<br />
<br />
SELECT <br />
<br />
gi.itemmodule AS 'activity type'<br />
# cs.section AS 'section number'<br />
<br />
# Calculation assumes each section lasts one week<br />
, CONCAT(DATE_FORMAT(FROM_UNIXTIME(c.startdate + (7*24*60*60* (cs.section-1))), '%b %e, %Y'),' - <br>',DATE_FORMAT(FROM_UNIXTIME(c.startdate + (7*24*60*60* (cs.section))), '%b %e, %Y')) AS 'Date'<br />
<br />
, gi.itemname AS 'activity name'<br />
<br />
#, (SELECT asg.intro FROM prefix_assign AS asg WHERE asg.id = cm.instance) AS 'intro'<br />
<br />
#, (SELECT f.intro FROM prefix_forum AS f WHERE f.id = cm.instance) AS 'f intro'<br />
<br />
, CASE gi.itemmodule <br />
WHEN 'assign' THEN (SELECT asg.intro FROM prefix_assign AS asg WHERE asg.id = gi.iteminstance) <br />
WHEN 'forum' THEN (SELECT f.intro FROM prefix_forum AS f WHERE f.id = gi.iteminstance) <br />
WHEN 'quiz' THEN (SELECT q.intro FROM prefix_quiz AS q WHERE q.id = gi.iteminstance) <br />
END AS 'test case'<br />
<br />
#, (SELECT GROUP_CONCAT(CONCAT(' - ',gi.itemname) SEPARATOR '<BR>') FROM prefix_grade_items AS gi JOIN prefix_course_modules AS cm ON gi.iteminstance = cm.instance WHERE gi.gradetype = 1 AND gi.hidden != 1 AND gi.courseid = c.id AND cm.course = c.id AND cm.section = cs.id ) AS 'activities'<br />
<br />
<br />
FROM<br />
prefix_course AS c <br />
<br />
#get grade sections<br />
LEFT JOIN prefix_course_sections AS cs ON cs.course = c.id AND cs.section > 0 AND cs.section <=14<br />
LEFT JOIN prefix_course_modules AS cm ON cm.course = c.id AND cm.section = cs.id<br />
<br />
#LEFT JOIN prefix_assign AS asg ON asg.id = cm.instance<br />
<br />
JOIN prefix_grade_items AS gi ON gi.iteminstance = cm.instance AND gi.gradetype = 1 AND gi.hidden != 1 AND gi.courseid = c.id AND cm.course = c.id AND cm.section = cs.id<br />
<br />
WHERE<br />
c.id = %%COURSEID%%<br />
AND cs.visible = 1<br />
<br />
ORDER BY gi.itemmodule, cs.section<br />
</code><br />
<br />
==Grade and Course Completion Reports==<br />
===Site-Wide Grade Report with All Items===<br />
Shows grades for all course items along with course totals for each student. Works with ad-hoc reports or Configurable Reports<br />
<code sql><br />
SELECT u.firstname AS 'First' , u.lastname AS 'Last', <br />
u.firstname + ' ' + u.lastname AS 'Display Name', <br />
c.fullname AS 'Course', <br />
cc.name AS 'Category',<br />
<br />
CASE <br />
WHEN gi.itemtype = 'course' <br />
THEN c.fullname + ' Course Total'<br />
ELSE gi.itemname<br />
END AS 'Item Name',<br />
<br />
ROUND(gg.finalgrade,2) AS Grade,<br />
DATEADD(ss,gg.timemodified,'1970-01-01') AS Time<br />
<br />
FROM prefix_course AS c<br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid<br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
JOIN prefix_grade_grades AS gg ON gg.userid = u.id<br />
JOIN prefix_grade_items AS gi ON gi.id = gg.itemid<br />
JOIN prefix_course_categories as cc ON cc.id = c.category<br />
<br />
WHERE gi.courseid = c.id <br />
ORDER BY lastname<br />
</code><br />
For MySQL users, you'll need to use the MySQL DATE_ADD function instead of DATEADD. Replace the line:<br />
<code><br />
DATEADD(ss,gg.timemodified,'1970-01-01') AS Time<br />
</code><br />
with:<br />
<code><br />
FROM_UNIXTIME(gg.timemodified) AS Time<br />
</code><br />
And:<br />
<code><br />
u.firstname + ' ' + u.lastname AS 'Display Name', <br />
</code><br />
with:<br />
<code><br />
CONCAT(u.firstname,' ',u.lastname) AS 'Display Name', <br />
</code><br />
<br />
===Site-Wide Grade Report with Just Course Totals===<br />
A second site-wide grade report for all students that just shows course totals. Works with ad-hoc reports or Configurable Reports<br />
<code sql><br />
SELECT u.firstname AS 'First' , u.lastname AS 'Last', u.firstname + ' ' + u.lastname AS 'Display Name', <br />
cc.name AS 'Category',<br />
CASE <br />
WHEN gi.itemtype = 'course' <br />
THEN c.fullname + ' Course Total'<br />
ELSE gi.itemname<br />
END AS 'Item Name',<br />
<br />
ROUND(gg.finalgrade,2) AS Grade,<br />
DATEADD(ss,gg.timemodified,'1970-01-01') AS Time<br />
<br />
FROM prefix_course AS c<br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid<br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
JOIN prefix_grade_grades AS gg ON gg.userid = u.id<br />
JOIN prefix_grade_items AS gi ON gi.id = gg.itemid<br />
JOIN prefix_course_categories as cc ON cc.id = c.category<br />
<br />
WHERE gi.courseid = c.id AND gi.itemtype = 'course'<br />
<br />
ORDER BY lastname<br />
</code><br />
<br />
For MySQL users:<br />
<code sql><br />
SELECT u.firstname AS 'First' , u.lastname AS 'Last', CONCAT(u.firstname , ' ' , u.lastname) AS 'Display Name', <br />
c.fullname AS 'Course', <br />
cc.name AS 'Category',<br />
CASE <br />
WHEN gi.itemtype = 'course' <br />
THEN CONCAT(c.fullname, ' - Total')<br />
ELSE gi.itemname<br />
END AS 'Item Name',<br />
<br />
ROUND(gg.finalgrade,2) AS Grade,<br />
FROM_UNIXTIME(gg.timemodified) AS TIME<br />
<br />
FROM prefix_course AS c<br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid<br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
JOIN prefix_grade_grades AS gg ON gg.userid = u.id<br />
JOIN prefix_grade_items AS gi ON gi.id = gg.itemid<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
<br />
WHERE gi.courseid = c.id AND gi.itemtype = 'course'<br />
ORDER BY lastname<br />
</code><br />
<br />
===Learner report by Learner with grades===<br />
Which Learners in which course and what are the grades<br />
<code sql><br />
SELECT u.firstname AS 'Name' , u.lastname AS 'Surname', c.fullname AS 'Course', cc.name AS 'Category', <br />
CASE WHEN gi.itemtype = 'Course' <br />
THEN c.fullname + ' Course Total' <br />
ELSE gi.itemname <br />
END AS 'Item Name', ROUND(gg.finalgrade,2) AS Score,ROUND(gg.rawgrademax,2) AS Max, ROUND(gg.finalgrade / gg.rawgrademax * 100 ,2) as Percentage,<br />
<br />
if (ROUND(gg.finalgrade / gg.rawgrademax * 100 ,2) > 79,'Yes' , 'No') as Pass<br />
<br />
FROM prefix_course AS c <br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid <br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id <br />
JOIN prefix_user AS u ON u.id = ra.userid <br />
JOIN prefix_grade_grades AS gg ON gg.userid = u.id <br />
JOIN prefix_grade_items AS gi ON gi.id = gg.itemid <br />
JOIN prefix_course_categories AS cc ON cc.id = c.category <br />
WHERE gi.courseid = c.id and gi.itemname != 'Attendance'<br />
ORDER BY `Name` ASC<br />
</code><br />
<br />
===User Course Completion===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
A very simple report with a list of course completion status by username. Completions are noted by date, blank otherwise. <br />
<br />
<code sql><br />
SELECT <br />
u.username, <br />
c.shortname, <br />
DATE_FORMAT(FROM_UNIXTIME(p.timecompleted),'%Y-%m-%d') AS completed<br />
FROM prefix_course_completions AS p<br />
JOIN prefix_course AS c ON p.course = c.id<br />
JOIN prefix_user AS u ON p.userid = u.id<br />
WHERE c.enablecompletion = 1<br />
ORDER BY u.username<br />
</code><br />
<br />
===User Course Completion with Criteria===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
A report with course completions by username, with Aggregation method, Criteria types, and Criteria detail where available.<br />
<br />
<code sql><br />
SELECT u.username AS user, <br />
c.shortname AS course,<br />
DATE_FORMAT(FROM_UNIXTIME(t.timecompleted),'%Y-%m-%d') AS completed,<br />
CASE<br />
WHEN (SELECT a.method FROM prefix_course_completion_aggr_methd AS a WHERE (a.course = c.id AND a.criteriatype IS NULL) = 1) THEN "Any"<br />
ELSE "All"<br />
END AS aggregation,<br />
CASE <br />
WHEN p.criteriatype = 1 THEN "Self"<br />
WHEN p.criteriatype = 2 THEN "By Date"<br />
WHEN p.criteriatype = 3 THEN "Unenrol Status"<br />
WHEN p.criteriatype = 4 THEN "Activity"<br />
WHEN p.criteriatype = 5 THEN "Duration"<br />
WHEN p.criteriatype = 6 THEN "Course Grade"<br />
WHEN p.criteriatype = 7 THEN "Approve by Role"<br />
WHEN p.criteriatype = 8 THEN "Previous Course"<br />
END AS criteriatype,<br />
CASE <br />
WHEN p.criteriatype = 1 THEN "*"<br />
WHEN p.criteriatype = 2 THEN DATE_FORMAT(FROM_UNIXTIME(p.timeend),'%Y-%m-%d')<br />
WHEN p.criteriatype = 3 THEN t.unenroled<br />
WHEN p.criteriatype = 4 THEN <br />
CONCAT('<a target="_new" href="%%WWWROOT%%/mod/',p.module,'/view.php?id=',p.moduleinstance,'">',p.module,'</a>')<br />
WHEN p.criteriatype = 5 THEN p.enrolperiod<br />
WHEN p.criteriatype = 6 THEN CONCAT('Needed: ',ROUND(p.gradepass,2),' Achieved: ',ROUND(t.gradefinal,2)) <br />
WHEN p.criteriatype = 7 THEN p.role<br />
WHEN p.criteriatype = 8 THEN (SELECT pc.shortname FROM prefix_course AS pc WHERE pc.id = p.courseinstance)<br />
END AS criteriadetail <br />
FROM prefix_course_completion_crit_compl AS t<br />
JOIN prefix_user AS u ON t.userid = u.id<br />
JOIN prefix_course AS c ON t.course = c.id<br />
JOIN prefix_course_completion_criteria AS p ON t.criteriaid = p.id<br />
<br />
</code><br />
<br />
===Courses with Completion Enabled and their settings===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
List of all courses with completion enabled and their Aggregation setting, Criteria types, and Criteria details.<br />
<br />
<code sql><br />
<br />
SELECT c.shortname AS Course, <br />
CASE<br />
WHEN (SELECT a.method FROM prefix_course_completion_aggr_methd AS a WHERE (a.course = t.course AND a.criteriatype IS NULL)) = 2 THEN "All"<br />
ELSE "Any"<br />
END AS Course_Aggregation,<br />
CASE<br />
WHEN t.criteriatype = 1 THEN "Self completion"<br />
WHEN t.criteriatype = 2 THEN "Date done by" <br />
WHEN t.criteriatype = 3 THEN "Unenrolement" <br />
WHEN t.criteriatype = 4 THEN "Activity completion" <br />
WHEN t.criteriatype = 5 THEN "Duration in days" <br />
WHEN t.criteriatype = 6 THEN "Final grade" <br />
WHEN t.criteriatype = 7 THEN "Approve by role" <br />
WHEN t.criteriatype = 8 THEN "Previous course"<br />
END AS Criteria_type,<br />
CASE<br />
WHEN t.criteriatype = 1 THEN "On"<br />
WHEN t.criteriatype = 2 THEN DATE_FORMAT(FROM_UNIXTIME(t.timeend),'%Y-%m-%d')<br />
WHEN t.criteriatype = 3 THEN "On"<br />
WHEN t.criteriatype = 4 THEN<br />
CONCAT('<a target="_new" href="%%WWWROOT%%/mod/',t.module,'/view.php?id=',t.moduleinstance,'">',t.module,'</a>')<br />
WHEN t.criteriatype = 5 THEN ROUND(t.enrolperiod/86400)<br />
WHEN t.criteriatype = 6 THEN ROUND(t.gradepass,2)<br />
WHEN t.criteriatype = 7 THEN (SELECT r.shortname FROM prefix_role AS r WHERE r.id = t.role)<br />
WHEN t.criteriatype = 8 THEN (SELECT pc.shortname FROM prefix_course AS pc WHERE pc.id = t.courseinstance)<br />
END AS Criteria_detail<br />
FROM prefix_course_completion_criteria as t<br />
JOIN prefix_course AS c ON t.course = c.id<br />
WHERE c.enablecompletion = 1<br />
ORDER BY course<br />
</code><br />
<br />
===Course Completion Report with custom dates===<br />
<br />
List of users who completed multiple or single course/s from a start date to end date chosen by the user. The output gives username, name, course name, completion date and score<br />
<br />
<code sql><br />
<br />
SELECT u.username AS 'User Name',<br />
CONCAT(u.firstname , ' ' , u.lastname) AS 'Name',<br />
c.shortname AS 'Course Name', <br />
DATE_FORMAT(FROM_UNIXTIME(p.timecompleted),'%W %e %M, %Y') AS 'Completed Date',<br />
ROUND(c4.gradefinal,2) AS 'Score'<br />
FROM prefix_course_completions AS p<br />
JOIN prefix_course AS c ON p.course = c.id<br />
JOIN prefix_user AS u ON p.userid = u.id<br />
JOIN prefix_course_completion_crit_compl AS c4 ON u.id = c4.userid<br />
WHERE c.enablecompletion = 1 AND (p.timecompleted IS NOT NULL OR p.timecompleted !='') <br />
AND (p.timecompleted>= :start_date AND p.timecompleted<=:end_date)<br />
GROUP BY u.username<br />
ORDER BY c.shortname<br />
<br />
</code><br />
<br />
===Scales used in activities===<br />
<code sql><br />
SELECT scale.name<br />
,CONCAT('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS Course<br />
,CONCAT('<a target="_new" href="%%WWWROOT%%/mod/',gi.itemmodule,'/view.php?id=',cm.id,'">',gi.itemname,'</a>') AS "Module View"<br />
,CONCAT('<a target="_new" href="%%WWWROOT%%/course/modedit.php?up','date=',cm.id,'">',gi.itemname,'</a>') AS "Module Settings"<br />
<br />
FROM prefix_grade_items AS gi<br />
JOIN prefix_course AS c ON c.id = gi.courseid<br />
JOIN prefix_course_modules AS cm ON cm.course = gi.courseid AND cm.instance = gi.iteminstance<br />
JOIN prefix_scale AS scale ON scale.id = gi.scaleid<br />
WHERE gi.scaleid IS NOT NULL<br />
</code><br />
<br />
<br />
===Extra Credit Items by Name Only===<br />
Contributed by Eric Strom<br />
<br />
This query identifies grade items in visible courses with student enrollment that have "extra credit" in the name of the item but set as extra credit in the grade settings. Includes the defined course start date, count of students and instructors, and a clickable email link of instructor (first found record if more than one).<br />
<br />
<code sql><br />
SELECT DATE(FROM_UNIXTIME(c.startdate)) AS StartDate, <br />
concat('<a target="_new" href="%%WWWROOT%%/grade/edit/tree/index.php',CHAR(63),'id=',<br />
c.id,'">',c.idnumber,'</a>') AS Course_ID, gi.itemname AS Item_Name<br />
<br />
,(SELECT COUNT( ra.userid ) FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = c.id) AS Students<br />
<br />
,(SELECT COUNT( ra.userid ) FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id) AS Instructors<br />
<br />
,(SELECT DISTINCT concat('<a href="mailto:',u.email,'">',u.email,'</a>')<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_user AS u ON ra.userid = u.id<br />
JOIN prefix_context AS ctx ON ctx.id = ra.contextid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id AND ctx.contextlevel = 50 LIMIT 1) AS 'Instructor_Email'<br />
<br />
,now() AS Report_Timestamp<br />
<br />
FROM prefix_grade_items AS gi<br />
JOIN prefix_course AS c ON gi.courseid = c.id<br />
<br />
WHERE gi.itemname LIKE '%extra credit%' <br />
AND gi.gradetype = '1' <br />
AND gi.hidden = '0' <br />
AND gi.aggregationcoef = '0' <br />
AND c.visible = 1<br />
AND (SELECT COUNT( ra.userid ) FROM prefix_role_assignments AS ra JOIN prefix_context AS ctx ON ra.contextid = ctx.id WHERE ra.roleid = 5 AND ctx.instanceid = c.id) > 0<br />
<br />
GROUP BY Course_ID, gi.id<br />
ORDER BY StartDate, Course_ID<br />
<br />
%%FILTER_SEARCHTEXT:Course_ID:~%%<br />
</code><br />
<br />
===Site Wide Number of Courses Completed by User===<br />
Contributed by Ken St. John<br />
<br />
Simple report that shows the number of completed courses for all users site wide<br />
<br />
<code sql><br />
SELECT u.lastname, u.firstname,<br />
COUNT(p.timecompleted) AS TotalCompletions<br />
FROM prefix_course_completions AS p<br />
JOIN prefix_user AS u ON p.userid = u.id<br />
GROUP BY p.userid<br />
ORDER BY u.lastname<br />
</code><br />
<br />
==Activity Module Reports==<br />
<br />
=== User activity completions with dates===<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
This report shows the users completion status of activities across all courses. It is intended to be uses with Configurable Reports filters for user, start and end times, and also to be able to search the Module names. <br />
<br />
Note: The CASE statement with module numbers may differ on different systems, depending on the number give to the module when the site was created or the module added to the site. These are common default numbers, but you should check your id numbers for them in the course_modules table and adjust as required. You can also add other, third-party plugins too if you wish. <br />
<br />
<code sql><br />
SELECT<br />
u.username As 'User',<br />
c.shortname AS 'Course',<br />
m.name AS Activitytype, <br />
CASE <br />
WHEN cm.module = 1 THEN (SELECT a1.name FROM prefix_assign a1 WHERE a1.id = cm.instance)<br />
WHEN cm.module = 2 THEN (SELECT a2.name FROM prefix_assignment a2 WHERE a2.id = cm.instance)<br />
WHEN cm.module = 3 THEN (SELECT a3.name FROM prefix_book a3 WHERE a3.id = cm.instance)<br />
WHEN cm.module = 4 THEN (SELECT a4.name FROM prefix_chat a4 WHERE a4.id = cm.instance)<br />
WHEN cm.module = 5 THEN (SELECT a5.name FROM prefix_choice a5 WHERE a5.id = cm.instance)<br />
WHEN cm.module = 6 THEN (SELECT a6.name FROM prefix_data a6 WHERE a6.id = cm.instance)<br />
WHEN cm.module = 7 THEN (SELECT a7.name FROM prefix_feedback a7 WHERE a7.id = cm.instance)<br />
WHEN cm.module = 8 THEN (SELECT a8.name FROM prefix_folder a8 WHERE a8.id = cm.instance)<br />
WHEN cm.module = 9 THEN (SELECT a9.name FROM prefix_forum a9 WHERE a9.id = cm.instance)<br />
WHEN cm.module = 10 THEN (SELECT a10.name FROM prefix_glossary a10 WHERE a10.id = cm.instance)<br />
WHEN cm.module = 11 THEN (SELECT a11.name FROM prefix_imscp a11 WHERE a11.id = cm.instance)<br />
WHEN cm.module = 12 THEN (SELECT a12.name FROM prefix_label a12 WHERE a12.id = cm.instance)<br />
WHEN cm.module = 13 THEN (SELECT a13.name FROM prefix_lesson a13 WHERE a13.id = cm.instance)<br />
WHEN cm.module = 14 THEN (SELECT a14.name FROM prefix_lti a14 WHERE a14.id = cm.instance)<br />
WHEN cm.module = 15 THEN (SELECT a15.name FROM prefix_page a15 WHERE a15.id = cm.instance)<br />
WHEN cm.module = 16 THEN (SELECT a16.name FROM prefix_quiz a16 WHERE a16.id = cm.instance)<br />
WHEN cm.module = 17 THEN (SELECT a17.name FROM prefix_resource a17 WHERE a17.id = cm.instance)<br />
WHEN cm.module = 18 THEN (SELECT a18.name FROM prefix_scorm a18 WHERE a18.id = cm.instance)<br />
WHEN cm.module = 19 THEN (SELECT a19.name FROM prefix_survey a19 WHERE a19.id = cm.instance)<br />
WHEN cm.module = 20 THEN (SELECT a20.name FROM prefix_url a20 WHERE a20.id = cm.instance)<br />
WHEN cm.module = 21 THEN (SELECT a21.name FROM prefix_wiki a21 WHERE a21.id = cm.instance)<br />
WHEN cm.module = 22 THEN (SELECT a22.name FROM prefix_workshop a22 WHERE a22.id = cm.instance)<br />
END AS Actvityname,<br />
# cm.section AS Coursesection,<br />
CASE<br />
WHEN cm.completion = 0 THEN '0 None'<br />
WHEN cm.completion = 1 THEN '1 Self'<br />
WHEN cm.completion = 2 THEN '2 Auto'<br />
END AS Activtycompletiontype, <br />
CASE<br />
WHEN cmc.completionstate = 0 THEN 'In Progress'<br />
WHEN cmc.completionstate = 1 THEN 'Completed'<br />
WHEN cmc.completionstate = 2 THEN 'Completed with Pass'<br />
WHEN cmc.completionstate = 3 THEN 'Completed with Fail'<br />
ELSE 'Unknown'<br />
END AS 'Progress', <br />
DATE_FORMAT(FROM_UNIXTIME(cmc.timemodified), '%Y-%m-%d %H:%i') AS 'When'<br />
FROM prefix_course_modules_completion cmc <br />
JOIN prefix_user u ON cmc.userid = u.id<br />
JOIN prefix_course_modules cm ON cmc.coursemoduleid = cm.id<br />
JOIN prefix_course c ON cm.course = c.id<br />
JOIN prefix_modules m ON cm.module = m.id<br />
# skip the predefined admin and guest user<br />
WHERE u.id > 2<br />
# config reports filters<br />
%%FILTER_USERS:u.username%%<br />
%%FILTER_SEARCHTEXT:m.name:~%%<br />
%%FILTER_STARTTIME:cmc.timemodified:>%% %%FILTER_ENDTIME:cmc.timemodified:<%%<br />
<br />
ORDER BY u.username<br />
<br />
</code><br />
<br />
===How many SCORM activities are used in each Course===<br />
<code sql><br />
SELECT cm.course,c.fullname ,m.name <br />
,concat('<a target="_new" href="%%WWWROOT%%/mod/scorm/index.php?id=',c.id,'">',count(cm.id),'</a>') AS Counter<br />
<br />
FROM `prefix_course_modules` as cm <br />
JOIN prefix_modules as m ON cm.module=m.id <br />
JOIN prefix_course as c ON cm.course = c.id <br />
WHERE m.name LIKE '%scorm%' <br />
GROUP BY cm.course,cm.module <br />
ORDER BY count(cm.id) desc<br />
</code><br />
<br />
===SCORM Usage by Course Start Date===<br />
Contributed by Elizabeth Dalton, Granite State College <br />
<br />
Report of number of inclusions of SCORM activities in courses, filtered by course start date.<br />
<br />
<code sql><br />
SELECT <br />
<br />
CONCAT('<a target="_blank" href="%%WWWROOT%%/course/view.php',CHAR(63),'id=',c.id,'">',c.shortname,'</a>') AS 'course'<br />
<br />
, cc.name AS 'Category'<br />
, scm.name AS 'Sample Activity Name'<br />
, FROM_UNIXTIME(c.startdate) AS 'Course Start Date'<br />
, COUNT(DISTINCT cm.id) AS 'Resources Used'<br />
#, FROM_UNIXTIME(cm.added) AS 'resource added'<br />
<br />
<br />
FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id AND m.name LIKE 'SCO%'<br />
<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
JOIN prefix_scorm AS scm ON scm.id = cm.instance<br />
<br />
WHERE<br />
1<br />
<br />
%%FILTER_STARTTIME:c.startdate:>%%<br />
%%FILTER_ENDTIME:c.startdate:<%%<br />
<br />
GROUP BY c.shortname, m.name<br />
ORDER BY c.startdate, c.shortname <br />
</code><br />
<br />
=== LTI (External Tool) Usage by Course Start Date===<br />
Contributed by Elizabeth Dalton, Granite State College <br />
<br />
Report of number of inclusions of LTI (External Tool) Usage activities in courses, filtered by course start date.<br />
<br />
<code sql><br />
SELECT <br />
<br />
CONCAT('<a target="_blank" href="%%WWWROOT%%/course/view.php',CHAR(63),'id=',c.id,'">',c.shortname,'</a>') AS 'course'<br />
<br />
, cc.name AS 'Category'<br />
, lti.name AS 'Sample Activity Name'<br />
, FROM_UNIXTIME(c.startdate) AS 'Course Start Date'<br />
, COUNT(DISTINCT cm.id) AS 'Resources Used'<br />
#, FROM_UNIXTIME(cm.added) AS 'resource added'<br />
<br />
<br />
FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id AND m.name LIKE 'lti'<br />
<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
JOIN prefix_lti AS lti ON lti.id = cm.instance<br />
WHERE<br />
1<br />
<br />
%%FILTER_STARTTIME:c.startdate:>%%<br />
%%FILTER_ENDTIME:c.startdate:<%%<br />
<br />
GROUP BY c.shortname, m.name<br />
ORDER BY c.startdate, c.shortname <br />
</code><br />
<br />
===Detailed ACTIONs for each MODULE===<br />
<code sql><br />
SELECT module,action,count(id) as counter<br />
FROM prefix_log<br />
GROUP BY module,action<br />
ORDER BY module,counter desc<br />
</code><br />
<br />
===Most popular ACTIVITY===<br />
<code sql><br />
SELECT COUNT(l.id) hits, module<br />
FROM prefix_log l<br />
WHERE module != 'login' AND module != 'course' AND module != 'role'<br />
GROUP BY module<br />
ORDER BY hits DESC<br />
</code><br />
<br />
===System wide use of ACTIVITIES and RESOURCES===<br />
<code sql><br />
SELECT count( cm.id ) AS counter, m.name<br />
FROM `prefix_course_modules` AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
GROUP BY cm.module<br />
ORDER BY counter DESC<br />
</code><br />
<br />
===LOG file ACTIONS per MODULE per COURSE (IDs)===<br />
<code sql><br />
select course,module,action,count(action) as summa from prefix_log<br />
where action <> 'new'<br />
group by course,action,module<br />
order by course,module,action<br />
</code><br />
<br />
===System Wide usage count of various course Activities===<br />
(Tested and works fine in Moodle 2.x)<br />
Like: Forum, Wiki, Blog, Assignment, Database,<br />
#Within specific category<br />
#Teacher name in course<br />
<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') as Course<br />
<br />
,(SELECT CONCAT(u.firstname,' ', u.lastname) AS Teacher<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS Teacher <br />
<br />
,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%') AS Wikis<br />
,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
WHERE cm.course = c.id AND m.name LIKE '%blog%') AS Blogs<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
WHERE cm.course = c.id AND m.name LIKE '%forum%') AS Forums<br />
<br />
,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
WHERE cm.course = c.id AND m.name LIKE '%data%') AS Databses<br />
<br />
,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
WHERE cm.course = c.id AND m.name LIKE '%assignment%') AS Assignments<br />
<br />
,(SELECT Count( ra.userid ) AS Users FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = c.id) AS Students<br />
<br />
FROM prefix_course AS c<br />
WHERE c.category IN ( 18)<br />
ORDER BY Wikis DESC,Blogs DESC, Forums DESC<br />
</code><br />
<br />
===Course wiki usage/activity over the last 6 semesters===<br />
<code sql><br />
SELECT "Courses with Wikis"<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%'<br />
and c.fullname LIKE CONCAT('%','2010','%') and c.fullname LIKE '%Semester A%') AS '2010 <br/> Semester A'<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%'<br />
and c.fullname LIKE CONCAT('%','2010','%') and c.fullname LIKE '%Semester B%') AS '2010 <br/> Semester B'<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%'<br />
and c.fullname LIKE CONCAT('%','תשעא','%') and c.fullname LIKE '%סמסטר א%') AS 'תשעא <br/> סמסטר א'<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%'<br />
and c.fullname LIKE CONCAT('%','תשעא','%') and c.fullname LIKE '%סמסטר ב%') AS 'תשעא <br/> סמסטר ב'<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%'<br />
and c.fullname LIKE CONCAT('%','תשעב','%') and c.fullname LIKE '%סמסטר א%') AS 'תשעב <br/> סמסטר א'<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%'<br />
and c.fullname LIKE CONCAT('%','תשעב','%') and c.fullname LIKE '%סמסטר ב%') AS 'תשעב <br/> סמסטר ב'<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%'<br />
and c.fullname LIKE CONCAT('%','תשעג','%') and c.fullname LIKE '%סמסטר א%') AS 'תשעג <br/> סמסטר א'<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%'<br />
and c.fullname LIKE CONCAT('%','תשעג','%') and c.fullname LIKE '%סמסטר ב%') AS 'תשעג <br/> סמסטר ב'<br />
</code><br />
<br />
===Detailed WIKI activity (per wiki per course)===<br />
Including Number of Students in course (for reference)<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',cm.course,'">',c.fullname,'</a>') as CourseID <br />
,(SELECT Count( ra.userid ) AS Users<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = c.id ) AS Students<br />
,m.name<br />
, ( SELECT count(id) FROM prefix_log WHERE cmid = cm.id AND action LIKE '%updat%' ) as 'UPDAT E'<br />
, ( SELECT count(id) FROM prefix_log WHERE cmid = cm.id AND action LIKE '%annotate%' ) as ANNOTATE<br />
, ( SELECT count(id) FROM prefix_log WHERE cmid = cm.id AND action LIKE '%comment%' ) as COMMENT<br />
, ( SELECT count(id) FROM prefix_log WHERE cmid = cm.id AND action LIKE '%add%' ) as 'A DD'<br />
, ( SELECT count(id) FROM prefix_log WHERE cmid = cm.id AND action LIKE '%edit%' ) as EDIT<br />
, ( SELECT count(id) FROM prefix_log WHERE cmid = cm.id AND action NOT LIKE '%view%' ) as 'All (NO View)'<br />
FROM `prefix_course_modules` as cm <br />
JOIN prefix_modules as m ON cm.module=m.id <br />
JOIN prefix_course as c ON cm.course = c.id <br />
WHERE m.name LIKE '%wiki%'<br />
GROUP BY cm.course,cm.module<br />
ORDER BY 'All (NO View)' DESC<br />
</code><br />
<br />
===Wiki usage, system wide===<br />
(you can filter the output by selecting some specific course categories : "WHERE c.category IN ( 8,13,15)")<br />
<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') as Course<br />
<br />
,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%') AS Wikis<br />
<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.course = c.id AND l.module LIKE '%wiki%') AS 'WikiActivity<br/>ALL'<br />
<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.course = c.id AND l.module LIKE '%wiki%' and l.action LIKE '%add%' ) AS 'WikiActivity<br/>ADD'<br />
<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.course = c.id AND l.module LIKE '%wiki%' and l.action LIKE '%edit%' ) AS 'WikiActivity<br/>EDIT'<br />
<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.course = c.id AND l.module LIKE '%wiki%' and l.action LIKE '%annotate%' ) AS 'WikiActivity<br/>ANNOTATE'<br />
<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.course = c.id AND l.module LIKE '%wiki%' and l.action LIKE '%comments%' ) AS 'WikiActivity<br/>Comments'<br />
<br />
,(SELECT Count( ra.userid ) AS Users FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = c.id) AS Students<br />
<br />
,(SELECT count(*) FROM prefix_ouwiki_pages as ouwp<br />
JOIN prefix_ouwiki as ouw ON ouw.id = ouwp.subwikiid<br />
WHERE ouw.course = c.id GROUP BY ouw.course ) as OUWikiPages<br />
<br />
,(SELECT count( DISTINCT nwp.pagename ) FROM prefix_wiki_pages AS nwp<br />
JOIN prefix_wiki AS nw ON nw.id = nwp.dfwiki WHERE nw.course = c.id ) As NWikiPages<br />
<br />
FROM prefix_course AS c<br />
WHERE c.category IN ( 8,13,15)<br />
HAVING Wikis > 0<br />
ORDER BY 'WikiActivity<br/>ALL' DESC<br />
</code><br />
<br />
===Aggregated Teacher activity by "WEB2" Modules===<br />
(Tested and works fine in Moodle 2.x)<br />
The NV column shows activity without VIEW log activity<br />
<code sql><br />
SELECT ra.userid, u.firstname,u.lastname<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.userid = u.id AND l.module LIKE '%wiki%') AS Wiki<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.userid = u.id AND l.module LIKE '%wiki%' AND l.action NOT LIKE '%view%') AS Wiki_NV<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.userid = u.id AND l.module LIKE '%forum%') AS Forum<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.userid = u.id AND l.module LIKE '%forum%' AND l.action NOT LIKE '%view%') AS Forum_NV<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.userid = u.id AND l.module LIKE '%blog%') AS Blog<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.userid = u.id AND l.module LIKE '%blog%' AND l.action NOT LIKE '%view%') AS Blog_NV<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.userid = u.id AND l.module LIKE '%assignment%') AS Assignment<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.userid = u.id AND l.module LIKE '%assignment%' AND l.action NOT LIKE '%view%') AS Assignment_NV<br />
FROM prefix_role_assignments AS ra <br />
JOIN prefix_user AS u ON u.id = ra.userid <br />
WHERE ra.roleid = 3 <br />
GROUP BY ra.userid<br />
</code><br />
<br />
===List all the certificates issued, sort by variables in the custom profile fields===<br />
Note: The SQL queries look intimidating at first, but isn't really that difficult to learn. I've seen in the forums that users wanted to do 'site-wide' groups in 1.9x. This is sort of the idea. It pulls all the certificates issued to all users sorted by the custom profile fields, which in my case is the Units or Depts (i.e. my site wide groups). Why certificates? I've explored with both grades and quizzes, the course admins are not really interested in the actual grades but whether the learner received a certificate (i.e. passed the course with x, y, z activities). It also saves me from creating groups and assigning them into the right groups. Even assigning in bulk is not efficient, since I have upward of 25 groups per course and constantly new learners enrolling in courses. The limitation is something to do with the server? as it only pull 5000 rows of data. If anyone figured out how to change this, please let me know. In the meantime, the work around is to pull only a few units/depts at a time to limit the number of rows. This is fine at the moment, since each course admin are only responsible for certain units/depts.<br />
<br />
<code sql><br />
SELECT<br />
DATE_FORMAT( FROM_UNIXTIME(prefix_certificate_issues.timecreated), '%Y-%m-%d' ) AS Date,<br />
prefix_certificate_issues.classname AS Topic,<br />
prefix_certificate.name AS Certificate,<br />
prefix_certificate_issues.studentname as Name,<br />
prefix_user_info_data.data AS Units<br />
<br />
FROM<br />
prefix_certificate_issues<br />
<br />
INNER JOIN prefix_user_info_data<br />
on prefix_certificate_issues.userid = prefix_user_info_data.userid<br />
<br />
INNER JOIN prefix_certificate<br />
on prefix_certificate_issues.certificateid = prefix_certificate.id<br />
<br />
WHERE prefix_user_info_data.data='Unit 1'<br />
OR prefix_user_info_data.data='Unit 2'<br />
OR prefix_user_info_data.data='Unit 3'<br />
<br />
ORDER BY Units, Name, Topic ASC<br />
</code><br />
<br />
<br />
=== All Simple Certificates Earned in the Site===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
Basic report of all certificates earned with the Simple Certificate plugin module in the whole site, sorted by most recent first. (Note: this uses the MySQL [http://www.mysqltutorial.org/mysql-date_format/ DATE_FORMAT] function.)<br />
<br />
<code sql><br />
SELECT<br />
CONCAT (u.firstname, ' ',u.lastname) As 'User',<br />
c.fullname AS 'Course',<br />
sc.name AS 'Certificate',<br />
DATE_FORMAT( FROM_UNIXTIME(sci.timecreated), '%Y-%m-%d' ) As 'Date Awarded'<br />
# sci.code 'CertificateId'<br />
FROM prefix_simplecertificate_issues sci<br />
JOIN prefix_user u ON sci.userid = u.id<br />
JOIN prefix_simplecertificate sc ON sci.certificateid = sc.id<br />
JOIN prefix_course AS c ON sc.course = c.id<br />
ORDER BY sci.timecreated DESC<br />
</code><br />
<br />
If you want to limit this to the most recent ones, you can add a condition to limit it to a certain number of days past. For example, adding this WHERE clause (above the ORDER BY) will show only those earned in the last 30 days:<br />
<code sql><br />
WHERE DATEDIFF(NOW(),FROM_UNIXTIME(sci.timecreated) ) < 30<br />
</code><br />
<br />
===Counter Blog usage in Courses,system wide===<br />
What teachers in what courses, uses blogs and how many + student count in that course.<br />
<code sql><br />
<br />
SELECT ( @counter := @counter+1) as counter, <br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') as Course<br />
<br />
,( SELECT DISTINCT CONCAT(u.firstname,' ',u.lastname)<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_user AS u ON ra.userid = u.id<br />
JOIN prefix_context AS ctx ON ctx.id = ra.contextid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id AND ctx.contextlevel = 50 LIMIT 1) AS Teacher<br />
<br />
,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
WHERE cm.course = c.id AND m.name LIKE '%blog%') AS Blogs<br />
<br />
,(SELECT Count( ra.userid ) AS Users FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = c.id) AS Students<br />
<br />
FROM prefix_course AS c, (SELECT @counter := 0) as s_init<br />
WHERE c.category IN ( 8,13,15)<br />
HAVING Blogs > 0<br />
ORDER BY Blogs DESC<br />
</code><br />
<br />
=== Elluminate (Blackboard Collaborate) - system wide usage===<br />
<code sql><br />
SELECT e.name As Session ,er.recordingsize<br />
,c.fullname As Course<br />
,u.firstname,u.lastname <br />
,DATE_FORMAT(FROM_UNIXTIME(e.timestart),'%d-%m-%Y') AS dTimeStart<br />
,concat('<a target="_new" href="%%WWWROOT%%/moodle/mod/elluminate/loadrecording.php?id=',er.id,'">Show</a>') AS RecordedSession<br />
<br />
FROM prefix_elluminate_recordings AS er<br />
JOIN prefix_elluminate AS e ON e.meetingid = er.meetingid<br />
JOIN prefix_course as c ON c.id = e.course<br />
JOIN prefix_user AS u ON u.id = e.creator <br />
ORDER BY er.recordingsize DESC<br />
</code><br />
<br />
<br />
=== Choice ===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
Results of the Choice activity. For all courses, shows course shortname, username, the Choice text, and the answer chosen by the user.<br />
<br />
<code sql><br />
SELECT c.shortname AS course, u.username, h.name as question, o.text AS answer<br />
FROM prefix_choice AS h<br />
JOIN prefix_course AS c ON h.course = c.id<br />
JOIN prefix_choice_answers AS a ON h.id = a.choiceid<br />
JOIN prefix_user AS u ON a.userid = u.id<br />
JOIN prefix_choice_options AS o ON a.optionid = o.id<br />
</code><br />
<br />
=== Assignment type usage in courses ===<br />
<code sql><br />
SELECT <br />
<br />
CONCAT('<a target="_new" href="%%WWWROOT%%/mod/assign/index.php?id=',c.id,'">',c.fullname,'</a>') AS "List assignments"<br />
<br />
,(SELECT COUNT(*) FROM prefix_assign WHERE c.id = course) AS Assignments<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_assign_plugin_config AS apc<br />
JOIN prefix_assign AS iassign ON iassign.id = apc.assignment <br />
WHERE iassign.course = c.id AND apc.plugin = 'file' AND apc.subtype = 'assignsubmission' AND apc.name = 'enabled' AND apc.value = '1'<br />
#GROUP BY apc.plugin<br />
) AS "File Assignments"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_assign_plugin_config AS apc<br />
JOIN prefix_assign AS iassign ON iassign.id = apc.assignment <br />
WHERE iassign.course = c.id AND apc.plugin = 'onlinetext' AND apc.subtype = 'assignsubmission' AND apc.name = 'enabled' AND apc.value = '1'<br />
) AS "Online Assignments"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_assign_plugin_config AS apc<br />
JOIN prefix_assign AS iassign ON iassign.id = apc.assignment <br />
WHERE iassign.course = c.id AND apc.plugin = 'pdf' AND apc.subtype = 'assignsubmission' AND apc.name = 'enabled' AND apc.value = '1'<br />
) AS "PDF Assignments"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_assign_plugin_config AS apc<br />
JOIN prefix_assign AS iassign ON iassign.id = apc.assignment <br />
WHERE iassign.course = c.id AND apc.plugin = 'offline' AND apc.subtype = 'assignsubmission' AND apc.name = 'enabled' AND apc.value = '1'<br />
) AS "Offline Assignments"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_assign_plugin_config AS apc<br />
JOIN prefix_assign AS iassign ON iassign.id = apc.assignment <br />
WHERE iassign.course = c.id AND apc.plugin = 'comments' AND apc.subtype = 'assignsubmission' AND apc.name = 'enabled' AND apc.value = '1'<br />
) AS "Assignments Comments"<br />
<br />
FROM prefix_assign AS assign<br />
JOIN prefix_course AS c ON c.id = assign.course<br />
GROUP BY c.id <br />
</code><br />
<br />
==Moodle Learning Analytics Reports==<br />
<br />
===Average Cognitive Depth and Social Breadth===<br />
<br />
Here is a simple SQL snippet to calculate average cognitive depth and social breadth indicators for all students in the system. This one ignores indicator values of 0, as they are nulls as defined in this model.<br />
Contributed by Elizabeth Dalton, Moodle HQ<br />
<br />
<code sql><br />
SELECT<br />
<br />
i.contextid,<br />
i.sampleid,<br />
<br />
TRUNC(AVG(CASE<br />
WHEN i.indicator LIKE '%cognitive%' THEN i.value <br />
ELSE '0'<br />
END),2) AS "Average Cognitive Depth",<br />
<br />
TRUNC(AVG(CASE<br />
WHEN i.indicator LIKE '%social%' THEN i.value <br />
ELSE '0'<br />
END),2) AS "Average Social Breadth"<br />
<br />
FROM prefix_analytics_indicator_calc as i<br />
WHERE<br />
i.value != 0<br />
GROUP BY i.contextid, i.sampleid<br />
</code><br />
<br />
==Assignment Module Reports==<br />
===All Ungraded Assignments===<br />
<br />
'''NOTE: This query is for the deprecated old Assignment module from Moodle 2.2, not the new Assignments module. Please update this query if you are the author or it will be removed as the 2.2 Assignment module is no longer supported since release 2.7.<br />
''' See: [https://docs.moodle.org/dev/Moodle_2.7_release_notes#Assignment]<br />
<br />
Returns all the submitted assignments that still need grading<br />
<code sql><br />
select <br />
u.firstname AS "First",<br />
u.lastname AS "Last",<br />
c.fullname AS "Course",<br />
a.name AS "Assignment"<br />
<br />
from prefix_assignment_submissions as asb<br />
join prefix_assignment as a ON a.id = asb.assignment<br />
join prefix_user as u ON u.id = asb.userid<br />
join prefix_course as c ON c.id = a.course<br />
join prefix_course_modules as cm ON c.id = cm.course<br />
<br />
where asb.grade < 0 and cm.instance = a.id<br />
and cm.module = 1<br />
<br />
order by c.fullname, a.name, u.lastname<br />
</code><br />
<br />
===All Ungraded Assignments w/ Link===<br />
<br />
'''NOTE: This query is for the deprecated old Assignment module from Moodle 2.2, not the new Assignments module. Please update this query if you are the author or it will be removed as the 2.2 Assignment module is no longer supported since release 2.7.<br />
''' See: [https://docs.moodle.org/dev/Moodle_2.7_release_notes#Assignment]<br />
<br />
<br />
Returns all the submitted assignments that still need grading, along with a link that goes directly to the submission to grade it. The links work if you view the report within Moodle.<br />
<code sql><br />
select <br />
u.firstname AS "First",<br />
u.lastname AS "Last",<br />
c.fullname AS "Course",<br />
a.name AS "Assignment",<br />
<br />
'<a href="http://education.varonis.com/mod/assignment/submissions.php' + char(63) +<br />
+ 'id=' + cast(cm.id as varchar) + '&userid=' + cast(u.id as varchar) <br />
+ '&mode=single&filter=0&offset=2">' + a.name + '</a>'<br />
AS "Assignmentlink"<br />
<br />
<br />
from prefix_assignment_submissions as asb<br />
join prefix_assignment as a ON a.id = asb.assignment<br />
join prefix_user as u ON u.id = asb.userid<br />
join prefix_course as c ON c.id = a.course<br />
join prefix_course_modules as cm ON c.id = cm.course<br />
<br />
where asb.grade < 0 and cm.instance = a.id and cm.module = 1<br />
<br />
order by c.fullname, a.name, u.lastname<br />
</code><br />
<br />
===Assignments (and Quizzes) waiting to be graded===<br />
<br />
'''NOTE: This query is for the deprecated old Assignment module from Moodle 2.2, not the new Assignments module. Please update this query if you are the author or it will be removed as the 2.2 Assignment module is no longer supported since release 2.7.<br />
''' See: [https://docs.moodle.org/dev/Moodle_2.7_release_notes#Assignment]<br />
<br />
<br />
This report requires a YEAR filter to be added (Available when using the latest block/configurable_reports)<br />
<br />
Which you can always remove, to make this query work on earlier versions.<br />
<br />
The report includes: <br />
*number of quizzes<br />
*unFinished Quiz attempts<br />
*Finished Quiz attempts<br />
*number of students<br />
*number of Assignments<br />
*number of submitted answers by students <br />
*number of unchecked assignments (waiting for the Teacher) in a Course.<br />
<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS Course<br />
<br />
,(SELECT CONCAT(u.firstname,' ', u.lastname) AS Teacher<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS Teacher <br />
<br />
,concat('<a target="_new" href="%%WWWROOT%%/mod/assignment/index.php?id=',c.id,'">מטלות</a>') AS Assignments<br />
<br />
,concat('<a target="_new" href="%%WWWROOT%%/mod/quiz/index.php?id=',c.id,'">בחנים</a>') AS 'Quizzes'<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_course_modules cm <br />
JOIN prefix_modules as m ON m.id = cm.module <br />
WHERE m.name LIKE 'quiz' AND cm.course = c.id <br />
GROUP BY cm.course <br />
) AS 'nQuizzes'<br />
<br />
,(SELECT COUNT(*)<br />
FROM prefix_quiz_attempts AS qa<br />
JOIN prefix_quiz AS q ON q.id = qa.quiz<br />
WHERE q.course = c.id<br />
AND qa.timefinish = 0<br />
GROUP BY q.course) AS 'unFinished Quiz attempts'<br />
<br />
,(SELECT COUNT(*)<br />
FROM prefix_quiz_attempts AS qa<br />
JOIN prefix_quiz AS q ON q.id = qa.quiz<br />
WHERE q.course = c.id<br />
AND qa.timefinish > 0<br />
GROUP BY q.course) AS 'finished quiz attempts'<br />
<br />
,(SELECT Count( ra.userid ) AS Users<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5<br />
AND ctx.instanceid = c.id<br />
) AS nStudents<br />
<br />
<br />
,(<br />
SELECT count(a.id)<br />
FROM prefix_assignment AS a <br />
JOIN prefix_course_modules AS cm ON a.course = cm.course <br />
WHERE cm.instance = a.id AND cm.module = 1 AND a.course = c.id<br />
) nAssignments<br />
<br />
,(<br />
SELECT count(*)<br />
FROM prefix_assignment AS a <br />
WHERE a.course = c.id AND FROM_UNIXTIME(a.timedue) > NOW()<br />
GROUP BY a.course<br />
) 'Open <br/>Assignments'<br />
<br />
, CONCAT(ROUND( (100 / iAssignments ) * iOpenAssignments ) ,'%') 'unFinished <br/>Assignments <br/>(percent)'<br />
<br />
,(<br />
SELECT count(asb.id)<br />
FROM prefix_assignment_submissions AS asb<br />
JOIN prefix_assignment AS a ON a.id = asb.assignment<br />
JOIN prefix_course_modules AS cm ON a.course = cm.course <br />
WHERE asb.grade < 0 AND cm.instance = a.id AND cm.module = 1 AND a.course = c.id<br />
) 'unChecked <br/>Submissions' <br />
<br />
,(<br />
SELECT count(asb.id)<br />
FROM prefix_assignment_submissions AS asb<br />
JOIN prefix_assignment AS a ON a.id = asb.assignment<br />
JOIN prefix_course_modules AS cm ON a.course = cm.course <br />
WHERE cm.instance = a.id AND cm.module = 1 AND a.course = c.id<br />
) 'Submitted <br/>Assignments'<br />
<br />
FROM prefix_course AS c<br />
LEFT JOIN (<br />
SELECT course, count(*) AS iAssignments<br />
FROM prefix_assignment AS a <br />
GROUP BY a.course <br />
) AS tblAssignmentsCount ON tblAssignmentsCount.course = c.id<br />
<br />
LEFT JOIN (<br />
SELECT course, count(*) AS iOpenAssignments<br />
FROM prefix_assignment AS a <br />
WHERE FROM_UNIXTIME(a.timedue) > NOW()<br />
GROUP BY a.course <br />
) AS tblOpenAssignmentsCount ON tblOpenAssignmentsCount.course = c.id<br />
<br />
WHERE 1=1 <br />
#AND c.fullname LIKE '%תשעג%'<br />
%%FILTER_YEARS:c.fullname%%<br />
## You can enable the SEMESTER filter as well, <br />
## by uncommenting the following line:<br />
## %%FILTER_SEMESTERS:c.fullname%%<br />
ORDER BY 'Open <br/>Assignments' DESC<br />
</code><br />
<br />
===Rubrics without zero values in criteria===<br />
Contributed by Eric Strom<br />
<br />
Rubric calculations in Moodle can fail to align with instructors expectations if they lack a zero value for each criterion used in the assessment. From documentation at https://docs.moodle.org/32/en/Rubrics#Grade_calculation:<br />
<br />
"For example, when the teacher in the previous example chose both levels with 1 point, the plain sum would be 2 points. But that is actually the lowest possible score so it maps to the grade 0 in Moodle.<br />
TIP: To avoid confusion from this sort of thing, we recommend including a level with 0 points in every rubric criterion."<br />
<br />
This report identifies rubrics having criteria without a zero value level and the courses they live in. This also refines to only assignments with active rubrics that are visible to students in the course. Links to the each rubric id is the direct link to edit the rubric. Fix by adding a zero level for each criteria that is missing it. In general, the grading changes that result will be in the students' favor.<br />
<br />
Includes search filter of course idnumber.<br />
<br />
<code sql><br />
SELECT cat.name AS Department, concat('<a target="_new" href="%%WWWROOT%%/course/view.php',CHAR(63),'id=',<br />
c.id,'">',c.idnumber,'</a>') AS Course_ID, <br />
c.fullname AS Course_Name, <br />
concat('<a target="_new" href="%%WWWROOT%%/grade/grading/form/rubric/edit.php',CHAR(63),'areaid=',gd.areaid,'">',gd.areaid,'</a>') AS Rubric<br />
FROM prefix_course AS c<br />
JOIN prefix_course_categories AS cat <br />
ON cat.id = c.category<br />
JOIN prefix_course_modules AS cm <br />
ON c.id=cm.course<br />
JOIN prefix_context AS ctx <br />
ON cm.id = ctx.instanceid<br />
JOIN prefix_grading_areas AS garea <br />
ON ctx.id = garea.contextid<br />
JOIN prefix_grading_definitions AS gd <br />
ON garea.id = gd.areaid<br />
JOIN prefix_gradingform_rubric_criteria AS crit <br />
ON gd.id = crit.definitionid<br />
JOIN prefix_gradingform_rubric_levels AS levels <br />
ON levels.criterionid = crit.id<br />
WHERE cm.visible='1' AND garea.activemethod = 'rubric' AND (crit.id NOT IN<br />
(SELECT crit.id<br />
FROM prefix_gradingform_rubric_criteria AS crit<br />
JOIN prefix_gradingform_rubric_levels AS levels <br />
ON levels.criterionid = crit.id WHERE levels.score = '0'))<br />
<br />
GROUP BY Rubric<br />
ORDER BY Course_ID, Rubric<br />
<br />
%%FILTER_SEARCHTEXT:c.idnumber:~%%<br />
</code><br />
<br />
===Who is using "Single File Upload" assignment===<br />
<code sql><br />
SELECT <br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS Course<br />
<br />
,(SELECT CONCAT(u.firstname,' ', u.lastname) AS Teacher<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS Teacher <br />
<br />
,ass.name as "Assignment Name"<br />
<br />
FROM <br />
prefix_assignment as ass<br />
<br />
JOIN <br />
prefix_course as c ON c.id = ass.course<br />
<br />
WHERE `assignmenttype` LIKE 'uploadsingle'<br />
</code><br />
<br />
==Feedback Module Reports==<br />
===List the answers to all the Feedback activities within the current course, submitted by the current user===<br />
<code sql><br />
SELECT /* crs.fullname as "Course name", f.name AS "Journal name", CONCAT(u.firstname,' ',UPPER(u.lastname)) as "Participant", */ /* include these fields if you want to check the composition of the recordset */<br />
DATE_FORMAT(FROM_UNIXTIME(c.timemodified),'%W %e %M, %Y') as "Answer Date",<br />
CASE i.typ WHEN 'label' THEN i.presentation ELSE i.name END as "Topic", /* usually labels are used as section titles, so you'd want them present in the recordset */<br />
v.value as "My Answer"<br />
<br />
FROM prefix_feedback AS f<br />
INNER JOIN prefix_course as crs on crs.id=f.course %%FILTER_COURSES:f.course%% <br />
INNER JOIN prefix_feedback_item AS i ON f.id=i.feedback<br />
INNER JOIN prefix_feedback_completed AS c on f.id=c.feedback %%FILTER_COURSEUSER:c.userid%% <br />
LEFT JOIN prefix_feedback_value AS v on v.completed=c.id AND v.item=i.id<br />
INNER JOIN prefix_user AS u on c.userid=u.id<br />
<br />
WHERE c.id = %%COURSEID%% AND u.id = %%USERID%% AND c.anonymous_response = 1 /* This clause limits the recordset to the current course and the current user and includes/ excludes the anonymous responses as needed */<br />
<br />
ORDER BY f.id, c.timemodified, i.id<br />
</code><br />
<br />
===Show all Feedbacks from all courses for all users including showing names of anonymous users===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
Shows all Feedbacks in all Courses with all multi-choice questions and answers of all users including showing the username of anonymous users. Also shows tryly anonymous users on the front page as 'Not-logged-in' users. This is a rough report, not a pretty report, and is limited to multiple-choice type questions, but is shows the answer number and the list of possible answers in raw form. I post it here as a basis for further reports, and also as away to get the identities of anonymous users if needed.<br />
<br />
<code sql><br />
SELECT <br />
c.shortname AS Course, <br />
f.name AS Feedback,<br />
# i.id AS Itemid,<br />
i.name AS Itemname,<br />
i.label AS Itemlabel,<br />
CASE <br />
WHEN f.anonymous = 1 AND u.id != 0 THEN CONCAT(u.username, ' :ANON')<br />
WHEN fc.userid = 0 THEN 'Not-logged-in'<br />
ELSE u.username<br />
END AS 'User',<br />
DATE_FORMAT(FROM_UNIXTIME(fc.timemodified),'%Y-%m-%d %H:%i') AS "Completed",<br />
v.value AS "Choice",<br />
CASE <br />
WHEN i.typ = 'multichoice' THEN<br />
IF ( SUBSTRING(i.presentation,1,6)='d>>>>>',<br />
SUBSTRING(i.presentation,7),<br />
i.presentation)<br />
ELSE i.presentation<br />
END AS "Answers",<br />
i.typ,<br />
i.dependitem,<br />
i.dependvalue<br />
<br />
FROM prefix_feedback f<br />
JOIN prefix_course c ON c.id=f.course <br />
JOIN prefix_feedback_item AS i ON f.id=i.feedback<br />
JOIN prefix_feedback_completed fc ON f.id=fc.feedback<br />
LEFT JOIN prefix_feedback_value v ON v.completed=fc.id AND v.item=i.id<br />
LEFT JOIN prefix_user AS u ON fc.userid=u.id<br />
WHERE i.typ != 'pagebreak'<br />
</code><br />
<br />
==Resource Module Reports==<br />
===List "Recently uploaded files"===<br />
see what users are uploading<br />
<code sql><br />
SELECT FROM_UNIXTIME(time,'%Y %M %D %h:%i:%s') as time ,ip,userid,url,info <br />
FROM `prefix_log` <br />
WHERE `action` LIKE 'upload' <br />
ORDER BY `prefix_log`.`time` DESC<br />
</code><br />
<br />
===List Courses that loaded a specific file: "X"===<br />
Did the Teacher (probably) uploaded course's Syllabus ?<br />
<code sql><br />
SELECT c.id, c.fullname FROM `prefix_log` as l <br />
JOIN prefix_course as c ON c.id = l.course <br />
WHERE `action` LIKE '%upload%' AND ( info LIKE '%Syllabus%' OR info LIKE '%Sylabus%' ) GROUP BY c.id<br />
</code><br />
<br />
===All resources that link to some specific external website===<br />
+ link to course<br />
+ who's the teacher<br />
+ link to external resource<br />
<code sql><br />
SELECT<br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS Course<br />
,c.shortname,r.name<br />
,(SELECT CONCAT(u.firstname,' ', u.lastname) AS Teacher<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS Teacher<br />
,concat('<a target="_new" href="%%WWWROOT%%/mod/resource/view.php?id=',r.id,'">',r.name,'</a>') AS Resource<br />
FROM prefix_resource AS r <br />
JOIN prefix_course AS c ON r.course = c.id<br />
WHERE r.reference LIKE 'http://info.oranim.ac.il/home%' <br />
</code><br />
<br />
==="Compose Web Page" RESOURCE count===<br />
<code sql><br />
SELECT course,prefix_course.fullname, COUNT(*) AS Total<br />
FROM `prefix_resource`<br />
JOIN `prefix_course` ON prefix_course.id = prefix_resource.course<br />
WHERE type='html'<br />
GROUP BY course<br />
</code><br />
<br />
===Resource count in courses===<br />
+ (First)Teacher name<br />
+ Where course is inside some specific Categories<br />
<code sql><br />
SELECT <br />
COUNT(*) AS count<br />
,r.course <br />
,c.shortname shortname<br />
,c.fullname coursename<br />
,( SELECT DISTINCT CONCAT(u.firstname,' ',u.lastname)<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_user as u ON ra.userid = u.id<br />
JOIN prefix_context AS ctx ON ctx.id = ra.contextid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = r.course AND ctx.contextlevel = 50 LIMIT 1) AS Teacher<br />
FROM prefix_resource r <br />
JOIN prefix_course c ON r.course = c.id<br />
WHERE c.category IN (10,13,28,18,26)<br />
GROUP BY r.course<br />
ORDER BY COUNT(*) DESC<br />
</code><br />
<br />
===Delete all the automated backup files===<br />
Prepare bash cli script to delete all the automated backup files on the file system. (clean up some disk space)<br />
<code sql><br />
SELECT CONCAT( 'rm -f /var/moodledatanew/filedir/', SUBSTRING( contenthash, 1, 2 ) , '/', SUBSTRING( contenthash, 3, 2 ) , '/', contenthash ) <br />
FROM `mdl_files` <br />
WHERE `filename` LIKE '%mbz%'<br />
AND filearea = 'automated'<br />
</code><br />
<br />
Find out how much disk space is used by all automated backup files:<br />
<code sql><br />
SELECT SUM(filesize)/(1024*1024*1024) FROM `mdl_files` WHERE `filename` LIKE '%mbz%' AND filearea = 'automated'<br />
</code><br />
<br />
==Forum Module Reports==<br />
===print all User's post in course Forums===<br />
%%COURSEID%% is a variable the is replace by the current CourseID you are running the sql report from. if you are using the latest block/configurable_reports ! (You can always change it to a fixed course or remove it to display all courses.)<br />
<code sql><br />
SELECT <br />
concat('<a target="_new" href="%%WWWROOT%%/mod/forum/user.php?course=',c.id,'&id=',u.id,'&mode=posts">',CONCAT(u.firstname,' ', u.lastname),'</a>') As Fullname<br />
,concat('<a target="_new" href="%%WWWROOT%%/mod/forum/view.php?f=',fd.forum,'">',f.name,'</a>') AS Forum<br />
,count(*) as Posts<br />
,(SELECT count(*) FROM prefix_forum_discussions AS ifd JOIN prefix_forum as iforum ON iforum.id = ifd.forum WHERE ifd.userid = fp.userid AND iforum.id = f.id) AS cAllDiscussion<br />
<br />
FROM prefix_forum_posts AS fp <br />
JOIN prefix_user as u ON u.id = fp.userid <br />
JOIN prefix_forum_discussions AS fd ON fp.discussion = fd.id <br />
JOIN prefix_forum AS f ON f.id = fd.forum <br />
JOIN prefix_course as c ON c.id = fd.course <br />
WHERE fd.course = %%COURSEID%% <br />
GROUP BY f.id,u.id<br />
ORDER BY u.id<br />
</code><br />
<br />
===FORUM use Count per COURSE -- not including NEWS Forum!===<br />
<code sql><br />
SELECT prefix_course.fullname, prefix_forum.course, count(*) as total FROM prefix_forum<br />
INNER JOIN prefix_course<br />
ON prefix_course.id = prefix_forum.course<br />
WHERE NOT(prefix_forum.type = 'news')<br />
GROUP BY prefix_forum.course<br />
ORDER BY total desc<br />
</code><br />
<br />
===FORUM use Count per COURSE by type -- not including NEWS Forum!===<br />
<code sql><br />
SELECT prefix_course.fullname, prefix_forum.course, prefix_forum.type, count(*) as total FROM prefix_forum<br />
INNER JOIN prefix_course<br />
ON prefix_course.id = prefix_forum.course<br />
WHERE NOT(prefix_forum.type = 'news')<br />
GROUP BY prefix_forum.course,prefix_forum.type<br />
ORDER BY total desc<br />
</code><br />
<br />
===Forum activity - system wide===<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.id,'</a>') AS CourseID<br />
,( SELECT DISTINCT CONCAT(u.firstname,' ',u.lastname)<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_user AS u ON ra.userid = u.id<br />
JOIN prefix_context AS ctx ON ctx.id = ra.contextid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id AND ctx.contextlevel = 50 LIMIT 1) AS Teacher<br />
,c.fullname as Course<br />
,f.type<br />
,(SELECT Count( ra.userid ) AS Users FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = c.id) AS Students<br />
, fd.forum, f.name,count(*) AS cPostAndDisc<br />
,(SELECT count(*) FROM prefix_forum_discussions AS ifd WHERE ifd.forum = f.id) AS cDiscussion<br />
FROM prefix_forum_posts AS fp<br />
JOIN prefix_forum_discussions AS fd ON fd.id = fp.discussion<br />
JOIN prefix_forum AS f ON f.id = fd.forum<br />
JOIN prefix_course AS c ON c.id = f.course<br />
WHERE f.type != 'news' AND c.fullname LIKE '%2013%'<br />
## WHERE 1=1 <br />
## %%FILTER_YEARS:c.fullname%%<br />
## You can enable the SEMESTER filter as well, <br />
## by uncommenting the following line:<br />
## %%FILTER_SEMESTERS:c.fullname%%<br />
<br />
GROUP BY fd.forum<br />
ORDER BY count( * ) DESC<br />
</code><br />
<br />
===Activity In Forums===<br />
Trying to figure out how much real activity we have in Forums by aggregating:<br />
Users in Course, Number of Posts, Number of Discussions, Unique student post, Unique student discussions, Number of Teachers , Number of Students, ratio between unique Student posts and the number of students in the Course...<br />
<code sql><br />
SELECT c.fullname,f.name,f.type <br />
,(SELECT count(id) FROM prefix_forum_discussions as fd WHERE f.id = fd.forum) as Discussions<br />
,(SELECT count(distinct fd.userid) FROM prefix_forum_discussions as fd WHERE fd.forum = f.id) as UniqueUsersDiscussions<br />
,(SELECT count(fp.id) FROM prefix_forum_discussions fd JOIN prefix_forum_posts as fp ON fd.id = fp.discussion WHERE f.id = fd.forum) as Posts<br />
,(SELECT count(distinct fp.userid) FROM prefix_forum_discussions fd JOIN prefix_forum_posts as fp ON fd.id = fp.discussion WHERE f.id = fd.forum) as UniqueUsersPosts<br />
,(SELECT Count( ra.userid ) AS Students<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid =5<br />
AND ctx.instanceid = c.id<br />
) AS StudentsCount<br />
,(SELECT Count( ra.userid ) AS Teachers<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid =3<br />
AND ctx.instanceid = c.id<br />
) AS 'Teacher<br/>Count'<br />
,(SELECT Count( ra.userid ) AS Users<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid IN (3,5)<br />
AND ctx.instanceid = c.id<br />
) AS UserCount<br />
, (SELECT (UniqueUsersDiscussions / StudentsCount )) as StudentDissUsage<br />
, (SELECT (UniqueUsersPosts /StudentsCount)) as StudentPostUsage<br />
FROM prefix_forum as f <br />
JOIN prefix_course as c ON f.course = c.id<br />
WHERE `type` != 'news'<br />
ORDER BY StudentPostUsage DESC<br />
</code><br />
<br />
===All Forum type:NEWS===<br />
<code sql><br />
SELECT f.id, f.name<br />
FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_forum AS f ON cm.instance = f.id<br />
WHERE m.name = 'forum'<br />
AND f.type = 'news'<br />
</code><br />
<br />
===All new forum NEWS items (discussions) from all my Courses===<br />
change "userid = 26" and "id = 26" to a new user id<br />
<code sql><br />
SELECT c.shortname,f.name,fd.name,FROM_UNIXTIME(fd.timemodified ,"%d %M %Y ") as Date<br />
FROM prefix_forum_discussions as fd <br />
JOIN prefix_forum as f ON f.id = fd.forum <br />
JOIN prefix_course as c ON c.id = f.course <br />
JOIN prefix_user_lastaccess as ul ON (c.id = ul.courseid AND ul.userid = 26)<br />
WHERE fd.timemodified > ul.timeaccess <br />
AND fd.forum IN (SELECT f.id<br />
FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_forum AS f ON cm.instance = f.id<br />
WHERE m.name = 'forum'<br />
AND f.type = 'news')<br />
AND c.id IN (SELECT c.id<br />
FROM prefix_course AS c<br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid<br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE u.id = 26) ORDER BY `fd`.`timemodified` DESC<br />
</code><br />
<br />
<br />
===News Forum - Discussions COUNT===<br />
Which is actually... How much instructions students get from their teachers<br />
<code sql><br />
SELECT c.shortname ,<br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS Course<br />
,( SELECT DISTINCT CONCAT(u.firstname,' ',u.lastname)<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_user AS u ON ra.userid = u.id<br />
JOIN prefix_context AS ctx ON ctx.id = ra.contextid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id AND ctx.contextlevel = 50 LIMIT 1) AS Teacher<br />
,concat('<a target="_new" href="%%WWWROOT%%/mod/forum/view.php?f=',fd.forum,'">',count(fd.id),'</a>') AS DiscussionsSum<br />
FROM prefix_forum_discussions AS fd<br />
INNER JOIN prefix_forum AS f ON f.id = fd.forum<br />
INNER JOIN prefix_course AS c ON c.id = f.course<br />
WHERE f.type = 'news' AND c.category IN (10,13,28,18,26)<br />
GROUP BY fd.forum<br />
ORDER BY count(fd.id) DESC<br />
</code><br />
<br />
===Cantidad de foros que han sido posteados por profesor===<br />
<br />
(Number of forums that have been posted by teacher/Google translator)<br />
<br />
Queriamos saber cuales son las acciones del profesor dentro de los foros de cada curso, por ello se hizo este informe.<br />
<br />
(We wanted to know what the teacher's actions are in the forums of each course, so this report was made. /Google translator)<br />
<code sql><br />
SELECT <br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.shortname,'</a>') AS curso,<br />
CONCAT(u.firstname ,' ',u.lastname) AS Facilitador,<br />
<br />
(SELECT COUNT( m.name ) AS COUNT FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
WHERE cm.course = c.id AND m.name LIKE '%forum%') AS foros,<br />
<br />
COUNT(*) AS Posts<br />
<br />
FROM prefix_forum_posts AS fp <br />
JOIN prefix_forum_discussions AS fd ON fp.discussion = fd.id <br />
JOIN prefix_forum AS f ON f.id = fd.forum <br />
JOIN prefix_course AS c ON c.id = fd.course<br />
JOIN prefix_user AS u ON u.id = fp.userid <br />
<br />
WHERE fp.userid =<br />
(<br />
select distinct prefix_user.id<br />
from prefix_user <br />
join prefix_role_assignments as ra on ra.userid = prefix_user.id <br />
where ra.roleid = 3 <br />
and userid = fp.userid<br />
limit 1<br />
)<br />
<br />
and c.shortname like '%2014-2-1%'<br />
GROUP BY c.id, u.id<br />
</code><br />
<br />
<br />
===List all the Posts in all the Forums that got high rating===<br />
We setup a scale that let teachers and students Rate forum post with "Important, interesting, valuable, not rated" scale<br />
And then add a link to the following report at the begining of the course "Link to all interesting posts"<br />
<code sql><br />
SELECT <br />
CONCAT('<a target="_new" href="%%WWWROOT%%/mod/forum/view.php?f=',f.id,'">',f.name,'</a>') AS 'Forum name,<br />
CONCAT('<a target="_new" href="%%WWWROOT%%/mod/forum/discuss.php?d=',fd.id,'#p',fp.id,'">',fp.subject,'</a>') AS 'Post link',<br />
SUM(r.rating) AS 'Rating'<br />
FROM mdl_rating AS r<br />
JOIN mdl_forum_posts AS fp ON fp.id = r.itemid<br />
JOIN mdl_forum_discussions AS fd ON fd.id = fp.discussion<br />
JOIN mdl_forum AS f ON f.id = fd.forum<br />
WHERE r.component = 'mod_forum' AND r.ratingarea = 'post' AND f.course = %%COURSEID%%<br />
GROUP BY r.itemid<br />
ORDER BY SUM(r.rating) DESC<br />
</code><br />
<br />
===List all the Posts in all Discussions of a single Forum===<br />
This report is used to help export all the student's posts and discussions of a single forum, by passing the context module id as a parameter to the report using "&filter_var=cmid"<br />
<code sql><br />
SELECT <br />
CONCAT('<a target="_new" href="%%WWWROOT%%/mod/forum/view.php?f=', f.id, '">', f.name, '</a>') AS 'Forum name',<br />
fd.name AS 'Discussion', <br />
CONCAT('<a target="_new" href="%%WWWROOT%%/mod/forum/discuss.php?d=', fd.id, '#p', fp.id, '">', fp.subject, '</a>') AS 'Post (link)',<br />
fp.message<br />
<br />
FROM mdl_forum_posts AS fp <br />
JOIN mdl_forum_discussions AS fd ON fd.id = fp.discussion<br />
JOIN mdl_forum AS f ON f.id = fd.forum<br />
JOIN mdl_course_modules AS cm ON cm.module = 9 AND cm.instance = f.id<br />
WHERE cm.id = %%FILTER_VAR%%<br />
ORDER BY f.id, fd.id<br />
</code><br />
<br />
==Quiz Module Reports==<br />
===Generate a list of instructors and their email addresses for those courses that has "essay questions" in their quizzes===<br />
<code sql><br />
SELECT qu.id AS quiz_id, qu.course AS course_id, qu.questions,<br />
co.fullname AS course_fullname, co.shortname AS course_shortname,<br />
qu.name AS quiz_name, FROM_UNIXTIME(qu.timeopen) AS quiz_timeopen, FROM_UNIXTIME(qu.timeclose) AS quiz_timeclose,<br />
u.firstname, u.lastname, u.email,<br />
FROM prefix_quiz qu, prefix_course co, prefix_role re, prefix_context ct, prefix_role_assignments ra, prefix_user u<br />
WHERE FROM_UNIXTIME(timeopen) > '2008-05-14' AND<br />
qu.course = co.id AND<br />
co.id = ct.instanceid AND<br />
ra.roleid = re.id AND<br />
re.name = 'Teacher' AND<br />
ra.contextid = ct.id AND<br />
ra.userid = u.id<br />
<br />
SELECT Count('x') As NumOfStudents<br />
FROM prefix_role_assignments a<br />
JOIN prefix_user u ON userid = u.id<br />
WHERE roleid = 5 AND contextid = (SELECT id FROM prefix_context WHERE instanceid = 668 AND contextlevel = 50)<br />
</code><br />
<br />
===Number of Quizes per Course===<br />
<code sql><br />
SELECT count(*)<br />
,concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS Course<br />
,concat('<a target="_new" href="%%WWWROOT%%/mod/quiz/index.php?id=',c.id,'">Link</a>') AS Quizes<br />
<br />
FROM prefix_course_modules cm<br />
JOIN prefix_course c ON c.id = cm.course<br />
JOIN prefix_modules as m ON m.id = cm.module<br />
WHERE m.name LIKE 'quiz'<br />
GROUP BY c.id<br />
</code><br />
<br />
===List all MultiAnswer (Cloze) Questions===<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/mod/quiz/attempt.php?q=', quiz.id, '">', quiz.name, '</a>') AS Quiz<br />
,question.id question_id, question.questiontext <br />
FROM prefix_question question<br />
JOIN prefix_quiz_question_instances qqi ON question.id = qqi.question<br />
JOIN prefix_quiz quiz ON qqi.quiz = quiz.id<br />
WHERE `qtype` LIKE 'multianswer'<br />
</code><br />
<br />
===List courses with MANUAL grades===<br />
Which is basically and indication to teachers using Moodle to hold offline grades inside Moodle's Gradebook,<br />
So grades could be uploaded into an administrative SIS. Use with Configurable Reports.<br />
<code sql><br />
SELECT COUNT( * )<br />
,concat('<a target="_new" href="%%WWWROOT%%/grade/edit/tree/index.php?showadvanced=1&id=',c.id,'">',c.fullname,'</a>') AS Course<br />
FROM prefix_grade_items AS gi<br />
JOIN prefix_course as c ON c.id = gi.courseid<br />
WHERE `itemtype` = 'manual'<br />
GROUP BY courseid<br />
</code><br />
===List the users that did not took the Quiz===<br />
Do not forget to change "c.id = 14" and q.name LIKE '%quiz name goes here%'<br />
<code sql><br />
SELECT<br />
user2.id AS ID,<br />
ul.timeaccess,<br />
user2.firstname AS Firstname,<br />
user2.lastname AS Lastname,<br />
user2.email AS Email,<br />
user2.username AS IDNumber,<br />
user2.institution AS Institution,<br />
<br />
IF (user2.lastaccess = 0,'never',<br />
DATE_FORMAT(FROM_UNIXTIME(user2.lastaccess),'%Y-%m-%d')) AS dLastAccess<br />
<br />
,(SELECT DATE_FORMAT(FROM_UNIXTIME(timeaccess),'%Y-%m-%d') FROM prefix_user_lastaccess WHERE userid=user2.id AND courseid=c.id) AS CourseLastAccess<br />
<br />
,(SELECT r.name<br />
FROM prefix_user_enrolments AS uenrol<br />
JOIN prefix_enrol AS e ON e.id = uenrol.enrolid<br />
JOIN prefix_role AS r ON e.id = r.id<br />
WHERE uenrol.userid=user2.id AND e.courseid = c.id) AS RoleName<br />
<br />
FROM prefix_user_enrolments AS ue<br />
JOIN prefix_enrol AS e ON e.id = ue.enrolid<br />
JOIN prefix_course AS c ON c.id = e.courseid<br />
JOIN prefix_user AS user2 ON user2 .id = ue.userid<br />
LEFT JOIN prefix_user_lastaccess AS ul ON ul.userid = user2.id<br />
WHERE c.id=14 and ue.userid NOT IN (SELECT qa.userid FROM prefix_quiz_attempts AS qa<br />
JOIN prefix_quiz AS q ON qa.quiz = q.id<br />
JOIN prefix_course AS c ON q.course = c.id<br />
WHERE c.id = 14 AND q.name LIKE '%quiz name goes here%')<br />
</code><br />
<br />
<br />
===List Questions in each Quiz===<br />
<br />
<code sql><br />
SELECT quiz.id,quiz.name, q.id, q.name<br />
FROM mdl_quiz AS quiz<br />
JOIN mdl_question AS q ON FIND_IN_SET(q.id, quiz.questions)<br />
WHERE quiz.course = %%COURSEID%%<br />
ORDER BY quiz.id ASC<br />
</code><br />
<br />
Note: this query does not work in Moodle 2.8. There is no mdl_quiz.questions field. It will need to be rewritten to use the usage/contextid organization.<br />
<br />
===Quiz activity research===<br />
This report was made to extract student full activity in quizzes for an academic research about adapting instructional design teaching methods in online learning. The students do not use the Quiz module as a standard quiz but more as Study booklets or mini courses with embedded questions and hints to assist students evaluate their progress (Similar to what you expect to find in a SCORM activity)<br />
<br />
<code sql><br />
SELECT <br />
cm.course "course_id", cm.id "moduel_id", q.id "quiz_id", q.name "quiz_name",<br />
<br />
CASE q.grademethod<br />
WHEN 1 THEN "GRADEHIGHEST"<br />
WHEN 2 THEN "GRADEAVERAGE"<br />
WHEN 3 THEN "ATTEMPTFIRST"<br />
WHEN 4 THEN "ATTEMPTLAST"<br />
END "grade method"<br />
<br />
, q.attempts "quiz_attempts_allowed", cm.groupmode "group_mode"<br />
, qa.id "attempt_id", qa.state "attempt_state", qa.sumgrades "attempt_grade", qg.grade "user_final_grade", q.grade "quiz_max_grade"<br />
,(SELECT GROUP_CONCAT(g.name) FROM mdl_groups AS g<br />
JOIN mdl_groups_members AS m ON g.id = m.groupid WHERE g.courseid = q.course AND m.userid = u.id) "user_groups",<br />
DATE_FORMAT(FROM_UNIXTIME(qa.timestart), '%d-%m-%Y %h:%k') "attempt_start",<br />
DATE_FORMAT(FROM_UNIXTIME(qa.timefinish), '%d-%m-%Y %h:%k') "attempt_finish",<br />
u.id "user_id", u.firstname, u.lastname,<br />
question.id "question_id", question.name "question_name",<br />
qas.state "question_step_state",qas.fraction "question_grade", qh.hint, question.qtype "question_type"<br />
<br />
FROM mdl_quiz as q<br />
JOIN mdl_course_modules as cm ON cm.instance = q.id and cm.module = 14 <br />
JOIN mdl_quiz_attempts qa ON q.id = qa.quiz<br />
LEFT JOIN mdl_quiz_grades as qg ON qg.quiz = q.id and qg.userid = qa.userid<br />
JOIN mdl_user as u ON u.id = qa.userid<br />
JOIN mdl_question_usages as qu ON qu.id = qa.uniqueid<br />
JOIN mdl_question_attempts as qatt ON qatt.questionusageid = qu.id<br />
JOIN mdl_question as question ON question.id = qatt.questionid<br />
JOIN mdl_question_attempt_steps as qas ON qas.questionattemptid = qatt.id<br />
LEFT JOIN mdl_question_hints as qh ON qh.questionid = q.id<br />
#WHERE q.id = "SOME QUIZ ID"<br />
WHERE cm.course = "SOME COURSE ID"<br />
</code><br />
<br />
===Quiz Usage in Courses by Date===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
This report lists the courses containing quizzes with the course start date between the two values, and provides a summary of the types of questions in the quizzes in each course and whether question randomization and answer randomization functions were used.<br />
<br />
"Multiple Choice" questions include true/false and matching question types.<br />
<br />
"Short Answer" are questions that accept a single phrase.<br />
<br />
"Other" questions include fixed numerical, calculated, essay, and various drag and drop types.<br />
<br />
"Min Quiz Age" and "Max Quiz Age" provide data about the last modified date for the quizzes in the course, compared to the course start date. The values are expressed in units of days. A negative value indicates that a quiz was edited after the start of the course. A value greater than 90 days indicates that the quiz may have been used in an earlier term (cohort) without modification.<br />
<br />
'''Note''': In Configurable Reports, the Date Filter is not applied until the "Apply" button is clicked.<br />
<br />
<code sql><br />
SELECT <br />
<br />
c.shortname AS 'Course'<br />
#, u.lastname AS 'Instructor'<br />
, COUNT(DISTINCT q.id) AS 'Quizzes'<br />
, COUNT(DISTINCT qu.id) AS 'Questions'<br />
, SUM(IF (qu.qtype = 'multichoice', 1, 0 )) + SUM(IF (qu.qtype = 'truefalse', 1, 0 )) + SUM(IF (qu.qtype = 'match', 1, 0 )) AS 'multichoice'<br />
<br />
, SUM(IF (qu.qtype = 'shortanswer', 1, 0 )) AS 'shortanswer'<br />
<br />
, COUNT( qu.id) - SUM(IF (qu.qtype = 'multichoice', 1, 0 )) - SUM(IF (qu.qtype = 'truefalse', 1, 0 )) - SUM(IF (qu.qtype = 'match', 1, 0 )) - SUM(IF (qu.qtype = 'shortanswer', 1, 0 )) AS 'Other'<br />
<br />
, (SUM(IF (qu.qtype = 'multichoice', 1, 0 )) + SUM(IF (qu.qtype = 'truefalse', 1, 0 )) + SUM(IF (qu.qtype = 'match', 1, 0 )))/COUNT( qu.id) AS 'Percent MC'<br />
<br />
#, SUM(IF (qu.qtype = 'numerical', 1, 0 )) AS 'numerical'<br />
#, SUM(IF (qu.qtype LIKE 'calc%', 1, 0 )) AS 'calculated'<br />
#, SUM(IF (qu.qtype = 'random', 1, 0 )) AS 'random'<br />
#, SUM(IF (qu.qtype = 'shortanswer', 1, 0 )) AS 'shortanswer'<br />
#, SUM(IF (qu.qtype = 'essay', 1, 0 )) AS 'essay'<br />
<br />
<br />
, IF(q.shufflequestions > 0,'Yes','No') AS 'Randomized Questions'<br />
, IF(q.shuffleanswers > 0,'Yes','No') AS 'Randomized Answers'<br />
<br />
#, FROM_UNIXTIME(c.startdate) AS 'Course Start Date'<br />
#, FROM_UNIXTIME(MIN(q.timemodified)) AS 'Last Modified'<br />
<br />
#, DATEDIFF(FROM_UNIXTIME(c.startdate),FROM_UNIXTIME(MIN(q.timemodified))) AS 'Quiz age'<br />
<br />
, MIN(DATEDIFF(FROM_UNIXTIME(c.startdate),FROM_UNIXTIME(q.timemodified))) AS 'Min Quiz Age' <br />
, MAX(DATEDIFF(FROM_UNIXTIME(c.startdate),FROM_UNIXTIME(q.timemodified))) AS 'Max Quiz Age' <br />
<br />
#, SUM(IF (DATEDIFF(FROM_UNIXTIME(c.startdate),FROM_UNIXTIME(q.timemodified)) < 90, 1,0)) AS 'new quizzes'<br />
<br />
FROM prefix_quiz AS q<br />
JOIN prefix_course AS c on c.id = q.course<br />
JOIN prefix_quiz_question_instances AS qqi ON qqi.quiz = q.id<br />
LEFT JOIN prefix_question AS qu ON qu.id = qqi.question<br />
<br />
WHERE<br />
1<br />
%%FILTER_STARTTIME:c.startdate:>%% %%FILTER_ENDTIME:c.startdate:<%%<br />
<br />
GROUP BY c.id<br />
<br />
ORDER BY c.shortname<br />
</code><br />
<br />
===Student responses (answers) to quiz questions===<br />
(Contributed by Juan F with help from Tim hunt and fellow Moodlers on the forums)<br />
A report that targets a specific quiz for all of our Biology courses, a summary of all questions and how many students get them right/wrong.<br />
<code sql><br />
SELECT<br />
concat( u.firstname, " ", u.lastname ) AS "Student Name",<br />
u.id,<br />
quiza.userid,<br />
q.course,<br />
q.name,<br />
quiza.attempt,<br />
qa.slot,<br />
que.questiontext AS 'Question',<br />
qa.rightanswer AS 'Correct Answer',<br />
qa.responsesummary AS 'Student Answer'<br />
<br />
FROM mdl_quiz_attempts quiza<br />
JOIN mdl_quiz q ON q.id=quiza.quiz<br />
JOIN mdl_question_usages qu ON qu.id = quiza.uniqueid<br />
JOIN mdl_question_attempts qa ON qa.questionusageid = qu.id<br />
JOIN mdl_question que ON que.id = qa.questionid<br />
JOIN mdl_user u ON u.id = quiza.userid<br />
<br />
WHERE q.name = "BIO 208 Post Test Assessment"<br />
AND q.course = "17926"<br />
<br />
ORDER BY quiza.userid, quiza.attempt, qa.slot<br />
</code><br />
<br />
==SCORM Activity Reports==<br />
<br />
===Lists All completed SCORM activites by Course name===<br />
This report will list all completed attempts for all SCORM activities. It is ordered first by Course name, then student's last name, then student's first name, then attempt number. Please note: the FROM_UNIXTIME command is for MySQL.<br />
<code sql><br />
SELECT u.firstname First,u.lastname Last,c.fullname Course, st.attempt Attempt,st.value Status,FROM_UNIXTIME(st.timemodified,"%m-%d-%Y") Date <br />
FROM prefix_scorm_scoes_track AS st <br />
JOIN prefix_user AS u ON st.userid=u.id<br />
JOIN prefix_scorm AS sc ON sc.id=st.scormid<br />
JOIN prefix_course AS c ON c.id=sc.course<br />
WHERE st.value='completed' <br />
ORDER BY c.fullname, u.lastname,u.firstname, st.attempt<br />
</code><br />
<br />
===Lists SCORM status for all enrolled users by Course name===<br />
This report will list the SCORM status for all users enrolled in the course. It is ordered first by Course name, then student's last name, then student's first name, then attempt number. This can be limited to individual courses by adding to the where clause the course id to report on. <br />
<code sql><br />
SELECT<br />
u.firstname AS First,<br />
u.lastname AS Last, <br />
u.idnumber AS Employee_ID, <br />
u.city AS City,<br />
uid.data AS State,<br />
u.country AS Country,<br />
g.name AS Group_name,<br />
c.fullname AS Course, <br />
st.attempt AS Attempt,<br />
st.value AS Status,<br />
FROM_UNIXTIME(st.timemodified,"%m-%d-%Y") AS Date <br />
<br />
FROM prefix_scorm_scoes_track AS st <br />
JOIN prefix_user AS u ON st.userid=u.id<br />
JOIN prefix_user_info_data AS uid ON uid.userid = u.id <br />
JOIN prefix_scorm AS sc ON sc.id=st.scormid<br />
JOIN prefix_course AS c ON c.id=sc.course<br />
JOIN prefix_groups AS g ON g.courseid = c.id<br />
JOIN prefix_groups_members AS m ON g.id = m.groupid<br />
<br />
WHERE st.element='cmi.core.lesson_status' AND m.userid=u.id<br />
<br />
UNION<br />
<br />
SELECT<br />
user2.firstname AS First,<br />
user2.lastname AS Last,<br />
user2. idnumber AS Employee_ID,<br />
user2.city AS City,<br />
uid.data AS State,<br />
user2.country AS Country,<br />
g.name AS Group_name,<br />
c.fullname AS Course,<br />
"-" AS Attempt,<br />
"not_started" AS Status,<br />
"-" AS Date<br />
<br />
FROM prefix_user_enrolments AS ue<br />
JOIN prefix_enrol AS e ON e.id = ue.enrolid<br />
JOIN prefix_course AS c ON c.id = e.courseid<br />
JOIN prefix_user AS user2 ON user2 .id = ue.userid<br />
JOIN prefix_user_info_data AS uid ON uid.userid = user2.id <br />
JOIN prefix_groups AS g ON g.courseid = c.id<br />
JOIN prefix_groups_members AS m ON g.id = m.groupid<br />
JOIN prefix_scorm AS sc ON sc.course=c.id<br />
Left Join prefix_scorm_scoes_track AS st on st.scormid=sc.id AND st.userid=user2.id<br />
<br />
WHERE st.timemodified IS NULL AND m.userid=user2.id<br />
<br />
ORDER BY Course, Last, First, Attempt<br />
<br />
</code><br />
<br />
== Badges==<br />
<br />
=== All badges issued, by User ===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
This report will show you all the badges on a site that have been issued, both site and all courses, by the username of each user issued a badge. Includes the type of criteria passed (activity, course completion, manual), date issued, date expires, and a direct link to that issued badge page so you can see all the other details for that badge.<br />
<br />
<code sql><br />
SELECT u.username, b.name AS badgename, <br />
CASE<br />
WHEN b.courseid IS NOT NULL THEN<br />
(SELECT c.shortname<br />
FROM prefix_course AS c<br />
WHERE c.id = b.courseid)<br />
WHEN b.courseid IS NULL THEN "*"<br />
END AS Context,<br />
CASE <br />
WHEN t.criteriatype = 1 AND t.method = 1 THEN "Activity Completion (All)"<br />
WHEN t.criteriatype = 1 AND t.method = 2 THEN "Activity Completion (Any)"<br />
WHEN t.criteriatype = 2 AND t.method = 2 THEN "Manual Award"<br />
WHEN t.criteriatype = 4 AND t.method = 1 THEN "Course Completion (All)"<br />
WHEN t.criteriatype = 4 AND t.method = 2 THEN "Course Completion (Any)"<br />
ELSE CONCAT ('Other: ', t.criteriatype)<br />
END AS Criteriatype,<br />
DATE_FORMAT( FROM_UNIXTIME( d.dateissued ) , '%Y-%m-%d' ) AS dateissued,<br />
DATE_FORMAT( FROM_UNIXTIME( d.dateexpire ), '%Y-%m-%d' ) AS dateexpires,<br />
CONCAT ('<a target="_new" href="%%WWWROOT%%/badges/badge.php?hash=',d.uniquehash,'">link</a>') AS Details<br />
FROM prefix_badge_issued AS d <br />
JOIN prefix_badge AS b ON d.badgeid = b.id<br />
JOIN prefix_user AS u ON d.userid = u.id<br />
JOIN prefix_badge_criteria AS t on b.id = t.badgeid <br />
WHERE t.criteriatype <> 0<br />
ORDER BY u.username<br />
</code><br />
<br />
Please note: the FROM_UNIXTIME command is for MySQL.<br />
<br />
=== All badges available in the system, with Earned count ===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
Report of all badges in the system, with badge name and description, context, course shortname if a course badge, whether it is active and available, and a count of how many users have been issued that badge.<br />
<br />
<code sql><br />
SELECT b.id, b.name, b.description,<br />
CASE<br />
WHEN b.type = 1 THEN "System"<br />
WHEN b.type = 2 THEN "Course"<br />
END AS Context, <br />
CASE<br />
WHEN b.courseid IS NOT NULL THEN <br />
(SELECT c.shortname <br />
FROM prefix_course AS c <br />
WHERE c.id = b.courseid)<br />
WHEN b.courseid IS NULL THEN "*"<br />
END AS Course, <br />
CASE<br />
WHEN b.status = 0 OR b.status = 2 THEN "No"<br />
WHEN b.status = 1 OR b.status = 3 THEN "Yes"<br />
WHEN b.status = 4 THEN "x"<br />
END AS Available,<br />
CASE<br />
WHEN b.status = 0 OR b.status = 1 THEN "0"<br />
WHEN b.status = 2 OR b.status = 3 OR b.status = 4 THEN <br />
(SELECT COUNT(*) <br />
FROM prefix_badge_issued AS d<br />
WHERE d.badgeid = b.id<br />
)<br />
END AS Earned<br />
FROM prefix_badge AS b<br />
<br />
</code><br />
<br />
=== Badges Leaderboard ===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
A simple list of usernames and how many badges they have earned overall.<br />
<br />
<code sql><br />
SELECT u.username, (SELECT COUNT(*) FROM prefix_badge_issued AS d WHERE d.userid = u.id) AS earned<br />
FROM prefix_user AS u<br />
ORDER BY earned DESC, u.username ASC<br />
</code><br />
<br />
=== Manage badges (System & Course) ===<br />
<br />
List system wide badges, course and system level badges + a link to relevant "manage badges" page.<br />
<br />
<code sql><br />
SELECT b.id, b.name, b.description <br />
,CASE <br />
WHEN b.type = 1 THEN 'System'<br />
WHEN b.type = 2 THEN 'Course'<br />
END AS Level<br />
,CONCAT('<a target="_new" href="%%WWWROOT%%/badges/index.php?type=', b.type, '&id=',<br />
c.id, '">Manage badges in: ', c.fullname, '</a>') AS Manage <br />
FROM prefix_badge AS b<br />
JOIN prefix_course AS c ON c.id = b.courseid<br />
</code><br />
<br />
==Administrator Reports==<br />
<br />
===Config changes in Export friendly form===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
The Administrative report Config changes is very useful but it would be nice to have it in a format that could be easily exported in one listing. Here is code to do that.<br />
<br />
<code sql><br />
SELECT <br />
DATE_FORMAT( FROM_UNIXTIME( g.timemodified ) , '%Y-%m-%d' ) AS date, <br />
u.username AS user, <br />
g.name AS setting, <br />
CASE <br />
WHEN g.plugin IS NULL THEN "core"<br />
ELSE g.plugin<br />
END AS plugin, <br />
g.value AS new_value, <br />
g.oldvalue AS original_value<br />
FROM prefix_config_log AS g<br />
JOIN prefix_user AS u ON g.userid = u.id<br />
ORDER BY date DESC<br />
</code><br />
<br />
===Cohorts by user===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
How to get a list of all users and which cohorts they belong to.<br />
<br />
<code sql><br />
SELECT u.firstname, u.lastname, h.idnumber, h.name<br />
FROM prefix_cohort AS h<br />
JOIN prefix_cohort_members AS hm ON h.id = hm.cohortid<br />
JOIN prefix_user AS u ON hm.userid = u.id<br />
ORDER BY u.firstname<br />
</code><br />
<br />
===Cohorts with Courses===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
List of all cohorts with name, id, visibility, and which courses they are enrolled in.<br />
<br />
<code sql><br />
SELECT<br />
# h.id,<br />
# e.customint1,<br />
h.name AS Cohort,<br />
h.idnumber AS Cohortid,<br />
CASE <br />
WHEN h.visible = 1 THEN 'Yes'<br />
ELSE '-'<br />
END AS Cohortvisible,<br />
CONCAT('<a target="_new" href="%%WWWROOT%%/course/view.php', CHAR(63),'id=',c.id,'">',c.fullname,'</a>') AS Course<br />
FROM prefix_cohort h<br />
JOIN prefix_enrol e ON h.id = e.customint1<br />
JOIN prefix_course c ON c.id = e.courseid %%FILTER_COURSES:e.courseid%% <br />
WHERE e.enrol = 'cohort' AND e.roleid = 5<br />
</code><br />
<br />
===Courses created And Active courses by Year===<br />
Active courses is counting course that have at least one Hit, And "Active_MoreThan100Hits" counts courses that have at least 100 Hits<br />
<code sql><br />
SELECT <br />
<br />
YEAR( FROM_UNIXTIME( `timecreated` ) ) AS YEAR, COUNT( * ) AS Counter<br />
<br />
, (SELECT COUNT( DISTINCT course ) <br />
FROM prefix_log AS l<br />
WHERE YEAR( FROM_UNIXTIME( l.`time` ) ) = YEAR( FROM_UNIXTIME( `timecreated` ) )<br />
) AS "Active"<br />
<br />
,(SELECT COUNT(*) FROM ( <br />
SELECT COUNT( * ),time <br />
FROM prefix_log AS l <br />
GROUP BY course <br />
HAVING COUNT(*) > 100) AS courses_log<br />
WHERE YEAR( FROM_UNIXTIME( courses_log.`time` ) ) = YEAR( FROM_UNIXTIME( `timecreated` ) )<br />
) AS "Active_MoreThan100Hits"<br />
<br />
FROM `prefix_course` <br />
GROUP BY YEAR( FROM_UNIXTIME( `timecreated` ) ) <br />
</code><br />
<br />
===Users created And Active users by Year===<br />
Active users is counting users that have at least one Hit, And "Active_MoreThan500Hits" counts users that have at least 500 Hits<br />
<code sql><br />
SELECT <br />
<br />
YEAR( FROM_UNIXTIME( `firstaccess` ) ) AS YEAR, COUNT( * ) AS Counter<br />
<br />
, (SELECT COUNT( DISTINCT userid ) <br />
FROM prefix_log AS l<br />
WHERE YEAR( FROM_UNIXTIME( l.`time` ) ) = YEAR( FROM_UNIXTIME( `firstaccess` ) )<br />
) AS "Active"<br />
<br />
,(SELECT COUNT(*) FROM ( <br />
SELECT COUNT( * ),time <br />
FROM prefix_log AS l <br />
GROUP BY userid <br />
HAVING COUNT(*) > 500) AS users_log<br />
WHERE YEAR( FROM_UNIXTIME( users_log.`time` ) ) = YEAR( FROM_UNIXTIME( `firstaccess` ) )<br />
) AS "Active_MoreThan500Hits"<br />
<br />
FROM `prefix_user` <br />
GROUP BY YEAR( FROM_UNIXTIME( `timecreated` ) ) <br />
</code><br />
<br />
===Course Aggregation Report===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
If you are considering upgrading from Moodle 2.6 to 2.8 or later, your grades may be changed. This report can help quantify and identify the courses at risk of changes.<br />
<br />
In particular, be on the lookout for any courses with the following combinations of parameters, which are known to cause changes in calculations:<br />
<br />
# mean of grades set with aggregate with subcategory.<br />
# Simple weighted mean of grades with aggregate with sub category and drop the lowest<br />
# Sum of grades drop the lowest<br />
<br />
Also review:<br />
https://tracker.moodle.org/browse/MDL-48618<br />
https://tracker.moodle.org/browse/MDL-48634<br />
https://tracker.moodle.org/browse/MDL-49257<br />
https://tracker.moodle.org/browse/MDL-50089<br />
https://tracker.moodle.org/browse/MDL-50062<br />
<br />
<code sql><br />
SELECT<br />
<br />
COUNT(c.shortname) AS 'Count of Courses'<br />
<br />
# If you want to display all the courses for each aggregation type, uncomment the next line and change GROUP BY settings<br />
#, c.shortname AS 'course name'<br />
<br />
# If you need to display grade categories for each aggregation type, uncomment the next line and change GROUP BY settings<br />
#, gc.fullname AS 'grade category name'<br />
<br />
, gc.aggregation AS 'aggregation method'<br />
<br />
#These aggregation text strings appear to be hard-coded. I couldn't find a table for them. If you have aggregation types I haven't included here, they'll be blank in your report results.<br />
, CASE gc.aggregation<br />
WHEN 0 THEN 'Mean of Grades'<br />
WHEN 2 THEN 'Median of Grades'<br />
WHEN 6 THEN 'Highest Grade'<br />
WHEN 8 THEN 'Mode of Grades'<br />
WHEN 10 THEN 'Weighted Mean of Grades'<br />
WHEN 11 THEN 'Simple Weighted Mean of Grades'<br />
WHEN 12 THEN 'Mean of Grades (with extra credits)'<br />
WHEN 13 THEN 'Sum of Grades'<br />
END AS 'aggregation name'<br />
<br />
# Note that gc.aggregatesubcats column is eliminated in 2.8 and later per MDL-47503, so comment that line on updated systems or you'll get an error<br />
, gc.keephigh AS 'keep high'<br />
, gc.droplow AS 'dr0p low'<br />
, gc.aggregateonlygraded AS 'Aggregate only graded'<br />
, gc.aggregateoutcomes AS 'aggregate outcomes'<br />
, gc.aggregatesubcats AS 'aggregate subcategories'<br />
<br />
# If you are displaying data about individual courses, you may want to know how old they are<br />
#, FROM_UNIXTIME(c.startdate) AS 'course start date'<br />
<br />
# If you are trying to use this report to check to see if final grades have changed after an upgrade, you might want these data items, but calculations can still change later when the courses are actually viewed. Also, you'll need to uncomment the necessary JOINs below<br />
#, gi.itemname AS 'grade item'<br />
#, gg.finalgrade AS 'final grade'<br />
<br />
FROM<br />
<br />
prefix_course AS c<br />
JOIN prefix_grade_categories AS gc ON gc.courseid = c.id<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
<br />
#LEFT JOIN prefix_grade_items AS gi ON gi.courseid = c.id #AND gi.categoryid=gc.id<br />
#LEFT JOIN prefix_grade_grades AS gg ON gg.itemid = gi.id AND gg.userid = u.id<br />
<br />
WHERE<br />
1<br />
#AND gc.aggregation = 13 #only the dreaded Sum of Grades aggregations<br />
#AND gc.depth = 1 # if for some reason you only want course aggregations, not subcategories<br />
<br />
<br />
GROUP BY gc.aggregation, gc.keephigh, gc.droplow, gc.aggregateonlygraded, gc.aggregateoutcomes, gc.aggregatesubcats<br />
<br />
</code><br />
<br />
=== Running Cron jobs (task_scheduled) ===<br />
<code sql><br />
SELECT classname<br />
,DATE_FORMAT(FROM_UNIXTIME(lastruntime), '%H:%i [%d]') AS 'last'<br />
,DATE_FORMAT(now(), '%H:%i') AS 'now'<br />
,DATE_FORMAT(FROM_UNIXTIME(nextruntime), '%H:%i [%d]') AS 'next'<br />
,DATE_FORMAT(FROM_UNIXTIME(UNIX_TIMESTAMP()-nextruntime), '%i') AS 'next in min'<br />
FROM mdl_task_scheduled<br />
WHERE now() > FROM_UNIXTIME(nextruntime)<br />
</code><br />
<br />
=== All Meta courses with Parent and Child course relationships ===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
This shows the list of courses with Meta course link enrollments in them ('Parent course'), and the courses which are connected to them to provide enrollments ('Child courses').<br />
<br />
<code sql><br />
SELECT <br />
c.fullname AS 'Parent course name',<br />
c.shortname AS 'Parent course shortname',<br />
en.courseid AS 'Parent course id',<br />
(SELECT fullname FROM prefix_course WHERE prefix_course.id = en.customint1) As 'Child course name',<br />
(SELECT shortname FROM prefix_course WHERE prefix_course.id = en.customint1) As 'Child course shortname',<br />
en.customint1 AS 'Child course id'<br />
FROM prefix_enrol en<br />
JOIN prefix_course c ON c.id = en.courseid<br />
WHERE en.enrol = 'meta'<br />
ORDER BY c.fullname<br />
</code><br />
<br />
== Useful sub queries ==<br />
<br />
IN this section please put any short one purpose sub queries that show how common procedures often useful as part of larger queries.<br />
<br />
=== All teachers in the course ===<br />
<br />
<br />
This snippet shows how to get teachers from a course. The contextevel for course objects is 50. And the default Teacher role is role id 3.<br />
<br />
<code sql><br />
,(SELECT GROUP_CONCAT( CONCAT( u.firstname, " ", u.lastname ) ) <br />
FROM prefix_course ic<br />
JOIN prefix_context con ON con.instanceid = ic.id<br />
JOIN prefix_role_assignments ra ON con.id = ra.contextid AND con.contextlevel = 50<br />
JOIN prefix_role r ON ra.roleid = r.id<br />
JOIN prefix_user u ON u.id = ra.userid<br />
WHERE r.id = 3 AND ic.id = c.id<br />
GROUP BY ic.id<br />
) AS TeacherNames<br />
</code><br />
<br />
=== Get custom User profile fields for a user ===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
This snippet of code shows how to connect a user with their custom profile field data. This will list all users with all custom profile fields and data. Custom profile fields have two tables, one for the definition of the profile field (user_info_field) and its settings, and a separate table to hold the data entered by users (user_info_data). <br />
<br />
<code sql><br />
SELECT u.username, uif.name, uid.data<br />
FROM prefix_user AS u<br />
JOIN prefix_user_info_data AS uid ON uid.userid = u.id<br />
JOIN prefix_user_info_field AS uif ON uid.fieldid = uif.id <br />
</code><br />
<br />
If you want to limit it to one of those fields, you can restrict it by shortname of the custom profile field, so:<br />
<br />
<code sql><br />
SELECT u.username, uif.name, uid.data<br />
FROM prefix_user AS u<br />
JOIN prefix_user_info_data AS uid ON uid.userid = u.id<br />
JOIN prefix_user_info_field AS uif ON (uid.fieldid = uif.id AND uif.shortname = 'shortname1')<br />
</code><br />
<br />
will show you only the data from the custom profile field with the shortname 'shortname1'.<br />
<br />
If you want to do this with two or more custom profile fields, you will need to have a JOIN and table alias for each with a restriction for each profile field shortname. Example:<br />
<br />
<code sql><br />
SELECT u.username, d1.data AS 'Profile One', d2.data As 'Profile Two'<br />
FROM prefix_user u<br />
JOIN prefix_user_info_data d1 ON d1.userid = u.id<br />
JOIN prefix_user_info_field f1 ON d1.fieldid = f1.id AND f1.shortname = 'shortname1'<br />
JOIN prefix_user_info_data d2 ON d2.userid = u.id<br />
JOIN prefix_user_info_field f2 ON d2.fieldid = f2.id AND f2.shortname = 'shortname2'<br />
</code><br />
<br />
==== NOTE: Alternate Method ====<br />
<br />
If you have more than a couple of fields you need to use, then this query may time out or not return data due to too many joins. The limit seems to be around 10 custom profile fields. <br />
<br />
Instead you should use an alternate method which uses Subselects for each of the profile fields. Details and sample code are in this forum discussion: https://moodle.org/mod/forum/discuss.php?d=355502#p1434854. A sample of the style is:<br />
<br />
<code sql><br />
SELECT u.username<br />
<br />
,(SELECT d1.data FROM prefix_user_info_data d1<br />
JOIN prefix_user_info_field f1 ON d1.fieldid = f1.id AND f1.shortname = 'shortname1'<br />
WHERE d1.userid = u.id<br />
) AS thefirstfield<br />
<br />
,(SELECT d1.data FROM prefix_user_info_data d1<br />
JOIN prefix_user_info_field f1 ON d1.fieldid = f1.id AND f1.shortname = 'shortname2'<br />
WHERE d1.userid = u.id<br />
) AS thesecondfield<br />
<br />
FROM prefix_user u<br />
</code><br />
<br />
=== How to use Configurable Reports Date Time Filters===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
In the Configurable Reports block, you can set the Time and Date filter to allow you to pick your report Start date/time and End date/time interactively. This will work on any column in a table that is a timestamp.<br />
<br />
Here is a simple example:<br />
<br />
<code sql><br />
SELECT u.username, <br />
DATE_FORMAT(FROM_UNIXTIME(u.firstaccess),'%Y-%m-%d %H:%i') AS 'FirstAccess',<br />
DATE_FORMAT(FROM_UNIXTIME(u.lastaccess),'%Y-%m-%d %H:%i') AS 'LastAccess' <br />
FROM prefix_user u<br />
<br />
WHERE 1=1<br />
%%FILTER_STARTTIME:u.firstaccess:>%% <br />
%%FILTER_ENDTIME:u.lastaccess:<%% <br />
</code><br />
<br />
1) You will need to replace name of the table and column for the filter to use the time and date column you need for your query. In the example above, it filters on the firstaccess and lastaccess columns in the user table. If you were doing a report on course completion, you might put the timecompleted column, and so forth.<br />
<br />
2) You MUST then add the Start / End date filter on the Filters tab of the Report. If you don't, the report will still run, probably, but the filter will be ignored.<br />
<br />
Note: the WHERE 1=1 statement is a peculiarity of the filters in Config reports: if you don't have a WHERE statement in your query already, then you must add this dummy WHERE to keep the statement valid. If you already have a WHERE statement in your code, simply add the %%FILTER%% placeholders after it (and before any GROUP or ORDER BY statements.)<br />
<br />
==See also==<br />
* [https://github.com/jleyva/moodle-configurable_reports_repository Configurable Reports Repository on GitHub]<br />
* [https://moodleschema.zoola.io/index.html Moodle DB schema explorer] - searching and filtering tables, fields and external key connections between tables.<br />
<br />
[[Category:Contributed code]]<br />
<br />
[[es:Reportes específicos hechos por usuarios]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=ad-hoc_contributed_reports&diff=133237ad-hoc contributed reports2019-03-07T09:14:53Z<p>Fox: /* User detailed activity in course modules */ Use prefix_ (and not mdl_)</p>
<hr />
<div>{{Sitewide reports}}<br />
==User and Role Report==<br />
<br />
===Count number of distinct learners and teachers enrolled per category (including all its sub categories)===<br />
<code sql>SELECT COUNT(DISTINCT lra.userid) AS learners, COUNT(DISTINCT tra.userid) as teachers<br />
FROM prefix_course AS c #, mdl_course_categories AS cats<br />
LEFT JOIN prefix_context AS ctx ON c.id = ctx.instanceid<br />
JOIN prefix_role_assignments AS lra ON lra.contextid = ctx.id<br />
JOIN prefix_role_assignments AS tra ON tra.contextid = ctx.id<br />
JOIN prefix_course_categories AS cats ON c.category = cats.id<br />
WHERE c.category = cats.id<br />
AND (<br />
cats.path LIKE '%/CATEGORYID/%' #Replace CATEGORYID with the category id you want to count (eg: 80)<br />
OR cats.path LIKE '%/CATEGORYID'<br />
)<br />
AND lra.roleid=5<br />
AND tra.roleid=3</code><br />
<br />
===Detailed ACTIONs for each ROLE (TEACHER, NON-EDITING TEACHER and STUDENT)===<br />
<code sql><br />
SELECT r.name, l.action, COUNT( l.userid ) AS counter<br />
FROM prefix_log AS l<br />
JOIN prefix_context AS context ON context.instanceid = l.course AND context.contextlevel = 50<br />
JOIN prefix_role_assignments AS ra ON l.userid = ra.userid AND ra.contextid = context.id<br />
JOIN prefix_role AS r ON ra.roleid = r.id<br />
WHERE ra.roleid IN ( 3, 4, 5 ) <br />
GROUP BY roleid, l.action<br />
</code><br />
<br />
===Student (user) COUNT in each Course===<br />
Including (optional) filter by: year (if included in course fullname).<br />
<code sql><br />
SELECT CONCAT('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',course.id,'">',course.fullname,'</a>') AS Course<br />
,CONCAT('<a target="_new" href="%%WWWROOT%%/user/index.php?contextid=',context.id,'">Show users</a>') AS Users<br />
, COUNT(course.id) AS Students<br />
FROM prefix_role_assignments AS asg<br />
JOIN prefix_context AS context ON asg.contextid = context.id AND context.contextlevel = 50<br />
JOIN prefix_user AS user ON user.id = asg.userid<br />
JOIN prefix_course AS course ON context.instanceid = course.id<br />
WHERE asg.roleid = 5 <br />
# AND course.fullname LIKE '%2013%'<br />
GROUP BY course.id<br />
ORDER BY COUNT(course.id) DESC<br />
</code><br />
<br />
=== Enrolment count in each Course ===<br />
<br />
Shows the total number of enroled users of all roles in each course. Sorted by course name.<br />
<br />
<code sql><br />
SELECT c.fullname, COUNT(ue.id) AS Enroled<br />
FROM prefix_course AS c <br />
JOIN prefix_enrol AS en ON en.courseid = c.id<br />
JOIN prefix_user_enrolments AS ue ON ue.enrolid = en.id<br />
GROUP BY c.id<br />
ORDER BY c.fullname<br />
</code><br />
<br />
===LIST of all site USERS by COURSE enrollment (Moodle 2.x)===<br />
<br />
<code sql><br />
SELECT<br />
user2.firstname AS Firstname,<br />
user2.lastname AS Lastname,<br />
user2.email AS Email,<br />
user2.city AS City,<br />
course.fullname AS Course<br />
,(SELECT shortname FROM prefix_role WHERE id=en.roleid) as Role<br />
,(SELECT name FROM prefix_role WHERE id=en.roleid) as RoleName<br />
<br />
FROM prefix_course as course <br />
JOIN prefix_enrol AS en ON en.courseid = course.id<br />
JOIN prefix_user_enrolments AS ue ON ue.enrolid = en.id<br />
JOIN prefix_user AS user2 ON ue.userid = user2.id<br />
</code><br />
<br />
===Enrolled users,which did not login into the Course, even once (Moodle 2)===<br />
Designed forMoodle 2 table structure and uses special plugin filter : %%FILTER_SEARCHTEXT:table.field%%<br />
<br />
<code sql><br />
SELECT<br />
user2.id as ID,<br />
ul.timeaccess,<br />
user2.firstname AS Firstname,<br />
user2.lastname AS Lastname,<br />
user2.email AS Email,<br />
user2.city AS City,<br />
user2.idnumber AS IDNumber,<br />
user2.phone1 AS Phone,<br />
user2.institution AS Institution,<br />
<br />
IF (user2.lastaccess = 0,'never',<br />
DATE_FORMAT(FROM_UNIXTIME(user2.lastaccess),'%Y-%m-%d')) AS dLastAccess<br />
<br />
,(SELECT DATE_FORMAT(FROM_UNIXTIME(timeaccess),'%Y-%m-%d') FROM prefix_user_lastaccess WHERE userid=user2.id and courseid=c.id) as CourseLastAccess<br />
<br />
,(SELECT r.name<br />
FROM prefix_user_enrolments AS uenrol<br />
JOIN prefix_enrol AS e ON e.id = uenrol.enrolid<br />
JOIN prefix_role AS r ON e.id = r.id<br />
WHERE uenrol.userid=user2.id and e.courseid = c.id) AS RoleName<br />
<br />
FROM prefix_user_enrolments as ue<br />
JOIN prefix_enrol as e on e.id = ue.enrolid<br />
JOIN prefix_course as c ON c.id = e.courseid<br />
JOIN prefix_user as user2 ON user2 .id = ue.userid<br />
LEFT JOIN prefix_user_lastaccess as ul on ul.userid = user2.id<br />
WHERE c.id=16 AND ul.timeaccess IS NULL<br />
%%FILTER_SEARCHTEXT:user2.firstname%%<br />
</code><br />
<br />
===Role assignments on categories===<br />
<code sql><br />
SELECT <br />
concat('<a target="_new" href="%%WWWROOT%%/course/category.php?id=',cc.id,'">',cc.id,'</a>') AS id,<br />
concat('<a target="_new" href="%%WWWROOT%%/course/category.php?id=',cc.id,'">',cc.name,'</a>') AS category,<br />
cc.depth, cc.path, r.name AS role,<br />
concat('<a target="_new" href="%%WWWROOT%%/user/view.php?id=',usr.id,'">',usr.lastname,'</a>') AS name,<br />
usr.firstname, usr.username, usr.email<br />
FROM prefix_course_categories cc<br />
INNER JOIN prefix_context cx ON cc.id = cx.instanceid<br />
AND cx.contextlevel = '40'<br />
INNER JOIN prefix_role_assignments ra ON cx.id = ra.contextid<br />
INNER JOIN prefix_role r ON ra.roleid = r.id<br />
INNER JOIN prefix_user usr ON ra.userid = usr.id<br />
ORDER BY cc.depth, cc.path, usr.lastname, usr.firstname, r.name, cc.name<br />
</code><br />
<br />
===Permissions Overides on Categories===<br />
(By: [http://moodle.org/mod/forum/discuss.php?d=153059#p712834 Séverin Terrier] )<br />
<code sql><br />
SELECT rc.id, ct.instanceid, ccat.name, rc.roleid, rc.capability, rc.permission, <br />
DATE_FORMAT( FROM_UNIXTIME( rc.timemodified ) , '%Y-%m-%d' ) AS timemodified, rc.modifierid, ct.instanceid, ct.path, ct.depth<br />
FROM `prefix_role_capabilities` AS rc<br />
INNER JOIN `prefix_context` AS ct ON rc.contextid = ct.id<br />
INNER JOIN `prefix_course_categories` AS ccat ON ccat.id = ct.instanceid<br />
AND `contextlevel` =40<br />
</code><br />
<br />
===Lists "Totally Opened Courses" (visible, opened to guests, with no password)===<br />
(By: [http://moodle.org/mod/forum/discuss.php?d=153059#p712837 Séverin Terrier] )<br />
<code sql><br />
SELECT<br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.id,'</a>') AS id,<br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.shortname,'</a>') AS 'Course',<br />
concat('<a target="_new" href="%%WWWROOT%%/enrol/instances.php?id=',c.id,'">Méthodes inscription</a>') AS 'Enrollment plugins',<br />
e.sortorder<br />
FROM prefix_enrol AS e, prefix_course AS c<br />
WHERE e.enrol='guest' AND e.status=0 AND e.password='' AND c.id=e.courseid AND c.visible=1<br />
</code><br />
<br />
===Lists "loggedin users" from the last 120 days===<br />
<code sql><br />
SELECT id,username,FROM_UNIXTIME(`lastlogin`) as days <br />
FROM `prefix_user` <br />
WHERE DATEDIFF( NOW(),FROM_UNIXTIME(`lastlogin`) ) < 120<br />
</code><br />
<br />
''and user count for that same population:''<br />
<code sql><br />
SELECT COUNT(id) as Users FROM `prefix_user` <br />
WHERE DATEDIFF( NOW(),FROM_UNIXTIME(`lastlogin`) ) < 120<br />
</code><br />
<br />
==== Users loggedin within the last 7 days ====<br />
<code sql><br />
SELECT<br />
l.* FROM mdl_logstore_standard_log l<br />
WHERE<br />
l.eventname = '\\core\\event\\user_loggedin'<br />
AND FROM_UNIXTIME(l.timecreated, '%Y-%m-%d') >= DATE_SUB(NOW(), INTERVAL 7 DAY)<br />
<br />
SELECT l.eventname FROM mdl_logstore_standard_log l<br />
GROUP BY l.eventname<br />
</code><br />
<br />
===Lists the users who have only logged into the site once===<br />
<code sql><br />
SELECT id, username, firstname, lastname, idnumber<br />
FROM prefix_user<br />
WHERE prefix_user.deleted = 0<br />
AND prefix_user.lastlogin = 0 <br />
AND prefix_user.lastaccess > 0<br />
</code><br />
<br />
===Students in all courses of some institute===<br />
What is the status (deleted or not) of all Students (roleid = 5) in all courses of some Institute<br />
<code sql><br />
SELECT c.id, c.fullname, u.firstname, u.lastname, u.deleted<br />
FROM prefix_course AS c<br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid<br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE ra.roleid =5<br />
AND ctx.instanceid = c.id<br />
AND u.institution = 'please enter school name here'<br />
</code><br />
<br />
===Full User info (for deleted users)===<br />
Including extra custom profile fields (from prefix_user_info_data)<br />
<code sql><br />
SELECT * <br />
FROM prefix_user as u <br />
JOIN prefix_user_info_data as uid ON uid.userid = u.id <br />
JOIN prefix_user_info_field as uif ON (uid.fieldid = uif.id AND uif.shortname = 'class')<br />
WHERE `deleted` = "1" and `institution`="your school name" and `department` = "your department" and `data` = "class level and number"<br />
</code><br />
<br />
===User's courses===<br />
change "u.id = 2" with a new user id<br />
<code sql><br />
SELECT u.firstname, u.lastname, c.id, c.fullname<br />
FROM prefix_course AS c<br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid<br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE u.id = 2<br />
</code><br />
<br />
===List Users with extra info (email) in current course===<br />
blocks/configurable_reports replaces %%COURSEID%% with course id.<br />
<code sql><br />
SELECT u.firstname, u.lastname, u.email<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS context ON context.id = ra.contextid AND context.contextlevel = 50<br />
JOIN prefix_course AS c ON c.id = context.instanceid AND c.id = %%COURSEID%%<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
</code><br />
<br />
===List Students with enrollment and completion dates in current course===<br />
This is meant to be a "global" report in Configurable Reports containing the following:<br />
firstname, lastname, idnumber, institution, department, email, student enrolment date, student completion date<br />
Note: for PGSQL, use to_timestamp() instead of FROM_UNIXTIME()<br />
Contributed by Elizabeth Dalton, Moodle HQ<br />
<br />
<code sql><br />
SELECT <br />
u.firstname<br />
, u.lastname<br />
, u.idnumber<br />
, u.institution<br />
, u.department<br />
, u.email<br />
, FROM_UNIXTIME(cc.timeenrolled)<br />
, FROM_UNIXTIME(cc.timecompleted)<br />
<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS context ON context.id = ra.contextid AND context.contextlevel = 50<br />
JOIN prefix_course AS c ON c.id = context.instanceid AND c.id = %%COURSEID%%<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
JOIN prefix_course_completions AS cc ON cc.course = c.id AND cc.userid = u.id<br />
</code><br />
<br />
===Special Roles===<br />
<code sql><br />
SELECT ra.roleid,r.name<br />
,concat('<a target="_new" href="%%WWWROOT%%/course/user.php?id=1&user=',ra.userid,'">',u.firstname ,' ',u.lastname,'</a>') AS Username<br />
,concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS Course<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_role AS r ON r.id = ra.roleid<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
JOIN prefix_context AS ctx ON (ctx.id = ra.contextid AND ctx.contextlevel = 50)<br />
JOIN prefix_course AS c ON ctx.instanceid = c.id<br />
WHERE ra.roleid > 6<br />
</code><br />
<br />
===Courses without Teachers===<br />
Actually, shows the number of Teachers in a course.<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') as Course<br />
,(SELECT Count( ra.userid ) AS Users FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id) AS Teachers<br />
FROM prefix_course AS c<br />
ORDER BY Teachers ASC<br />
</code><br />
<br />
===List of users who have been enrolled for more than 4 weeks===<br />
For Moodle 2.2 , by Isuru Madushanka Weerarathna <br />
<code sql><br />
SELECT uenr.userid As User, IF(enr.courseid=uenr.courseid ,'Y','N') As Enrolled, <br />
IF(DATEDIFF(NOW(), FROM_UNIXTIME(uenr.timecreated))>=28,'Y','N') As EnrolledMoreThan4Weeks<br />
FROM prefix_enrol As enr, prefix_user_enrolments AS uenr<br />
WHERE enr.id = uenr.enrolid AND enr.status = uenr.status<br />
</code><br />
<br />
=== List of users with language===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
An issue with systems that do not have their default language set up properly is the need to do a mass change for all users to a localization. A common case is changing default English to American English. <br />
<br />
This will show you the language setting for all users:<br />
<code sql><br />
SELECT username, lang from prefix_user <br />
</code><br />
<br />
NOTE: UPDATE commands require the ability to alter the database directly via tools like Adminer or PHPMyAdmin or other db tools.<br />
<br />
This code will change the setting from 'en' to 'en_us' for all users:<br />
<br />
<code sql><br />
UPDATE prefix_user SET lang = 'en_us' WHERE lang = 'en'<br />
</code><br />
<br />
To do this for only users who have a particular country set, use this as an example:<br />
<code sql><br />
UPDATE prefix_user SET lang = 'en_us' WHERE country = 'US' AND lang = 'en'<br />
</code><br />
<br />
=== List of users with Authentication ===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
Sometimes you need to do mass changes of authentication methods. A common case is changing default manual to LDAP. <br />
<br />
This will show you the Authentication setting for all users:<br />
<code sql><br />
SELECT username, auth from prefix_user <br />
</code><br />
<br />
NOTE: UPDATE commands require the ability to alter the database directly via tools like Adminer or PHPMyAdmin or other db tools. <br />
<br />
This code will change the setting from 'manual' to 'ldap' for all users except for the first two accounts which are Guest and Admin. (WARNING: it is bad practice to change your admin account from manual to an external method as failure of that external method will lock you out of Moodle as admin.)<br />
<br />
<code sql><br />
UPDATE prefix_user SET auth = 'ldap' WHERE auth = 'manual' AND id > 2<br />
</code><br />
<br />
=== Compare role capability and permissions ===<br />
<code sql><br />
SELECT DISTINCT mrc.capability <br />
,(SELECT rc.permission FROM `mdl_role_capabilities` AS rc WHERE rc.capability = mrc.capability <br />
AND rc.roleid = '1' AND rc.contextid = '1') AS Manager<br />
,(SELECT rc.permission FROM `mdl_role_capabilities` AS rc WHERE rc.capability = mrc.capability <br />
AND rc.roleid = '2' AND rc.contextid = '1') AS CourseCreator<br />
,(SELECT rc.permission FROM `mdl_role_capabilities` AS rc WHERE rc.capability = mrc.capability <br />
AND rc.roleid = '3' AND rc.contextid = '1') AS Teacher<br />
,(SELECT rc.permission FROM `mdl_role_capabilities` AS rc WHERE rc.capability = mrc.capability <br />
AND rc.roleid = '4' AND rc.contextid = '1') AS AssistantTeacher<br />
,(SELECT rc.permission FROM `mdl_role_capabilities` AS rc WHERE rc.capability = mrc.capability <br />
AND rc.roleid = '5' AND rc.contextid = '1') AS Student<br />
,(SELECT rc.permission FROM `mdl_role_capabilities` AS rc WHERE rc.capability = mrc.capability <br />
AND rc.roleid = '6' AND rc.contextid = '1') AS Guest<br />
<br />
FROM `mdl_role_capabilities` AS mrc<br />
</code><br />
<br />
=== User's accumulative time spent in course ===<br />
A sum up of the time delta between logstore_standard_log user's records, considering the a 2 hour session limit.<br />
<br />
Uses: current user's id %%USERID%% and current course's id %%COURSEID%% <br />
<br />
And also using a date filter (which can be ignored) <br />
<br />
The extra "User" field is used as a dummy field for the Line chart Series field, in which I use X=id, Series=Type, Y=delta.<br />
<br />
<code sql><br />
SELECT <br />
l.id, <br />
l.timecreated, <br />
DATE_FORMAT(FROM_UNIXTIME(l.timecreated),'%d-%m-%Y') AS dTime,<br />
@prevtime := (SELECT max(timecreated) FROM mdl_logstore_standard_log <br />
WHERE userid = %%USERID%% and id < l.id ORDER BY id ASC LIMIT 1) AS prev_time,<br />
IF (l.timecreated - @prevtime < 7200, @delta := @delta + (l.timecreated-@prevtime),0) AS sumtime,<br />
l.timecreated-@prevtime AS delta,<br />
"User" as type<br />
<br />
FROM prefix_logstore_standard_log as l, <br />
(SELECT @delta := 0) AS s_init <br />
# Change UserID<br />
WHERE l.userid = %%USERID%% AND l.courseid = %%COURSEID%%<br />
%%FILTER_STARTTIME:l.timecreated:>%% %%FILTER_ENDTIME:l.timecreated:<%% <br />
</code><br />
<br />
=== Low-Participation Student Report ===<br />
Contributed by Elizabeth Dalton, Granite State College / Moodle HQ<br />
<br />
This report returns a list of students who are enrolled in courses filtered by a short-name text marker (in this case "OL-") in the specified category, but have very low participation in the course during the specified time period (fewer than 2 "Edits" to Activity Modules, indicating few active contributions to the course). The number of "Edits" is provided for each student for the time period specified.<br />
<br />
An "Edit" is defined as course activity other than viewing content. Click the "Logs" link to review the student activity. The Logs offer the option to review "View" activity as well as "Edit" activity.<br />
<br />
Only "visible" courses are included in this report. The report may be downloaded as an Excel spreadsheet.<br />
<br />
Don't forget to set up Filters: "Start / End date filter" and "Filter categories" on the Filters tab in Configurable reports.<br />
<br />
<code sql><br />
SELECT u.lastname AS Last, u.firstname AS First, u.idnumber AS IDnumber, u.email AS email, c.shortname AS CourseID, count(l.id) AS Edits, CONCAT('<a target="_new" href="https://learn.granite.edu/report/log/index.php',CHAR(63),'chooselog=1&showusers=1&showcourses=0&id=',c.id,'&user=',u.id,'&date=0&modid=&modaction=-view&logformat=showashtml','">','Logs','</a>') AS Link<br />
<br />
FROM prefix_user AS u<br />
JOIN prefix_role_assignments AS ra ON u.id = ra.userid<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
<br />
LEFT JOIN prefix_log AS l ON l.userid = u.id AND l.course = c.id AND l.action NOT LIKE "view%" %%FILTER_STARTTIME:l.TIME:>%% %%FILTER_ENDTIME:l.TIME:<%%<br />
<br />
WHERE ra.roleid =5<br />
AND ctx.instanceid = c.id<br />
AND c.visible=1<br />
# This prefix filter allows the exclusion of non-online courses at the original institution. Alter this to fit your institution, or remove it.<br />
AND c.shortname LIKE '%OL-%'<br />
%%FILTER_CATEGORIES:c.category%%<br />
<br />
GROUP BY u.idnumber<br />
<br />
HAVING Edits < 2<br />
</code><br />
<br />
=== Messages of All Users in a Specific Course ===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
NOTE: This query will probably not work at all in 3.5 now due to the changes in the structure of the Messages database. - RT<br />
<br />
This query shows the personal messages between users in a specific course, given the course id number. Properly speaking, personal messages pertain only to users and are not part of courses, but by filtering enrollments for roles in a course, you can show this. <br />
<br />
This report as is shows only the messages between Teachers and Students, as the WHERE statement contains and AND ((...))) section that restrict this report to ONLY messages between Teachers (role id = 3) and Students (role id =5). Remove that part of the statement if you wish to see _all_ messages between all users, e.g. teachers to teachers, student to student. <br />
<br />
Also, if you have created custom roles, you can replace the default id numbers with custom ones to further enhance the report.<br />
<br />
<code sql><br />
SELECT <br />
u.username AS 'From',<br />
CONCAT(u.firstname ,' ',u.lastname) AS 'From Name',<br />
u2.username AS 'To',<br />
CONCAT(u2.firstname ,' ',u2.lastname) AS 'To Name',<br />
DATE_FORMAT(FROM_UNIXTIME(me.timecreated), '%Y-%m-%d %H:%i') AS 'When',<br />
me.subject AS 'Subject', <br />
me.smallmessage AS 'Message'<br />
FROM prefix_message me<br />
JOIN prefix_role_assignments AS ra ON ra.userid = me.useridfrom AND ra.roleid IN (3,4,5) <br />
JOIN prefix_role_assignments AS ra2 ON ra2.userid = me.useridto AND ra2.roleid IN (3,4,5) <br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id AND ra2.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
JOIN prefix_user u ON u.id = me.useridfrom<br />
JOIN prefix_user u2 ON u2.id = me.useridto<br />
WHERE c.id=## <br />
AND ((ra.roleid = 3 AND ra2.roleid = 5) OR (ra.roleid = 5 AND ra2.roleid = 3)) <br />
ORDER BY me.useridfrom, me.useridto, me.timecreated<br />
</code><br />
<br />
==Log Activity Reports==<br />
===Count all Active Users by ROLE in a course category (including all of its sub-categories)===<br />
<code sql><br />
SELECT COUNT(DISTINCT l.userid) as active<br />
FROM mdl_course as c<br />
JOIN mdl_context AS ctx ON ctx.instanceid=c.id<br />
JOIN mdl_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN mdl_user_lastaccess as l ON ra.userid = l.userid<br />
JOIN mdl_course_categories AS cats ON c.category = cats.id<br />
WHERE c.category=cats.id AND (<br />
cats.path LIKE '%/80/%'<br />
OR cats.path LIKE '%/80'<br />
) <br />
AND ra.roleid=3 AND ctx.contextlevel=50 #ra.roleid= TEACHER 3, NON-EDITING TEACHER 4, STUDENT 5<br />
AND l.timeaccess > (unix_timestamp() - ((60*60*24)*NO_OF_DAYS)) #NO_OF_DAYS change to number<br />
</code><br />
===Detailed "VIEW" ACTION for each ROLE (TEACHER,NONE-EDITING TEACHER and STUDENT)===<br />
<code sql><br />
SELECT l.action, count( l.userid ) as counter , r.name<br />
FROM `prefix_log` as l<br />
JOIN `prefix_role_assignments` AS ra on l.userid = ra.userid<br />
JOIN `prefix_role` AS r ON ra.roleid = r.id<br />
WHERE (ra.roleid IN (3,4,5)) AND (l.action LIKE '%view%' )<br />
GROUP BY roleid,l.action<br />
order by r.name,counter desc<br />
</code><br />
<br />
===Total Activity of Roles:"Teacher" and "None-Editing Teacher" by Dates and by Hours===<br />
The output columns of this report table can be used as base for a Pivot-Table<br />
which will show the amount of '''activity''' per '''hour''' per '''days''' in 3D graph view.<br />
<br />
<code sql><br />
SELECT DATE_FORMAT( FROM_UNIXTIME( l.time ) , '%Y-%m-%d' ) AS grptimed ,<br />
DATE_FORMAT( FROM_UNIXTIME( l.time ) , '%k' ) AS grptimeh , count( l.userid ) AS counter <br />
FROM `prefix_log` AS l<br />
JOIN prefix_user AS u ON u.id = l.userid<br />
JOIN prefix_role_assignments AS ra ON l.userid = ra.userid<br />
JOIN prefix_role AS r ON r.id = ra.roleid<br />
WHERE ra.roleid IN (3,4)<br />
GROUP BY grptimed,grptimeh<br />
ORDER BY grptimed,grptimeh<br />
</code><br />
<br />
===How many LOGINs per user and user's Activity===<br />
+ link username to a user activity graph report<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/user.php?id=1&user=',u.id,'&mode=alllogs">',u.firstname ,' ',u.lastname,'</a>') as Username<br />
,count(*) as logins<br />
,(SELECT count(*) FROM prefix_log WHERE userid = l.userid GROUP BY userid) as Activity <br />
FROM prefix_log as l JOIN prefix_user as u ON l.userid = u.id <br />
WHERE `action` LIKE '%login%' group by userid<br />
ORDER BY Activity DESC<br />
</code><br />
===Distinct user logins per month===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
The following will show you the months of the current calendar year with the total number of distinct, unique user logins per month. Change the year in the WHERE clause to the year you need.<br />
<br />
<code sql><br />
SELECT <br />
COUNT(DISTINCT l.userid) AS 'DistinctUserLogins', <br />
DATE_FORMAT(FROM_UNIXTIME(l.timecreated), '%M') AS 'Month'<br />
FROM prefix_logstore_standard_log l<br />
WHERE l.action = 'loggedin' AND YEAR(FROM_UNIXTIME(l.timecreated)) = '2017' <br />
GROUP BY MONTH(FROM_UNIXTIME(l.timecreated))<br />
</code><br />
<br />
===Total activity per course, per unique user on the last 24h===<br />
<code sql><br />
SELECT<br />
COUNT(DISTINCT userid) AS countUsers<br />
, COUNT(l.courseid) AS countVisits<br />
, CONCAT('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">', c.fullname, '</a>') AS Course<br />
<br />
FROM mdl_logstore_standard_log AS l<br />
JOIN mdl_course AS c ON c.id = l.courseid<br />
WHERE l.courseid > 0<br />
AND FROM_UNIXTIME(l.timecreated) >= DATE_SUB(NOW(), INTERVAL 1 DAY)<br />
AND c.fullname LIKE '%תשעו%'<br />
GROUP BY l.courseid<br />
ORDER BY countVisits DESC<br />
</code><br />
<br />
===Weekly Instructor Online Participation===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
Displays participation of instructors in all courses per week of a term, including pre-term and post-term edits. An edit is defined as a change to the course, such as a discussion post, the grading of an assignment, or the uploading of file attachments, as well as alterations to course content.<br />
<br />
* To specify a subject and/or course number, use % as a wildcard, e.g. ARTS% or ARTS501%<br />
* To match part of a last name, use %, e.g. Smi% will match "Smith", "Smile", etc.<br />
<br />
At our institution, we include filters on the course name or category to constrain by terms. These are very specific to how course names and categories are constructed at our institution, so I've removed those elements from this code. Also, our terms are 12 weeks long. You would want to insert additional "SUM" lines for longer terms, or remove lines for shorter terms.<br />
<br />
'''Note''': This report can take a long time to run. While it can be run in Configurable Reports on demand, it may be more appropriate to implement it in the Ad Hoc Queries plugin as a scheduled report.<br />
<br />
'''Note''': This version uses legacy (pre-2.7) logs. See below for post-2.7 Standard Logs version.<br />
<br />
<code sql><br />
SELECT <br />
c.shortname AS CourseID<br />
, cc.name AS Category<br />
, CONCAT(u.firstname ,' ',u.lastname) AS Instructor<br />
<br />
, (SELECT COUNT( ra2.userid ) AS Users2 FROM prefix_role_assignments AS ra2<br />
JOIN prefix_context AS ctx2 ON ra2.contextid = ctx2.id<br />
WHERE ra2.roleid = 5 AND ctx2.instanceid = c.id) AS Students<br />
<br />
, c.startdate AS Course_Start_Date<br />
<br />
, c.visible AS Visible<br />
<br />
, COUNT(l.id) AS Edits<br />
<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time)) - WEEK(FROM_UNIXTIME(c.startdate))<0,1,0)) AS BeforeTerm<br />
<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=0,1,0)) AS Week1<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=1,1,0)) AS Week2<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=2,1,0)) AS Week3<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=3,1,0)) AS Week4<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=4,1,0)) AS Week5<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=5,1,0)) AS Week6<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=6,1,0)) AS Week7<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=7,1,0)) AS Week8<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=8,1,0)) AS Week9<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=9,1,0)) AS Week10<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=10,1,0)) AS Week11<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=11,1,0)) AS Week12<br />
<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))>=12,1,0)) AS AfterTerm<br />
<br />
, CONCAT('<a target="_new" href="%%WWWROOT%%/report/log/index.php',CHAR(63),'chooselog=1&showusers=1&showcourses=0&id=',c.id,'&user=',u.id,'&date=0&modid=&modaction=&logformat=showashtml','">','Logs','</a>') AS Link<br />
<br />
FROM prefix_user AS u<br />
JOIN prefix_role_assignments AS ra ON u.id = ra.userid<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
JOIN prefix_course_categories as cc ON c.category = cc.id<br />
<br />
LEFT JOIN prefix_log AS l ON l.userid = u.id AND l.course = c.id AND l.action NOT LIKE "view%"<br />
<br />
WHERE ra.roleid =3<br />
AND ctx.instanceid = c.id<br />
AND c.shortname LIKE :course<br />
AND u.lastname LIKE :last_name<br />
<br />
GROUP BY u.idnumber, c.id<br />
HAVING students > 0<br />
ORDER BY c.shortname<br />
</code><br />
<br />
'''Note''': Post-2.7 log version:<br />
<br />
<code sql><br />
SELECT <br />
c.shortname AS CourseID<br />
, cc.name AS Category<br />
, CONCAT(u.firstname ,' ',u.lastname) AS Instructor<br />
<br />
, (SELECT COUNT( ra2.userid ) AS Users2 FROM prefix_role_assignments AS ra2<br />
JOIN prefix_context AS ctx2 ON ra2.contextid = ctx2.id<br />
WHERE ra2.roleid = 5 AND ctx2.instanceid = c.id) AS Students<br />
<br />
, FROM_UNIXTIME(c.startdate) AS Course_Start_Date<br />
<br />
, c.visible AS Visible<br />
<br />
, COUNT(DISTINCT l.id) AS Edits<br />
<br />
, COUNT(DISTINCT IF((l.timecreated-c.startdate)<0,l.id,NULL)) AS 'Before Term'<br />
<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=0,l.id,NULL)) AS 'Week 1'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=1,l.id,NULL)) AS 'Week 2'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=2,l.id,NULL)) AS 'Week 3'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=3,l.id,NULL)) AS 'Week 4'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=4,l.id,NULL)) AS 'Week 5'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=5,l.id,NULL)) AS 'Week 6'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=6,l.id,NULL)) AS 'Week 7'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=7,l.id,NULL)) AS 'Week 8'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=8,l.id,NULL)) AS 'Week 9'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=9,l.id,NULL)) AS 'Week 10'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=10,l.id,NULL)) AS 'Week 11'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=11,l.id,NULL)) AS 'Week 12'<br />
<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))>=12,l.id,NULL)) AS 'After Term'<br />
<br />
, CONCAT('<a target="_new" href="%%WWWROOT%%/report/log/index.php',CHAR(63),'chooselog=1&showusers=1&showcourses=0&id=',c.id,'&user=',u.id,'&date=0&modid=&modaction=&logformat=showashtml','">','Logs','</a>') AS Link<br />
<br />
FROM prefix_user AS u<br />
LEFT JOIN prefix_role_assignments AS ra ON u.id = ra.userid<br />
LEFT JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
LEFT JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
LEFT JOIN prefix_course_categories as cc ON c.category = cc.id<br />
<br />
LEFT JOIN prefix_logstore_standard_log AS l ON l.userid = u.id AND l.courseid = c.id AND l.crud IN ('c','u')<br />
<br />
WHERE ra.roleid =3<br />
AND ctx.instanceid = c.id<br />
AND c.shortname LIKE '%OL-%'<br />
AND cc.idnumber LIKE '%current%'<br />
<br />
GROUP BY u.idnumber, c.id<br />
#HAVING students > 0<br />
ORDER BY RIGHT(c.shortname,2), c.shortname<br />
</code><br />
<br />
===Weekly Student Online Participation===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
Displays participation of students in the current course by week, including pre-term and post-term edits. An edit is defined as a change to the course, such as a discussion post, the submission of an assignment, or the completion of a quiz, as well as alterations to course content such as database entries (if permitted).<br />
<br />
Links to three other reports are also provided:<br />
<br />
* Logs: complete log entries for the student in the course, organized by date<br />
* Activity Outline: the "Outline Report" from the User Activity Reports, summarizing the student's activity in the course, organized by course content<br />
* Consolidated Activity Report: the "Complete Report" from the User Activity Reports, detailing the student's activity in the course, organized by course content (includes text of forum posts)<br />
<br />
'''Note''': This should be defined as a "Global" report (visible from within all courses). At our institution, our terms are 12 weeks long. You would want to insert additional "SUM" lines for longer terms, or remove lines for shorter terms. We pull advisor names into student user profiles as part of our configuration. These lines are present in the code below, but are commented out, as they are very specific to your Moodle configuration.<br />
<br />
'''Note''': This version of the report uses legacy (pre-2.7) logs. See below for a post-2.7 Standard Logs version.<br />
<br />
<code sql><br />
SELECT <br />
u.lastname AS 'Last Name'<br />
, u.firstname AS 'First Name'<br />
, COUNT(l.id) AS 'Edits'<br />
<br />
, SUM(IF((l.time-c.startdate)/7<0,1,0)) AS 'Before Term'<br />
<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=0,1,0)) AS 'Week 1'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=1,1,0)) AS 'Week 2'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=2,1,0)) AS 'Week 3'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=3,1,0)) AS 'Week 4'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=4,1,0)) AS 'Week 5'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=5,1,0)) AS 'Week 6'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=6,1,0)) AS 'Week 7'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=7,1,0)) AS 'Week 8'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=8,1,0)) AS 'Week 9'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=9,1,0)) AS 'Week 10'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=10,1,0)) AS 'Week 11'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=11,1,0)) AS 'Week 12'<br />
<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))>=15,1,0)) AS 'After Term'<br />
<br />
, CONCAT('<a target="_blank" href="%%WWWROOT%%/report/log/index.php',CHAR(63),'chooselog=1&showusers=1&showcourses=0&id=',c.id,'&user=',u.id,'&date=0&modid=&modaction=&logformat=showashtml','">','Logs','</a>') AS 'Logs'<br />
<br />
, CONCAT('<a target="_blank" href="%%WWWROOT%%/report/outline/user.php',CHAR(63),'id=',u.id,'&course=',c.id,'&mode=outline">','Outline','</a>') AS 'Activity Outline'<br />
<br />
, CONCAT('<a target="_blank" href="%%WWWROOT%%/report/outline/user.php',CHAR(63),'id=',u.id,'&course=',c.id,'&mode=complete">','Activity','</a>') AS 'Consolidated Activity'<br />
<br />
FROM prefix_user AS u<br />
JOIN prefix_role_assignments AS ra ON u.id = ra.userid<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
JOIN prefix_course_categories as cc ON c.category = cc.id<br />
<br />
LEFT JOIN prefix_log AS l ON l.userid = u.id AND l.course = c.id AND l.action NOT LIKE "view%"<br />
<br />
WHERE ra.roleid =5<br />
AND ctx.instanceid = c.id<br />
<br />
AND c.id = %%COURSEID%%<br />
<br />
GROUP BY u.idnumber<br />
<br />
ORDER BY u.lastname, u.firstname<br />
</code><br />
<br />
'''Note''': Post-2.7 (Standard Logs) version<br />
<br />
<code sql><br />
SELECT <br />
u.lastname AS 'Last Name'<br />
, u.firstname AS 'First Name'<br />
, COUNT(l.id) AS 'Edits'<br />
<br />
, COUNT(DISTINCT IF((l.timecreated-c.startdate)<0,l.id,NULL)) AS 'Before Term'<br />
<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=0,l.id,NULL)) AS 'Week 1'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=1,l.id,NULL)) AS 'Week 2'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=2,l.id,NULL)) AS 'Week 3'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=3,l.id,NULL)) AS 'Week 4'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=4,l.id,NULL)) AS 'Week 5'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=5,l.id,NULL)) AS 'Week 6'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=6,l.id,NULL)) AS 'Week 7'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=7,l.id,NULL)) AS 'Week 8'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=8,l.id,NULL)) AS 'Week 9'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=9,l.id,NULL)) AS 'Week 10'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=10,l.id,NULL)) AS 'Week 11'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=11,l.id,NULL)) AS 'Week 12'<br />
<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))>=12,l.id,NULL)) AS 'After Term'<br />
<br />
# Our institution stores academic advisor names and emails in custom profile fields<br />
#, CONCAT('<a href="mailto:',uce.data,'">',uid.data, '</a>') AS 'Academic Advisor'<br />
<br />
, CONCAT('<a target="_blank" href="%%WWWROOT%%/report/log/index.php',CHAR(63),'chooselog=1&showusers=1&showcourses=0&id=',c.id,'&user=',u.id,'&date=0&modid=&modaction=&logformat=showashtml','">','Logs','</a>') AS 'Logs'<br />
<br />
, CONCAT('<a target="_blank" href="%%WWWROOT%%/report/outline/user.php',CHAR(63),'id=',u.id,'&course=',c.id,'&mode=outline">','Outline','</a>') AS 'Activity Outline'<br />
<br />
, CONCAT('<a target="_blank" href="%%WWWROOT%%/report/outline/user.php',CHAR(63),'id=',u.id,'&course=',c.id,'&mode=complete">','Activity','</a>') AS 'Consolidated Activity'<br />
<br />
, CONCAT('<a target="_blank" href="%%WWWROOT%%/mod/forum/user.php',CHAR(63),'id=',u.id,'&course=',c.id,'">','Posts','</a>') AS 'Posts'<br />
<br />
FROM prefix_user AS u<br />
JOIN prefix_role_assignments AS ra ON u.id = ra.userid<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
JOIN prefix_course_categories as cc ON c.category = cc.id<br />
<br />
# student academic coach - you can include custom profile field data with these methods<br />
# LEFT JOIN prefix_user_info_data as uid ON u.id = uid.userid AND uid.fieldid = '2'<br />
# student academic coach email<br />
# LEFT JOIN prefix_user_info_data as uce on u.id = uce.userid AND uce.fieldid = '6'<br />
<br />
LEFT JOIN prefix_logstore_standard_log AS l ON l.userid = u.id AND l.courseid = c.id AND l.crud IN ('c','u')<br />
<br />
WHERE ra.roleid =5<br />
AND ctx.instanceid = c.id<br />
<br />
AND c.id = %%COURSEID%%<br />
<br />
GROUP BY u.idnumber<br />
<br />
ORDER BY u.lastname, u.firstname<br />
</code><br />
<br />
===My Weekly Online Participation===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
Displays participation of the '''current user''' in the '''current course''' by week, including pre-term and post-term submissions/edits. A submission/edit is defined as a change to the course, such as a discussion post, the submission of an assignment, or the completion of a quiz, as well as alterations to course content such as database entries or new course activities or resources (if permitted).<br />
<br />
This report uses Standard Logs (post 2.7).<br />
<br />
<code sql><br />
SELECT <br />
<br />
l.component AS 'activity'<br />
<br />
, COUNT(DISTINCT IF((l.timecreated-c.startdate)<0,l.id,NULL)) AS 'Before Term'<br />
<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=0,l.id,NULL)) AS 'Week 1'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=1,l.id,NULL)) AS 'Week 2'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=2,l.id,NULL)) AS 'Week 3'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=3,l.id,NULL)) AS 'Week 4'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=4,l.id,NULL)) AS 'Week 5'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=5,l.id,NULL)) AS 'Week 6'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=6,l.id,NULL)) AS 'Week 7'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=7,l.id,NULL)) AS 'Week 8'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=8,l.id,NULL)) AS 'Week 9'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=9,l.id,NULL)) AS 'Week 10'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=10,l.id,NULL)) AS 'Week 11'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=11,l.id,NULL)) AS 'Week 12'<br />
<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))>=12,l.id,NULL)) AS 'After Term'<br />
<br />
, COUNT(l.id) AS 'Total'<br />
<br />
FROM prefix_user AS u<br />
JOIN prefix_role_assignments AS ra ON u.id = ra.userid<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
JOIN prefix_course_categories as cc ON c.category = cc.id<br />
<br />
LEFT JOIN prefix_logstore_standard_log AS l ON l.userid = u.id AND l.courseid = c.id AND l.crud IN ('c','u')<br />
<br />
WHERE 1<br />
AND ctx.instanceid = c.id<br />
<br />
AND c.id = %%COURSEID%%<br />
AND u.id = %%USERID%%<br />
<br />
GROUP BY l.component<br />
<br />
ORDER BY l.component<br />
</code><br />
<br />
===Faculty/Student Interactions===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
Returns a count of instructor and other-student responses to student activity for the specified time period. This report can help indicate whether students' comments are being responded to, as well as summarizing post activity by students during the specified time.<br />
<br />
'''Note''': This version of the report uses legacy (pre-2.7) logs. See below for the post-2.7 Standard Logs version.<br />
<br />
'''Note''': This should be defined as a "Global" report (visible from within all courses). <br />
<br />
'''Note''': This report can take a long time to run. <br />
<br />
<br />
<code sql><br />
SELECT <br />
<br />
# Identify student<br />
CONCAT('<a target="_blank" href="%%WWWROOT%%/message/index.php?id=' , allstu.id , '">' , allstu.firstname , ' ' , allstu.lastname , '</a>' ) AS 'Student - click to send message'<br />
<br />
, IF((COUNT(DISTINCT IF(fps.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fps.id,NULL) )>0) OR (COUNT(DISTINCT IF(asb.timemodified > (UNIX_TIMESTAMP() - (7*24*60*60)),asb.id,NULL))>0) OR (SELECT COUNT(DISTINCT mfs.id) FROM prefix_message AS mfs WHERE mfs.useridfrom = allstu.id AND mfs.useridto = instr.id AND mfs.timecreated > (UNIX_TIMESTAMP() - (7*24*60*60))),'YES','NO') AS 'Student Participated This week'<br />
<br />
, IF((COUNT(DISTINCT IF(fpi.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpi.id,NULL) )>0) OR (COUNT(DISTINCT IF(asg.timemodified > (UNIX_TIMESTAMP() - (7*24*60*60)),asg.id,NULL))>0) OR (SELECT COUNT(DISTINCT mts.id) FROM prefix_message AS mts WHERE mts.useridfrom = instr.id AND mts.useridto = allstu.id AND mts.timecreated > (UNIX_TIMESTAMP() - (7*24*60*60))),'YES','NO') AS 'Student Contacted This week'<br />
<br />
## Only posts within last 7 days<br />
<br />
# Count posts by student<br />
, COUNT(DISTINCT IF(fps.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fps.id,NULL)) AS 'Forum Stu Posts - 7 days'<br />
<br />
# Count replies to student posts by instructors<br />
, COUNT(DISTINCT IF(fpi.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpi.id,NULL) ) AS 'Forum Instr Replies - 7 days'<br />
<br />
# using link back to student posts on replies, get unique student IDs responded<br />
, COUNT(DISTINCT IF(fpsr.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpsr.id,NULL)) - COUNT(DISTINCT IF(fpi.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpi.id,NULL) ) AS 'Forum Stu Replies - 7 days'<br />
<br />
# all replies<br />
, COUNT(DISTINCT IF(fpsr.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpsr.id,NULL)) AS 'Forum All Replies - 7 days'<br />
<br />
# add in count of graded assignments - 7 days<br />
, COUNT(DISTINCT IF(asb.timemodified > (UNIX_TIMESTAMP() - (7*24*60*60)),asb.id,NULL)) AS 'Assign Submit - 7 days'<br />
, COUNT(DISTINCT IF(asg.timemodified > (UNIX_TIMESTAMP() - (7*24*60*60)),asg.id,NULL)) AS 'Assign Grades - 7 days'<br />
<br />
# Messages between students and instructors - 7 days<br />
, (SELECT COUNT(DISTINCT mfs.id) FROM prefix_message AS mfs WHERE mfs.useridfrom = allstu.id AND mfs.useridto = instr.id AND mfs.timecreated > (UNIX_TIMESTAMP() - (7*24*60*60))) AS 'Msg Stu to Instr - 7 days'<br />
, (SELECT COUNT(DISTINCT mts.id) FROM prefix_message AS mts WHERE mts.useridfrom = instr.id AND mts.useridto = allstu.id AND mts.timecreated > (UNIX_TIMESTAMP() - (7*24*60*60))) AS 'Msg Instr to Stu - 7 days'<br />
<br />
## All posts in course so far<br />
# Count posts by student<br />
, COUNT(DISTINCT fps.id) AS 'Forum Stu Posts - to date'<br />
<br />
# Count replies to student posts by instructors<br />
, COUNT(DISTINCT fpi.id) AS 'Forum Instr Replies - to date'<br />
<br />
# using link back to student posts on replies, get unique student IDs responded<br />
, COUNT(DISTINCT fpsr.id) - COUNT(DISTINCT fpi.id) AS 'Forum Stu Replies - to date'<br />
<br />
# all replies<br />
, COUNT(DISTINCT fpsr.id) AS 'Forum All Replies - to date'<br />
<br />
# add in count of graded assignments - whole course<br />
, COUNT(DISTINCT asb.id) AS 'Assign Submit - to date'<br />
, COUNT(DISTINCT asg.id) AS 'Assign Grades - to date'<br />
<br />
# Messages between students and instructors - to date<br />
, (SELECT COUNT(DISTINCT mfs.id) FROM prefix_message AS mfs WHERE mfs.useridfrom = allstu.id AND mfs.useridto = instr.id ) AS 'Msg Stu to Instr - to date'<br />
, (SELECT COUNT(DISTINCT mts.id) FROM prefix_message AS mts WHERE mts.useridfrom = instr.id AND mts.useridto = allstu.id) AS 'Msg Instr to Stu - to date'<br />
<br />
## JOINS<br />
<br />
# Start by getting all the students in the course<br />
FROM prefix_user AS allstu <br />
JOIN prefix_role_assignments AS ras ON allstu.id = ras.userid AND ras.roleid = 5<br />
JOIN prefix_context AS ctx ON ras.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
JOIN prefix_course_categories as cc ON c.category = cc.id<br />
<br />
# Now we get the forums and forum discussions from this course only<br />
LEFT JOIN prefix_forum AS frm ON frm.course = c.id AND c.id = %%COURSEID%%<br />
LEFT JOIN prefix_forum_discussions AS fd ON fd.course = %%COURSEID%% AND fd.forum = frm.id<br />
<br />
# These are forum discussion posts just by students within specified time<br />
LEFT JOIN prefix_forum_posts AS fps ON fps.userid = allstu.id AND fps.discussion = fd.id<br />
<br />
# Separately, we connect the instructors of the courses<br />
# We can use the context we have already gotten for the students<br />
LEFT JOIN prefix_role_assignments AS rai ON rai.contextid = ctx.id<br />
LEFT JOIN prefix_user AS instr ON instr.id = rai.userid AND rai.roleid =3<br />
<br />
# Now we will connect to posts by instructors that are replies to student posts<br />
# This is a left join, because we don't want to eliminate any students from the list<br />
LEFT JOIN prefix_forum_posts AS fpi ON fpi.discussion = fd.id AND fpi.userid = instr.id AND fpi.parent = fps.id<br />
<br />
# To get identities of only those students who were replied to:<br />
# Connect from instr replies back up to parent posts by students again<br />
# This has to be a LEFT JOIN, we know these posts exist but don't eliminate non-responded students<br />
LEFT JOIN prefix_forum_posts AS fpir ON fpir.id = fpi.parent<br />
<br />
# We also want to know if students are replying to one another<br />
# These are posts that are replies to student posts<br />
# Again, a left join<br />
LEFT JOIN prefix_forum_posts AS fpsr ON fpsr.discussion = fd.id AND fpsr.parent = fps.id<br />
<br />
# get the activity modules<br />
LEFT JOIN prefix_course_modules AS cm ON c.id = cm.course<br />
<br />
# get the assignments<br />
LEFT JOIN prefix_assign AS a ON cm.instance = a.id<br />
LEFT JOIN prefix_assign_submission AS asb ON a.id = asb.assignment AND asb.userid=allstu.id <br />
LEFT JOIN prefix_assign_grades AS asg ON asg.assignment = a.id AND asg.userid = allstu.id AND asg.assignment = asb.assignment <br />
<br />
# We care about messages that involve both the instructor and students of this course<br />
# messages from instructor to students:<br />
# LEFT JOIN prefix_message AS mts ON mts.useridfrom = instr.id AND mts.useridto = allstu.id<br />
# LEFT JOIN prefix_message AS mfs ON mfs.useridfrom = instr.id AND mfs.useridto = allstu.id<br />
<br />
WHERE <br />
c.id = %%COURSEID%% <br />
<br />
# GROUP BY c.shortname , allstu.id<br />
GROUP BY allstu.id<br />
<br />
ORDER BY allstu.lastname<br />
</code><br />
<br />
'''Note''': Post-2.7 Standard Logs version<br />
<br />
<code sql><br />
SELECT <br />
<br />
# Identify student<br />
CONCAT('<a target="_blank" href="%%WWWROOT%%/message/index.php?id=' , allstu.id , '">' , allstu.firstname , ' ' , allstu.lastname , '</a>' ) AS 'Student - click to send message'<br />
<br />
, IF((COUNT(DISTINCT IF(fps.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fps.id,NULL) )>0) OR (COUNT(DISTINCT IF(asb.timemodified > (UNIX_TIMESTAMP() - (7*24*60*60)),asb.id,NULL))>0) OR (SELECT COUNT(DISTINCT mfs.id) FROM prefix_message AS mfs WHERE mfs.useridfrom = allstu.id AND mfs.useridto = instr.id AND mfs.timecreated > (UNIX_TIMESTAMP() - (7*24*60*60))),'YES','NO') AS 'Student Participated This week'<br />
<br />
, IF((COUNT(DISTINCT IF(fpi.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpi.id,NULL) )>0) OR (COUNT(DISTINCT IF(asg.timemodified > (UNIX_TIMESTAMP() - (7*24*60*60)),asg.id,NULL))>0) OR (SELECT COUNT(DISTINCT mts.id) FROM prefix_message AS mts WHERE mts.useridfrom = instr.id AND mts.useridto = allstu.id AND mts.timecreated > (UNIX_TIMESTAMP() - (7*24*60*60))),'YES','NO') AS 'Student Contacted This week'<br />
<br />
## Only posts within last 7 days<br />
<br />
# Count posts by student<br />
, COUNT(DISTINCT IF(fps.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fps.id,NULL)) AS 'Forum Stu Posts - 7 days'<br />
<br />
# Count replies to student posts by instructors<br />
, COUNT(DISTINCT IF(fpi.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpi.id,NULL) ) AS 'Forum Instr Replies - 7 days'<br />
<br />
# using link back to student posts on replies, get unique student IDs responded<br />
, COUNT(DISTINCT IF(fpsr.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpsr.id,NULL)) - COUNT(DISTINCT IF(fpi.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpi.id,NULL) ) AS 'Forum Stu Replies - 7 days'<br />
<br />
# all replies<br />
, COUNT(DISTINCT IF(fpsr.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpsr.id,NULL)) AS 'Forum All Replies - 7 days'<br />
<br />
# add in count of graded assignments - 7 days<br />
, COUNT(DISTINCT IF(asb.timemodified > (UNIX_TIMESTAMP() - (7*24*60*60)),asb.id,NULL)) AS 'Assign Submit - 7 days'<br />
, COUNT(DISTINCT IF(asg.timemodified > (UNIX_TIMESTAMP() - (7*24*60*60)),asg.id,NULL)) AS 'Assign Grades - 7 days'<br />
<br />
# Messages between students and instructors - 7 days<br />
, (SELECT COUNT(DISTINCT mfs.id) FROM prefix_message AS mfs WHERE mfs.useridfrom = allstu.id AND mfs.useridto = instr.id AND mfs.timecreated > (UNIX_TIMESTAMP() - (7*24*60*60))) AS 'Msg Stu to Instr - 7 days'<br />
, (SELECT COUNT(DISTINCT mts.id) FROM prefix_message AS mts WHERE mts.useridfrom = instr.id AND mts.useridto = allstu.id AND mts.timecreated > (UNIX_TIMESTAMP() - (7*24*60*60))) AS 'Msg Instr to Stu - 7 days'<br />
<br />
## All posts in course so far<br />
# Count posts by student<br />
, COUNT(DISTINCT fps.id) AS 'Forum Stu Posts - to date'<br />
<br />
# Count replies to student posts by instructors<br />
, COUNT(DISTINCT fpi.id) AS 'Forum Instr Replies - to date'<br />
<br />
# using link back to student posts on replies, get unique student IDs responded<br />
, COUNT(DISTINCT fpsr.id) - COUNT(DISTINCT fpi.id) AS 'Forum Stu Replies - to date'<br />
<br />
# all replies<br />
, COUNT(DISTINCT fpsr.id) AS 'Forum All Replies - to date'<br />
<br />
# add in count of graded assignments - whole course<br />
, COUNT(DISTINCT asb.id) AS 'Assign Submit - to date'<br />
, COUNT(DISTINCT asg.id) AS 'Assign Grades - to date'<br />
<br />
# Messages between students and instructors - to date<br />
, (SELECT COUNT(DISTINCT mfs.id) FROM prefix_message AS mfs WHERE mfs.useridfrom = allstu.id AND mfs.useridto = instr.id ) AS 'Msg Stu to Instr - to date'<br />
, (SELECT COUNT(DISTINCT mts.id) FROM prefix_message AS mts WHERE mts.useridfrom = instr.id AND mts.useridto = allstu.id) AS 'Msg Instr to Stu - to date'<br />
<br />
## JOINS<br />
<br />
# Start by getting all the students in the course<br />
FROM prefix_user AS allstu <br />
JOIN prefix_role_assignments AS ras ON allstu.id = ras.userid AND ras.roleid = 5<br />
JOIN prefix_context AS ctx ON ras.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
JOIN prefix_course_categories as cc ON c.category = cc.id<br />
<br />
# Now we get the forums and forum discussions from this course only<br />
JOIN prefix_forum AS frm ON frm.course = c.id AND c.id = %%COURSEID%%<br />
JOIN prefix_forum_discussions AS fd ON fd.course = %%COURSEID%% AND fd.forum = frm.id<br />
<br />
# These are forum discussion posts just by students within specified time<br />
LEFT JOIN prefix_forum_posts AS fps ON fps.userid = allstu.id AND fps.discussion = fd.id<br />
<br />
# Separately, we connect the instructors of the courses<br />
# We can use the context we have already gotten for the students<br />
JOIN prefix_role_assignments AS rai ON rai.contextid = ctx.id<br />
JOIN prefix_user AS instr ON instr.id = rai.userid AND rai.roleid =3<br />
<br />
# Now we will connect to posts by instructors that are replies to student posts<br />
# This is a left join, because we don't want to eliminate any students from the list<br />
LEFT JOIN prefix_forum_posts AS fpi ON fpi.discussion = fd.id AND fpi.userid = instr.id AND fpi.parent = fps.id<br />
<br />
# To get identities of only those students who were replied to:<br />
# Connect from instr replies back up to parent posts by students again<br />
# This has to be a LEFT JOIN, we know these posts exist but don't eliminate non-responded students<br />
LEFT JOIN prefix_forum_posts AS fpir ON fpir.id = fpi.parent<br />
<br />
# We also want to know if students are replying to one another<br />
# These are posts that are replies to student posts<br />
# Again, a left join<br />
LEFT JOIN prefix_forum_posts AS fpsr ON fpsr.discussion = fd.id AND fpsr.parent = fps.id<br />
<br />
# get the activity modules<br />
JOIN prefix_course_modules AS cm ON c.id = cm.course<br />
<br />
# get the assignments<br />
JOIN prefix_assign AS a ON cm.instance = a.id<br />
LEFT JOIN prefix_assign_submission AS asb ON a.id = asb.assignment AND asb.userid=allstu.id <br />
LEFT JOIN prefix_assign_grades AS asg ON asg.assignment = a.id AND asg.userid = allstu.id AND asg.assignment = asb.assignment <br />
<br />
WHERE <br />
c.id = %%COURSEID%% <br />
<br />
# GROUP BY c.shortname , allstu.id<br />
GROUP BY allstu.id<br />
<br />
ORDER BY allstu.lastname<br />
</code><br />
<br />
===Student Resource Usage===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
Displays usage by students of all activities and resources in the current course by activity. Only activities and sections which are visible in the course are included. This version requires the new "Standard Logs" from Moodle 2.7+.<br />
<br />
'''Note''': This should be defined as a "Global" report (visible from within all courses). <br />
<br />
<code sql><br />
SELECT <br />
cs.section AS 'Week'<br />
, cs.name AS 'Section Name'<br />
, m.name AS 'item type'<br />
<br />
, CONCAT(<br />
COALESCE(a.name, ''), <br />
COALESCE(b.name,''), <br />
COALESCE(cert.name,''), <br />
COALESCE(chat.name,''), <br />
COALESCE(choice.name,''), <br />
COALESCE(data.name,''), <br />
COALESCE(feedback.name,''), <br />
COALESCE(folder.name,''), <br />
COALESCE(forum.name,''), <br />
COALESCE(glossary.name,''), <br />
COALESCE(imscp.name,''), <br />
COALESCE(lesson.name,''), <br />
COALESCE(p.name,''),<br />
COALESCE(questionnaire.name,''), <br />
COALESCE(quiz.name,''), <br />
COALESCE(cr.name,''), <br />
COALESCE(scorm.name,''), <br />
COALESCE(survey.name,''), <br />
COALESCE(url.name,''), <br />
COALESCE(wiki.name,''), <br />
COALESCE(workshop.name,''), <br />
COALESCE(kalvidassign.name,''), <br />
COALESCE(attendance.name,''), <br />
COALESCE(checklist.name,''), <br />
COALESCE(flashcard.name,''), <br />
COALESCE(lti.name,''), <br />
COALESCE(oublog.name,''), <br />
COALESCE(ouwiki.name,''), <br />
COALESCE(subpage.name,''), <br />
COALESCE(journal.name,''), <br />
COALESCE(lightboxgallery.name,''), <br />
COALESCE(elluminate.name,''), <br />
COALESCE(adaptivequiz.name,''), <br />
COALESCE(hotpot.name,''), <br />
COALESCE(wiziq.name,''), <br />
COALESCE(turnitintooltwo.name,''), <br />
COALESCE(kvr.name,'')<br />
) AS 'item name'<br />
<br />
<br />
, SUM(IF(l.crud IN ('r'),1,0)) AS 'total views'<br />
, SUM(IF(l.crud IN ('c','u'),1,0)) AS 'total submissions'<br />
, COUNT(DISTINCT IF(l.crud IN ('r'),u.id,NULL)) AS 'count of students who viewed'<br />
, COUNT(DISTINCT IF(l.crud IN ('c','u'),u.id,NULL)) AS 'count of students who submitted'<br />
<br />
FROM prefix_user AS u<br />
JOIN prefix_role_assignments AS ra ON u.id = ra.userid<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
JOIN prefix_course_categories as cc ON c.category = cc.id<br />
<br />
JOIN prefix_course_sections AS cs ON cs.course = c.id AND cs.section <= 14 #AND cs.section > 0<br />
LEFT JOIN prefix_course_modules AS cm ON cm.course = c.id AND cm.section = cs.id<br />
JOIN prefix_modules AS m ON m.id = cm.module AND m.name NOT LIKE 'label'<br />
<br />
LEFT JOIN prefix_assign AS a ON a.id = cm.instance AND m.name = 'assign'<br />
LEFT JOIN prefix_book AS b ON b.id = cm.instance AND m.name = 'book'<br />
LEFT JOIN prefix_certificate AS cert ON cert.id = cm.instance AND m.name = 'certificate'<br />
LEFT JOIN prefix_chat AS chat ON chat.id = cm.instance AND m.name = 'chat'<br />
LEFT JOIN prefix_choice AS choice ON choice.id = cm.instance AND m.name = 'choice'<br />
LEFT JOIN prefix_data AS data ON data.id = cm.instance AND m.name = 'data'<br />
LEFT JOIN prefix_feedback AS feedback ON feedback.id = cm.instance AND m.name = 'feedback'<br />
LEFT JOIN prefix_folder AS folder ON folder.id = cm.instance AND m.name = 'folder'<br />
LEFT JOIN prefix_forum AS forum ON forum.id = cm.instance AND m.name = 'forum'<br />
LEFT JOIN prefix_glossary AS glossary ON glossary.id = cm.instance AND m.name = 'glossary'<br />
LEFT JOIN prefix_imscp AS imscp ON imscp.id = cm.instance AND m.name = 'imscp'<br />
LEFT JOIN prefix_lesson AS lesson ON lesson.id = cm.instance AND m.name = 'lesson'<br />
LEFT JOIN prefix_page AS p ON p.id = cm.instance AND m.name = 'page'<br />
LEFT JOIN prefix_questionnaire AS questionnaire ON questionnaire.id = cm.instance AND m.name = 'questionnaire'<br />
LEFT JOIN prefix_quiz AS quiz ON quiz.id = cm.instance AND m.name = 'quiz'<br />
LEFT JOIN prefix_resource AS cr ON cr.id = cm.instance AND m.name = 'resource'<br />
LEFT JOIN prefix_scorm AS scorm ON scorm.id = cm.instance AND m.name = 'scorm'<br />
LEFT JOIN prefix_survey AS survey ON survey.id = cm.instance AND m.name = 'survey'<br />
LEFT JOIN prefix_url AS url ON url.id = cm.instance AND m.name = 'url'<br />
LEFT JOIN prefix_wiki AS wiki ON wiki.id = cm.instance AND m.name = 'wiki'<br />
LEFT JOIN prefix_workshop AS workshop ON workshop.id = cm.instance AND m.name = 'workshop'<br />
LEFT JOIN prefix_kalvidassign AS kalvidassign ON kalvidassign.id = cm.instance AND m.name = 'kalvidassign'<br />
LEFT JOIN prefix_kalvidres AS kvr ON kvr.id = cm.instance AND m.name = 'kalvidres'<br />
LEFT JOIN prefix_attendance AS attendance ON attendance.id = cm.instance AND m.name = 'attendance'<br />
LEFT JOIN prefix_checklist AS checklist ON checklist.id = cm.instance AND m.name = 'checklist'<br />
LEFT JOIN prefix_flashcard AS flashcard ON flashcard.id = cm.instance AND m.name = 'flashcard'<br />
LEFT JOIN prefix_lti AS lti ON lti.id = cm.instance AND m.name = 'lti'<br />
LEFT JOIN prefix_oublog AS oublog ON oublog.id = cm.instance AND m.name = 'oublog'<br />
LEFT JOIN prefix_ouwiki AS ouwiki ON ouwiki.id = cm.instance AND m.name = 'ouwiki'<br />
LEFT JOIN prefix_subpage AS subpage ON subpage.id = cm.instance AND m.name = 'subpage'<br />
LEFT JOIN prefix_journal AS journal ON journal.id = cm.instance AND m.name = 'journal'<br />
LEFT JOIN prefix_lightboxgallery AS lightboxgallery ON lightboxgallery.id = cm.instance AND m.name = 'lightboxgallery'<br />
LEFT JOIN prefix_elluminate AS elluminate ON elluminate.id = cm.instance AND m.name = 'elluminate'<br />
LEFT JOIN prefix_adaptivequiz AS adaptivequiz ON adaptivequiz.id = cm.instance AND m.name = 'adaptivequiz'<br />
LEFT JOIN prefix_hotpot AS hotpot ON hotpot.id = cm.instance AND m.name = 'hotpot'<br />
LEFT JOIN prefix_wiziq AS wiziq ON wiziq.id = cm.instance AND m.name = 'wiziq'<br />
LEFT JOIN prefix_turnitintooltwo AS turnitintooltwo ON turnitintooltwo.id = cm.instance AND m.name = 'turnitintooltwo'<br />
<br />
LEFT JOIN prefix_logstore_standard_log AS l ON l.userid = u.id AND l.courseid = c.id<br />
<br />
<br />
WHERE ra.roleid =5<br />
AND ctx.instanceid = c.id<br />
AND cs.visible = 1<br />
AND cm.visible = 1<br />
<br />
AND c.id = %%COURSEID%%<br />
<br />
GROUP BY cm.id<br />
<br />
ORDER BY cs.section<br />
</code><br />
<br />
===Module activity (Hits) between dates===<br />
<code sql><br />
SELECT module, COUNT( * ) <br />
FROM prefix_logstore_standard_log AS l<br />
WHERE (FROM_UNIXTIME( l.`timecreated` ) BETWEEN '2018-10-01 00:00:00' AND '2019-09-31 00:00:00')<br />
GROUP BY module<br />
</code><br />
<br />
===Module activity (Instances and Hits) for each academic year===<br />
<code sql><br />
SELECT name<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_logstore_standard_log AS l<br />
WHERE (FROM_UNIXTIME(l.`timecreated`) BETWEEN '2017-10-01 00:00:00' AND '2018-09-31 00:00:00')<br />
AND l.module = m.name AND l.action = 'add'<br />
) AS "Added 2017"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_logstore_standard_log AS l<br />
WHERE (FROM_UNIXTIME(l.`timecreated`) BETWEEN '2017-10-01 00:00:00' AND '2018-09-31 00:00:00')<br />
AND l.module = m.name<br />
) AS "Used 2017"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_logstore_standard_log AS l<br />
WHERE (FROM_UNIXTIME(l.`timecreated`) BETWEEN '2018-10-01 00:00:00' AND '2019-09-31 00:00:00')<br />
AND l.module = m.name AND l.action = 'add'<br />
) AS "Added 2018"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_logstore_standard_log AS l<br />
WHERE (FROM_UNIXTIME(l.`timecreated`) BETWEEN '2018-10-01 00:00:00' AND '2019-09-31 00:00:00')<br />
AND l.module = m.name<br />
) AS "Used 2018"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_logstore_standard_log AS l<br />
WHERE (FROM_UNIXTIME(l.`timecreated`) BETWEEN '2019-10-01 00:00:00' AND '2020-09-31 00:00:00')<br />
AND l.module = m.name AND l.action = 'add'<br />
) AS "Added 2019"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_logstore_standard_log AS l<br />
WHERE (FROM_UNIXTIME(l.`timecreated`) BETWEEN '2019-10-01 00:00:00' AND '2020-09-31 00:00:00')<br />
AND l.module = m.name<br />
) AS "Used 2019"<br />
<br />
FROM mdl_modules AS m<br />
</code><br />
<br />
===Unique user sessions per day and month + graph===<br />
The "graph" column is used when displaying a graph (which needs at least three columns to pick from)<br />
<code sql><br />
SELECT COUNT(DISTINCT userid) AS "Unique User Logins"<br />
,DATE_FORMAT(FROM_UNIXTIME(timecreated), "%y /%m / %d") AS "Year / Month / Day", "Graph" <br />
FROM `mdl_logstore_standard_log` <br />
WHERE action LIKE 'loggedin'<br />
#AND timecreated > UNIX_TIMESTAMP('2015-01-01 00:00:00') # optional start date<br />
#AND timecreated <= UNIX_TIMESTAMP('2015-01-31 23:59:00') # optional end date<br />
GROUP BY MONTH(FROM_UNIXTIME(timecreated)), DAY(FROM_UNIXTIME(timecreated))<br />
ORDER BY MONTH(FROM_UNIXTIME(timecreated)), DAY(FROM_UNIXTIME(timecreated))<br />
</code><br />
<br />
And...<br />
<br />
Counting user's global and unique hits per day + counting individual usage of specific activities and resources (on that day),<br />
<br />
And since I am using phpMyAdmin's "Display Graph" feature (at the bottom of the query's output page), I have scaled down the "User Hits" by 10 to fit the graph. that's it.<br />
<code sql><br />
SELECT DATE_FORMAT(FROM_UNIXTIME(timecreated), "%y-%m-%d") AS "Datez"<br />
,COUNT(DISTINCT userid) AS "Unique Users"<br />
,ROUND(COUNT(*)/10) "User Hits (K)"<br />
,SUM(IF(component='mod_quiz',1,0)) "Quizzes"<br />
,SUM(IF(component='mod_forum' or component='mod_forumng',1,0)) "Forums"<br />
,SUM(IF(component='mod_assign',1,0)) "Assignments"<br />
,SUM(IF(component='mod_oublog',1,0)) "Blogs"<br />
,SUM(IF(component='mod_resource',1,0)) "Files (Resource)"<br />
,SUM(IF(component='mod_url',1,0)) "Links (Resource)"<br />
,SUM(IF(component='mod_page',1,0)) "Pages (Resource)"<br />
<br />
FROM `mdl_logstore_standard_log` <br />
WHERE 1=1<br />
AND timecreated > UNIX_TIMESTAMP('2015-03-01 00:00:00') # optional START DATE<br />
AND timecreated <= UNIX_TIMESTAMP('2015-05-31 23:59:00') # optional END DATE<br />
GROUP BY MONTH(FROM_UNIXTIME(timecreated)), DAY(FROM_UNIXTIME(timecreated))<br />
ORDER BY MONTH(FROM_UNIXTIME(timecreated)), DAY(FROM_UNIXTIME(timecreated))<br />
</code><br />
<br />
===System wide, daily unique user hits for the last 7 days===<br />
<code sql><br />
SELECT<br />
DATE_FORMAT(FROM_UNIXTIME(l.timecreated), '%m%d') 'Day'<br />
,COUNT(DISTINCT l.userid) AS 'Distinct Users Hits'<br />
,COUNT( l.userid) AS 'Users Hits'<br />
<br />
FROM prefix_logstore_standard_log AS l<br />
WHERE l.courseid > 1<br />
AND FROM_UNIXTIME(l.timecreated) >= DATE_SUB(NOW(), INTERVAL 7 DAY)<br />
GROUP BY DAY(FROM_UNIXTIME(timecreated))<br />
</code><br />
<br />
===User detailed activity in course modules===<br />
Considering only several modules: url, resource, forum, quiz, questionnaire.<br />
<br />
<code sql><br />
SELECT u.id, ra.roleid,<br />
CONCAT(u.lastname, ' ', u.firstname) AS 'Student'<br />
,COUNT(l.id) AS 'Actions'<br />
,l.component "Module type"<br />
,l.objectid "Module ID"<br />
,CASE <br />
WHEN l.component = 'mod_url' THEN (SELECT u.name FROM prefix_url AS u WHERE u.id = l.objectid )<br />
WHEN l.component = 'mod_resource' THEN (SELECT r.name FROM prefix_resource AS r WHERE r.id = l.objectid )<br />
WHEN l.component = 'mod_forum' THEN (SELECT f.name FROM prefix_forum AS f WHERE f.id = l.objectid )<br />
WHEN l.component = 'mod_quiz' THEN (SELECT q.name FROM prefix_quiz AS q WHERE q.id = l.objectid )<br />
WHEN l.component = 'mod_questionnaire' THEN (SELECT q.name FROM prefix_questionnaire AS q WHERE q.id = l.objectid )<br />
END AS 'Module name'<br />
<br />
,(SELECT GROUP_CONCAT(g.name) FROM prefix_groups AS g<br />
JOIN prefix_groups_members AS m ON g.id = m.groupid WHERE g.courseid = l.courseid AND m.userid = u.id) "user_groups"<br />
<br />
,(SELECT s.name <br />
FROM prefix_course_modules AS cm <br />
JOIN prefix_course_sections AS s ON s.course = cm.course AND s.id = cm.section <br />
WHERE cm.id = l.contextinstanceid) AS "Section name"<br />
<br />
FROM prefix_logstore_standard_log AS l <br />
JOIN prefix_user AS u ON u.id = l.userid<br />
JOIN prefix_role_assignments AS ra ON ra.userid = l.userid <br />
AND ra.contextid = (SELECT id FROM prefix_context WHERE instanceid = l.courseid AND contextlevel = 50) <br />
WHERE l.courseid = %%COURSEID%%<br />
AND l.component IN ('mod_url', 'mod_resource', 'mod_forum', 'mod_quiz', 'mod_questionnaire') <br />
%%FILTER_STARTTIME:l.timecreated:>%% %%FILTER_ENDTIME:l.timecreated:<%%<br />
<br />
GROUP BY u.id, l.component<br />
ORDER BY u.lastname, u.firstname<br />
</code><br />
<br />
===What teachers and courses considered active?===<br />
This report display several calculations and parameters that help the Online academic training team find teachers that might need more support getting their courses more supporting of online learning pedagogical methodologies. <br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',<br />
course.id,'">',course.fullname,'</a>') AS Course <br />
<br />
#,course.shortname<br />
<br />
,CASE <br />
WHEN course.fullname LIKE '%2012%' THEN '2012'<br />
WHEN course.fullname LIKE '%2013%' THEN '2013' <br />
WHEN course.fullname LIKE '%2014%' THEN '2014'<br />
WHEN course.fullname LIKE '%2015%' THEN '2015'<br />
END AS Year<br />
<br />
,CASE <br />
WHEN course.fullname LIKE '%semester a%' THEN 'Spring semester'<br />
WHEN course.fullname LIKE '%semester b%' THEN 'Fall semester'<br />
WHEN course.fullname LIKE '%semester s%' THEN 'Summer semester'<br />
END AS Semester<br />
<br />
,IF(course.startdate>0, DATE_FORMAT(FROM_UNIXTIME(startdate), '%d-%m-%Y'), 'no date') AS "Course Start Date" <br />
<br />
,(SELECT COUNT( ra.userid ) AS Users<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = course.id<br />
) AS Students<br />
<br />
,(SELECT COUNT( ra.userid ) AS Users<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 4 AND ctx.instanceid = course.id<br />
) AS "Assistant teacher"<br />
<br />
,(SELECT COUNT( ra.userid ) AS Users<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 3 AND ctx.instanceid = course.id<br />
) AS Teachers<br />
<br />
# Uncomment to use the new Moodle 2.8+ logstore<br />
#,(SELECT COUNT(*) FROM mdl_logstore_standard_log AS l WHERE l.courseid = course.id) AS Hits<br />
<br />
#,(SELECT COUNT(*)<br />
#FROM mdl_logstore_standard_log AS l<br />
#JOIN mdl_role_assignments AS ra ON ra.userid= l.userid AND ra.roleid = 5 AND ra.contextid = (SELECT id FROM mdl_context WHERE instanceid = l.courseid AND contextlevel = 50) <br />
#WHERE l.courseid = course.id ) AS "Student HITs"<br />
<br />
#,(SELECT COUNT(*)<br />
#FROM mdl_logstore_standard_log AS l<br />
#JOIN mdl_role_assignments AS ra ON ra.userid= l.userid AND ra.roleid = 3 AND ra.contextid = (SELECT id FROM mdl_context WHERE instanceid = l.courseid AND contextlevel = 50) <br />
#WHERE l.courseid = course.id ) AS "Teacher HITs"<br />
<br />
,(SELECT COUNT(*) FROM mdl_log AS l WHERE l.course = course.id) AS Hits<br />
<br />
,(SELECT COUNT(*)<br />
FROM mdl_log AS l<br />
JOIN mdl_context AS con ON con.instanceid= l.course AND con.contextlevel=50<br />
JOIN mdl_role_assignments AS ra ON ra.contextid= con.id AND ra.userid= l.userid AND ra.roleid = 5 <br />
WHERE l.course = course.id) AS "Students HITs"<br />
<br />
,(SELECT COUNT(*)<br />
FROM mdl_log AS l<br />
JOIN mdl_context AS con ON con.instanceid= l.course AND con.contextlevel=50<br />
JOIN mdl_role_assignments AS ra ON ra.contextid= con.id AND ra.userid= l.userid AND ra.roleid = 3 <br />
WHERE l.course = course.id) AS "Teachers HITs"<br />
<br />
,(SELECT GROUP_CONCAT( CONCAT( u.firstname, " ", u.lastname ) ) <br />
FROM prefix_course c<br />
JOIN prefix_context con ON con.instanceid = c.id<br />
JOIN prefix_role_assignments ra ON con.id = ra.contextid AND con.contextlevel = 50<br />
JOIN prefix_role r ON ra.roleid = r.id<br />
JOIN prefix_user u ON u.id = ra.userid<br />
WHERE r.id = 3 AND c.id = course.id<br />
GROUP BY c.id<br />
) AS Teachers<br />
<br />
,(SELECT COUNT(*) FROM prefix_course_modules cm WHERE cm.course = course.id) Modules<br />
<br />
,(SELECT COUNT(DISTINCT cm.module) FROM prefix_course_modules cm <br />
WHERE cm.course = course.id) UniqueModules<br />
<br />
,(SELECT GROUP_CONCAT(DISTINCT m.name) <br />
FROM prefix_course_modules cm <br />
JOIN mdl_modules as m ON m.id = cm.module<br />
WHERE cm.course = course.id) UniqueModuleNames<br />
<br />
,(SELECT COUNT(*) FROM mdl_course_modules cm JOIN mdl_modules as m ON m.id = cm.module <br />
WHERE cm.course = course.id AND m.name IN ( 'ouwiki', 'wiki') ) "Num Wikis"<br />
<br />
,(SELECT COUNT(*) FROM mdl_course_modules cm JOIN mdl_modules as m ON m.id = cm.module <br />
WHERE cm.course = course.id AND m.name IN ( 'oublog') ) "Num Blogs"<br />
<br />
,(SELECT COUNT(*) FROM mdl_course_modules cm JOIN mdl_modules as m ON m.id = cm.module <br />
WHERE cm.course = course.id AND m.name IN ( 'forum', 'forumng') ) "Num Forums"<br />
<br />
,(SELECT COUNT(*) FROM prefix_course_modules cm JOIN mdl_modules as m ON m.id = cm.module <br />
WHERE cm.course = course.id AND m.name IN ('resource', 'folder', 'url', 'tab', 'file', 'book', 'page') ) Resources<br />
<br />
,(SELECT COUNT(*) FROM prefix_course_modules cm JOIN mdl_modules as m ON m.id = cm.module <br />
WHERE cm.course = course.id AND m.name IN ('forum', 'forumng', 'oublog', 'page', 'file', 'url', 'wiki' , 'ouwiki') ) "Basic Activities"<br />
<br />
,(SELECT COUNT(*) FROM prefix_course_modules cm JOIN mdl_modules as m ON m.id = cm.module <br />
WHERE cm.course = course.id AND m.name IN ('advmindmap', 'assign', 'attendance', 'book', 'choice', 'folder', 'tab', 'glossary', 'questionnaire', 'quiz', 'label' ) ) "Avarage Activities"<br />
<br />
,(SELECT COUNT(*) FROM prefix_course_modules cm JOIN mdl_modules as m ON m.id = cm.module <br />
WHERE cm.course = course.id AND m.name IN ('elluminate', 'game', 'workshop') ) "Advanced Activities"<br />
<br />
FROM prefix_course AS course<br />
<br />
#WHERE course.shortname LIKE '%2015%'<br />
#WHERE 1=1<br />
#%%FILTER_SEARCHTEXT:course.shortname:~%%<br />
<br />
WHERE course.fullname LIKE '%2015%' <br />
<br />
HAVING Modules > 2<br />
ORDER BY UniqueModules DESC<br />
</code><br />
<br />
===Weekly attendance report===<br />
This report display weekly report in format HH:M:SS This MySQL query works together with AttendaceRegister module, and gather Log information from Attendanceregister_log table. <br />
<code sql><br />
SELECT u.username, SEC_TO_TIME (SUM(arsess.duration)) AS weekly_online_attendance, FROM_UNIXTIME (arsess.logout) AS Last_Logout<br />
FROM prefix_attendanceregister_session AS arsess<br />
JOIN prefix_user AS u ON arsess.userid = u.id<br />
<br />
WHERE (((arsess.logout) BETWEEN UNIX_TIMESTAMP(DATE_SUB(CURDATE(), INTERVAL 7 DAY)) AND UNIX_TIMESTAMP(CURDATE())))<br />
<br />
GROUP BY arsess.userid<br />
</code><br />
<br />
===How many distinct users connected to Moodle using the app by month===<br />
https://moodle.org/mod/forum/discuss.php?d=336086#p1354194 by <br />
Iñigo Zendegi Urzelai<br />
<code sql><br />
SELECT <br />
to_char(to_timestamp("timecreated"),'YYYY') as year, <br />
to_char(to_timestamp("timecreated"),'MM') as month, <br />
count(distinct userid) as distinct_users<br />
<br />
FROM mdl_logstore_standard_log m<br />
WHERE m.origin='ws'<br />
GROUP BY to_char(to_timestamp("timecreated"),'YYYY'), to_char(to_timestamp("timecreated"),'MM') <br />
ORDER BY to_char(to_timestamp("timecreated"),'YYYY'), to_char(to_timestamp("timecreated"),'MM');<br />
</code><br />
<br />
==Course Reports==<br />
===Most Active courses===<br />
<code sql><br />
SELECT count(l.userid) AS Views<br />
FROM `mdl_logstore_standard_log` l, `mdl_user` u, `mdl_role_assignments` r<br />
WHERE l.courseid=35<br />
AND l.userid = u.id<br />
AND (l.timecreated > UNIX_TIMESTAMP('2015-01-01 00:00:00') AND l.timecreated <= UNIX_TIMESTAMP('2015-01-31 23:59:59'))AND r.contextid= (<br />
SELECT id<br />
FROM mdl_context<br />
WHERE contextlevel=50 AND instanceid=l.courseid<br />
)<br />
AND r.roleid=5<br />
AND r.userid = u.id<br />
</code><br />
<br />
===Active courses, advanced===<br />
Including: Teacher's name, link to the course, All types of log activities, special YEAR generated field, Activities and Resource count, enrolled Student count<br />
<code sql><br />
SELECT COUNT(l.id) hits, concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS Course <br />
<br />
,(SELECT CONCAT(u.firstname,' ', u.lastname) AS Teacher<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS Teacher<br />
<br />
,CASE <br />
WHEN c.fullname LIKE '%תשע' THEN 'תשע'<br />
WHEN c.fullname LIKE '%תשעא' THEN 'תשעא'<br />
WHEN c.fullname LIKE '%תשעב' THEN 'תשעב'<br />
END AS Year<br />
<br />
,(SELECT count(*) FROM prefix_course_modules cm WHERE cm.course = l.course) Modules<br />
<br />
,(SELECT Count( ra.userid ) AS Users FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = c.id) AS Students<br />
<br />
FROM prefix_log l <br />
INNER JOIN prefix_course c ON l.course = c.id<br />
GROUP BY c.id<br />
#The following line restricts the courses returned to those having more than 2 modules. Adjust based on your needs.<br />
HAVING Modules > 2<br />
ORDER BY Year DESC, hits DESC<br />
</code><br />
<br />
=== Least active or probably empty courses===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
It is difficult to know sometimes when a course is actually empty or was never really in use. Other than the simple case where the course was created and never touched again, in which case the course timecreated and timemodified will be the same, many courses created as shells for teachers or other users may be used once or a few times and have few or no test users enrollments in them. This query helps you see the range of such courses, showing you how many days if any it was used after initial creation, and how many user are enrolled. It denotes a course never ever modified by "-1" instead of "0" so you can sort those to the top. By default it limits this to courses used within 60 days of creation, and to courses with 3 or less enrollments (for example, teacher and assistant and test student account only.) You can easily adjust these numbers. The query includes a link to the course as well. <br />
<br />
<code sql><br />
SELECT<br />
c.fullname,<br />
CONCAT('<a target="_blank" href="%%WWWROOT%%/course/view.php',CHAR(63),'id=',c.id,'">',c.shortname,'</a>') AS 'CourseLink',<br />
DATE_FORMAT(FROM_UNIXTIME(c.timecreated), '%Y-%m-%d %H:%i') AS 'Timecreated',<br />
DATE_FORMAT(FROM_UNIXTIME(c.timemodified), '%Y-%m-%d %H:%i') AS 'Timemodified',<br />
CASE<br />
WHEN c.timecreated = c.timemodified THEN '-1'<br />
ELSE DATEDIFF(FROM_UNIXTIME(c.timemodified),FROM_UNIXTIME(c.timecreated))<br />
END AS 'DateDifference',<br />
COUNT(ue.id) AS Enroled<br />
FROM prefix_course AS c<br />
JOIN prefix_enrol AS en ON en.courseid = c.id<br />
LEFT JOIN prefix_user_enrolments AS ue ON ue.enrolid = en.id<br />
WHERE DATEDIFF(FROM_UNIXTIME(c.timemodified),FROM_UNIXTIME(c.timecreated) ) < 60<br />
GROUP BY c.id<br />
HAVING COUNT(ue.id) <= 3<br />
ORDER BY c.fullname<br />
</code><br />
<br />
===Count unique teachers with courses that use at least X module (Moodle19)===<br />
You can remove the outer "SELECT COUNT(*) FROM (...) AS ActiveTeachers" SQL query and get the list of the Teachers and Courses.<br />
<code sql><br />
SELECT COUNT(*)<br />
FROM (SELECT c.id AS CourseID, c.fullname AS Course, ra.roleid AS RoleID, CONCAT(u.firstname, ' ', u.lastname) AS Teacher<br />
,(SELECT COUNT(*) FROM prefix_course_modules cm WHERE cm.course = c.id) AS Modules<br />
FROM prefix_course AS c<br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid AND ctx.contextlevel = 50 <br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE ra.roleid = 3 <br />
GROUP BY u.id<br />
HAVING Modules > 5) AS ActiveTeachers<br />
</code><br />
<br />
===RESOURCE count for each COURSE===<br />
<code sql><br />
SELECT COUNT(l.id) count, l.course, c.fullname coursename<br />
FROM prefix_resource l INNER JOIN prefix_course c on l.course = c.id<br />
GROUP BY course<br />
ORDER BY count DESC<br />
</code><br />
<br />
===Common resource types count for each Category (Moodle19)===<br />
Including sub-categories in total count.<br />
<code sql><br />
SELECT mcc.id AS mccid, CONCAT( LPAD( '', mcc.depth, '.' ) , mcc.name ) AS Category<br />
,(SELECT COUNT( * ) <br />
FROM prefix_resource AS r<br />
JOIN prefix_course AS c ON c.id = r.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%', mccid, '%' ) AND r.TYPE = 'file' AND r.reference LIKE 'http://%'<br />
) AS Links<br />
<br />
,(SELECT COUNT( * ) <br />
FROM prefix_resource AS r<br />
JOIN prefix_course AS c ON c.id = r.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%', mccid, '%' ) AND r.TYPE = 'file' AND r.reference NOT LIKE 'http://%'<br />
) AS Files<br />
<br />
,(SELECT COUNT( * ) <br />
FROM prefix_resource AS r<br />
JOIN prefix_course AS c ON c.id = r.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%', mccid, '%' ) AND r.TYPE = 'directory' <br />
) AS Folders<br />
<br />
,(SELECT COUNT( * ) <br />
FROM prefix_resource AS r<br />
JOIN prefix_course AS c ON c.id = r.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%', mccid, '%' ) AND r.TYPE = 'html' <br />
) AS Pages<br />
<br />
,(SELECT COUNT(*) <br />
FROM stats_log_context_role_course <br />
WHERE roleid = 5 AND module = 'resource' AND category = mcc.id<br />
) AS Hits<br />
<br />
FROM prefix_course_categories AS mcc<br />
ORDER BY mcc.path<br />
</code><br />
Where "stats_log_context_role_course" (in the above SQL query) is a VIEW generated by:<br />
<code sql><br />
CREATE VIEW stats_log_context_role_course AS<br />
SELECT l.course, c.category, cc.path, l.module, l.action, ra.userid, ra.roleid<br />
FROM prefix_log AS l<br />
JOIN prefix_context AS context ON context.instanceid = l.course AND context.contextlevel = 50<br />
JOIN prefix_role_assignments AS ra ON ra.userid = l.userid AND ra.contextid = context.id<br />
JOIN prefix_course AS c ON c.id = l.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
</code><br />
<br />
Same query but for Moodle2+<br />
<code sql><br />
SELECT mcc.id AS mccid, CONCAT( LPAD( '', mcc.depth, '.' ) , mcc.name ) AS Category,<br />
mcc.path,<br />
<br />
(SELECT COUNT(*) <br />
FROM prefix_url AS u<br />
JOIN prefix_course AS c ON c.id = u.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%/', mccid, '%' )<br />
) AS URLs,<br />
<br />
(SELECT COUNT(*) <br />
FROM prefix_folder AS f<br />
JOIN prefix_course AS c ON c.id = f.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%/', mccid, '%' )<br />
) AS FOLDERs,<br />
<br />
(SELECT COUNT(*) <br />
FROM prefix_page AS p<br />
JOIN prefix_course AS c ON c.id = p.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%/', mccid, '%' )<br />
) AS PAGEs,<br />
<br />
(SELECT COUNT(*) <br />
FROM prefix_book AS b<br />
JOIN prefix_course AS c ON c.id = b.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%/', mccid, '%' )<br />
) AS BOOKs,<br />
<br />
(SELECT COUNT(*) <br />
FROM prefix_label AS l<br />
JOIN prefix_course AS c ON c.id = l.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%/', mccid, '%' )<br />
) AS LABELs,<br />
<br />
(SELECT COUNT(*) <br />
FROM prefix_tab AS t<br />
JOIN prefix_course AS c ON c.id = t.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%/', mccid, '%' )<br />
) AS TABs<br />
<br />
FROM prefix_course_categories AS mcc<br />
ORDER BY mcc.path<br />
</code><br />
<br />
===Detailed Resource COUNT by Teacher in each course===<br />
<br />
Including (optional) filter by: year, semester and course id.<br />
<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS CourseID<br />
, c.id<br />
,( SELECT DISTINCT CONCAT(u.firstname,' ',u.lastname)<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_user AS u ON ra.userid = u.id<br />
JOIN prefix_context AS ctx ON ctx.id = ra.contextid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id AND ctx.contextlevel = 50 LIMIT 1) AS Teacher<br />
<br />
, (CASE <br />
WHEN c.fullname LIKE '%תשעב%' THEN '2012' <br />
WHEN c.fullname LIKE '%תשעא%' THEN '2011'<br />
END ) as Year<br />
, (CASE <br />
WHEN c.fullname LIKE '%סמסטר א%' THEN 'Semester A' <br />
WHEN c.fullname LIKE '%סמסטר ב%' THEN 'Semester B'<br />
WHEN c.fullname LIKE '%סמסטר ק%' THEN 'Semester C'<br />
END ) as Semester<br />
,COUNT(c.id) AS Total<br />
,(SELECT count(*) FROM prefix_course_modules AS cm WHERE cm.course = c.id AND cm.module= 20) AS TABs<br />
,(SELECT count(*) FROM prefix_course_modules AS cm WHERE cm.course = c.id AND cm.module= 33) AS BOOKs<br />
<br />
FROM `prefix_resource` as r <br />
JOIN `prefix_course` AS c on c.id = r.course<br />
#WHERE type= 'file' and reference NOT LIKE 'http://%' <br />
<br />
#WHERE 1=1<br />
#%%FILTER_YEARS:c.fullname%%<br />
#AND c.fullname LIKE '%2013%'<br />
<br />
GROUP BY course<br />
ORDER BY COUNT(c.id) DESC<br />
</code><br />
<br />
===Courses that are defined as using GROUPs===<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/group/index.php?id=',c.id,'">',c.fullname,'</a>') AS Course<br />
,(SELECT count(*) FROM prefix_course_modules cm WHERE cm.course = c.id) Modules<br />
,(SELECT count(*) FROM prefix_groups g WHERE g.courseid = c.id) Groups<br />
FROM `prefix_course` AS c<br />
WHERE groupmode > 0<br />
</code><br />
<br />
===Courses with Groups===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
List of all courses with Groups in them (groupmode > 0). You can also use groupmode=1 to list just Separate type groups or groupmode=2 to list Visible type groups.<br />
<br />
<code sql><br />
SELECT c.shortname, g.name, c.groupmode<br />
FROM prefix_course AS c<br />
JOIN prefix_groups AS g ON c.id = g.courseid<br />
WHERE c.groupmode > 0<br />
</code><br />
<br />
===Users enrolled in a course with groups but not assigned a group ===<br />
<br />
Displays by course all enrolled users that have not been assigned a group in courses that have groups. NOTE: This needs to be optimized.<br />
<br />
<code sql><br />
SELECT DISTINCT<br />
user2.firstname AS Firstname,<br />
user2.lastname AS Lastname,<br />
user2.email AS Email,<br />
user2.city AS City,<br />
course.fullname AS Course<br />
,(SELECT shortname FROM prefix_role WHERE id=en.roleid) AS ROLE<br />
,(SELECT name FROM prefix_role WHERE id=en.roleid) AS RoleName<br />
<br />
FROM prefix_course AS course <br />
JOIN prefix_enrol AS en ON en.courseid = course.id<br />
JOIN prefix_user_enrolments AS ue ON ue.enrolid = en.id<br />
JOIN prefix_user AS user2 ON ue.userid = user2.id<br />
JOIN prefix_groups AS g ON g.courseid = course.id<br />
<br />
WHERE ue.enrolid NOT IN (select userid from prefix_groups_members WHERE g.id=groupid)<br />
<br />
ORDER BY Course, Lastname<br />
</code><br />
<br />
===Groups in course with member list===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
List the groups in a course (replace the # by the course id number) with the members of each group.<br />
<br />
<code sql><br />
SELECT c.shortname, g.name AS Groupname, u.username<br />
FROM prefix_course AS c<br />
JOIN prefix_groups AS g ON g.courseid = c.id<br />
JOIN prefix_groups_members AS m ON g.id = m.groupid<br />
JOIN prefix_user AS u ON m.userid = u.id<br />
WHERE c.id = #<br />
</code><br />
<br />
Note: if you are using Configurable Reports block and want to perform this query on the current course you are in, then you can use a WHERE clause like this:<br />
<code sql><br />
WHERE c.id = %%COURSEID%%<br />
</code><br />
<br />
===Group Export===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
There's a [[Import_groups|group import]] function, but no export. Use this to give you a report with the proper column order and headings to export to a csv file you can then import into another course to replicate the groups. This is a simple version with just the main fields: groupname, description, enrolment key.<br />
<br />
<code sql><br />
SELECT g.name AS groupname, g.description, g.enrolmentkey<br />
FROM prefix_groups AS g <br />
JOIN prefix_course as c ON g.courseid = c.id<br />
WHERE c.id = #<br />
</code><br />
Note: if you are using Configurable Reports block and want to perform this query on the current course you are in, then you can use a WHERE clause like this:<br />
<code sql><br />
WHERE c.id = %%COURSEID%%<br />
</code><br />
<br />
===List all Courses in and below a certain category===<br />
Use this SQL code to retrieve all courses that exist in or under a set category.<br />
<br />
$s should be the id of the category you want to know about...<br />
<code sql><br />
SELECT prefix_course. * , prefix_course_categories. *<br />
FROM prefix_course, prefix_course_categories<br />
WHERE prefix_course.category = prefix_course_categories.id<br />
AND (<br />
prefix_course_categories.path LIKE '%/$s/%'<br />
OR prefix_course_categories.path LIKE '%/$s'<br />
)<br />
</code><br />
<br />
===List all Categories in one level below a certain category===<br />
Use this PHP code to retrieve a list of all categories below a certain category.<br />
<br />
$s should be the id of the top level category you are interested in.<br />
<code php><br />
<?php<br />
<br />
require_once('./config.php');<br />
<br />
$parent_id = $s;<br />
<br />
$categories= array();<br />
<br />
$categories = get_categories($parent_id);<br />
<br />
echo '<ol>';<br />
foreach ($categories as $category)<br />
{<br />
echo '<li><a href="'.$CFG->wwwroot.'/course/category.php?id='.$category->id.'">'.$category->name.'</a></li>';<br />
}<br />
echo '</ol>';<br />
<br />
?><br />
</code><br />
<br />
===Blog activity per Course (not including VIEW)===<br />
Filter activity logging to some specific Course Categories!<br />
+ link course name to actual course (for quick reference)<br />
(you can change %blog% to %wiki% to filter down all wiki activity or any other module you wish)<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',cm.course,'">',c.fullname,'</a>') as CourseID<br />
,m.name ,count(cm.id) as counter <br />
,(SELECT Count( ra.userid ) AS Users<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5<br />
AND ctx.instanceid = c.id<br />
) AS Students<br />
, ( SELECT count(id) FROM prefix_log WHERE `module` LIKE '%blog%' AND course = c.id AND action NOT LIKE '%view%' ) as BlogActivity<br />
FROM `prefix_course_modules` as cm JOIN prefix_modules as m ON cm.module=m.id JOIN prefix_course as c ON cm.course = c.id <br />
WHERE m.name LIKE '%blog%' AND c.category IN ( 8,13,15)<br />
GROUP BY cm.course,cm.module order by counter desc<br />
</code><br />
<br />
===Student's posts content in all course blogs (oublog)===<br />
<code sql><br />
SELECT <br />
b.name <br />
,op.title<br />
,op.message<br />
,( SELECT CONCAT(u.firstname, ' ',u.lastname) FROM prefix_user AS u WHERE u.id = oi.userid) AS "Username"<br />
<br />
FROM prefix_oublog_posts AS op<br />
JOIN prefix_oublog_instances AS oi ON oi.id = op.oubloginstancesid <br />
JOIN prefix_oublog as b ON b.id = oi.oublogid<br />
JOIN prefix_course AS c ON b.course = c.id<br />
<br />
WHERE c.id = %%COURSEID%%<br />
</code><br />
<br />
===All Courses which uploaded a Syllabus file===<br />
+ under specific Category<br />
+ show first Teacher in that course<br />
+ link Course's fullname to actual course<br />
<code sql><br />
SELECT<br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') as Course<br />
,c.shortname,r.name<br />
,(SELECT CONCAT(u.firstname,' ', u.lastname) as Teacher<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user as u ON u.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) as Teacher<br />
FROM prefix_resource as r <br />
JOIN prefix_course as c ON r.course = c.id<br />
WHERE ( r.name LIKE '%סילבוס%' OR r.name LIKE '%סילאבוס%' OR r.name LIKE '%syllabus%' OR r.name LIKE '%תכנית הקורס%' ) <br />
AND c.category IN (10,18,26,13,28)<br />
</code><br />
<br />
===Site-wide completed SCORM activities by Course name===<br />
This report will list all completed attempts for all SCORM activities. It is ordered first by Course name, then student's last name, then student's first name, then attempt number. Please note: the FROM_UNIXTIME command is for MySQL.<br />
<code sql><br />
SELECT u.firstname First,u.lastname Last,c.fullname Course, st.attempt Attempt,st.value Status,FROM_UNIXTIME(st.timemodified,"%m-%d-%Y") Date <br />
FROM prefix_scorm_scoes_track AS st <br />
JOIN prefix_user AS u ON st.userid=u.id<br />
JOIN prefix_scorm AS sc ON sc.id=st.scormid<br />
JOIN prefix_course AS c ON c.id=sc.course<br />
WHERE st.value='completed' <br />
ORDER BY c.fullname, u.lastname,u.firstname, st.attempt<br />
</code><br />
===All users enrolled in a course without a role===<br />
Identifies All users that are enrolled in a course but are not assigned a role.<br />
<code sql><br />
SELECT<br />
user.firstname AS Firstname,<br />
user.lastname AS Lastname,<br />
user.idnumber Employee_ID,<br />
course.fullname AS Course<br />
<br />
FROM prefix_course AS course <br />
JOIN prefix_enrol AS en ON en.courseid = course.id<br />
JOIN prefix_user_enrolments AS ue ON ue.enrolid = en.id<br />
JOIN prefix_user as user ON user.id = ue.userid<br />
<br />
WHERE user.id NOT IN (<br />
SELECT u.id<br />
FROM prefix_course AS c<br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid<br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN prefix_role AS r ON r.id = ra.roleid<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE c.id=course.id<br />
)<br />
ORDER BY Course, Lastname, Firstname<br />
<br />
</code><br />
<br />
===List course resources accumulative file size and count===<br />
This is the main (first) report, which has a link (alias) to a second report (the following on this page) which list each file in the course.<br />
<code sql><br />
SELECT c.id "CourseID", context.id "ContextID"<br />
,CONCAT('<a target="_new" href="%%WWWROOT%%/course/view.php?id=', c.id, '">', c.fullname ,'</a>') AS "Course Name"<br />
, COUNT(*) "Course Files" , ROUND( SUM( f.filesize ) /1048576 ) AS file_size_MB<br />
,CONCAT('<a target="_new" href="%%WWWROOT%%/blocks/configurable_reports/viewreport.php?alias=coursefiles&courseid=1&filter_courses=', c.id, '">List files</a>') AS "List Files"<br />
<br />
FROM mdl_files AS f<br />
JOIN mdl_context AS context ON context.id = f.contextid<br />
JOIN mdl_course AS c ON c.id = (<br />
SELECT instanceid<br />
FROM mdl_context<br />
WHERE id = SUBSTRING_INDEX( SUBSTRING_INDEX( context.path, '/' , -2 ) , '/', 1 ) )<br />
WHERE filesize >0<br />
GROUP BY c.id<br />
</code><br />
<br />
With this report, you will have to define "alias" report property to "coursefiles" for it to be able to be called from the above report.<br />
And also setup (add) a FILTER_COURSES filter. <br />
<code sql><br />
SELECT <br />
id ,CONCAT('<a target="_new" href="%%WWWROOT%%/pluginfile.php/', contextid, '/', component, '/', filearea, '/', itemid, '/', filename, '">', filename,'</a>') AS "File"<br />
,filesize, mimetype ,author, license, timecreated, component, filearea, filepath<br />
<br />
FROM mdl_files AS f<br />
WHERE filesize >0<br />
AND f.contextid<br />
IN ( SELECT id<br />
FROM mdl_context<br />
WHERE path <br />
LIKE ( SELECT CONCAT('%/',id,'/%')<br />
AS contextquery<br />
FROM mdl_context<br />
WHERE 1=1<br />
%%FILTER_COURSES:instanceid%%<br />
AND contextlevel = 50<br />
)<br />
)<br />
</code><br />
<br />
===Which courses has redundant topics===<br />
This report list several "active topics" calculations, per course. which should give an administrator some indications for which topics/sections/weeks are filled with resources and activities and which ones are empty and not used (usually, at the end of the course).<br />
<br />
The following, second SQL query, could be used to "trim" down those redundant course topics/sections/weeks by updating the course format's numsection (Number of sections) setting. (It's a per course format setting!)<br />
<br />
<code sql><br />
SELECT id, format,<br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">', c.fullname,'</a>') AS Course <br />
<br />
,(SELECT value FROM `mdl_course_format_options` WHERE `courseid` = c.id AND `format` = c.format AND `name` = 'numsections' ) AS "numsections"<br />
,(SELECT COUNT(*) FROM `mdl_course_sections` WHERE `course` = c.id AND `sequence` != '' ) AS "Non empty sections count"<br />
,(SELECT COUNT(*) FROM `mdl_course_sections` WHERE `course` = c.id ) AS "Total section count"<br />
,(SELECT COUNT(*) FROM `mdl_course_sections` WHERE `course` = c.id AND sequence IS NOT NULL) AS "Non NULL sections count"<br />
,(SELECT COUNT(*) FROM `mdl_course_sections` WHERE `course` = c.id AND name != '') AS "Non empty section Name count"<br />
,(SELECT COUNT(*) FROM mdl_course_modules cm WHERE cm.course = c.id) "Modules count"<br />
<br />
FROM mdl_course AS c<br />
</code><br />
<br />
The following SQL REPLACE query is used for "fixing" (updating) the "numsections" of a specific course format "onetopics" (you can always change it, or discard it to use this SQL REPLACE on all course formats) <br />
<code sql><br />
REPLACE INTO `mdl_course_format_options` (`id`, `courseid`, `format`, `sectionid`, `name`, `value`) <br />
SELECT NULL, c.id, 'onetopic', '0', 'numsections', (SELECT COUNT(*) FROM `mdl_course_sections` WHERE `course` = c.id AND name != '')<br />
FROM `mdl_course` c where format = 'onetopic'<br />
</code><br />
<br />
===Hidden Courses with Students Enrolled===<br />
Contributed by Eric Strom<br />
<br />
This query identifies courses with student enrollment that are currently hidden from students. Includes the defined course start date, count of students and instructors, and a clickable email link of instructor (first found record if more than one).<br />
<br />
<code sql><br />
SELECT c.visible AS Visible, <br />
DATE(FROM_UNIXTIME(c.startdate)) AS StartDate, <br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php',CHAR(63),'id=',<br />
c.id,'">',c.idnumber,'</a>') AS Course_ID,<br />
<br />
(SELECT COUNT( ra.userid ) FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = c.id) AS Students,<br />
<br />
(SELECT COUNT( ra.userid ) FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id) AS Instructors,<br />
<br />
(SELECT DISTINCT concat('<a href="mailto:',u.email,'">',u.email,'</a>')<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_user AS u ON ra.userid = u.id<br />
JOIN prefix_context AS ctx ON ctx.id = ra.contextid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id AND ctx.contextlevel = 50 LIMIT 1) AS 'Instructor_Email', <br />
<br />
now() AS Report_Timestamp<br />
<br />
FROM prefix_course AS c <br />
WHERE c.visible = 0 AND (SELECT COUNT( ra.userid ) FROM prefix_role_assignments AS ra JOIN prefix_context AS ctx ON ra.contextid = ctx.id WHERE ra.roleid = 5 AND ctx.instanceid = c.id) > 0<br />
ORDER BY StartDate, Instructor_Email, Course_ID<br />
</code><br />
<br />
<br />
==Course Design Reports==<br />
<br />
These are reports which summarize course design aspects, such as activity and resource modules per section, types of activities used, etc.<br />
<br />
===Course Content/Week===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
This report assumes that the first 14 sections in a course, not including the "0" or "Welcome" section, correspond to weeks (with "Subsections" given numbers much higher in the sequence). Of those sections, each is checked to count the number of:<br />
<br />
Forums<br />
Graded Activities (may include Forums)<br />
Resources (not including a Label)<br />
<br />
Totals of each of these types of content elements per section are provided.<br />
<br />
'''Note''': Only visible resources and activities are counted.<br />
'''Note''': this is a "Global" report. Run it within a course to see a summary of the contents of that course.<br />
<br />
<code sql><br />
SELECT<br />
<br />
cs.section AS 'Week'<br />
, cs.name AS 'Section Name'<br />
<br />
, COUNT(DISTINCT IF((gi.id IS NULL) AND (m.name NOT LIKE 'label'),cm.id,NULL)) AS 'Ungraded Resources'<br />
<br />
, COUNT(DISTINCT IF(m.name LIKE 'forum', cm.id, NULL)) AS 'Forums'<br />
<br />
, COUNT(DISTINCT IF(gi.id, cm.id, NULL)) AS 'Graded Activities'<br />
<br />
FROM prefix_course AS c<br />
JOIN prefix_course_sections AS cs ON cs.course = c.id AND cs.section <= 14 AND cs.section > 0<br />
LEFT JOIN prefix_course_modules AS cm ON cm.course = c.id AND cm.section = cs.id <br />
JOIN prefix_modules AS m ON m.id = cm.module<br />
LEFT JOIN prefix_grade_items AS gi ON gi.courseid = c.id AND gi.itemmodule = m.name AND gi.iteminstance = cm.instance<br />
<br />
WHERE <br />
cs.visible = 1<br />
AND cm.visible = 1<br />
AND c.id = %%COURSEID%%<br />
<br />
GROUP BY cs.section<br />
ORDER BY cs.section<br />
<br />
</code><br />
<br />
===Assignments and Weights===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
Returns a list of grade book categories for the current course, grade book weightings, the first type of assignment included in the category, a count of different assignment types for each category, and a count of assignments for each category.<br />
<br />
Categories with weights of 0 are not included in this report.<br />
<br />
Only visible activities are included in this report.<br />
<br />
'''Note''': This is designed to be a "Global" report in Configurable Reports.<br />
<code sql><br />
SELECT<br />
<br />
IF(gc.parent IS NOT NULL, gc.fullname, 'None') AS 'Grade Book Category'<br />
, IF(gc.parent IS NOT NULL, ROUND(gic.aggregationcoef, 2), ROUND(SUM(DISTINCT gi.aggregationcoef), 2)+ROUND(SUM(DISTINCT mgi.aggregationcoef), 2)) AS 'Category weight'<br />
<br />
, CONCAT_WS(', ',GROUP_CONCAT(DISTINCT gi.itemmodule SEPARATOR ', '), IF(mgi.id, 'manual',NULL)) AS 'Activity Types'<br />
, COUNT(DISTINCT gi.itemmodule) + IF(mgi.id,1,0) AS 'Different Activity Types'<br />
, CONCAT_WS('<br>', GROUP_CONCAT(DISTINCT gi.itemname ORDER BY gi.itemname SEPARATOR '<br>'), GROUP_CONCAT(DISTINCT mgi.itemname ORDER BY mgi.itemname SEPARATOR '<br>')) AS 'Activity Names'<br />
, COUNT(DISTINCT IF(gi.id, cm.id, NULL)) + COUNT(DISTINCT mgi.id) AS 'Activity Count'<br />
<br />
FROM prefix_course AS c<br />
<br />
#get grade categories<br />
LEFT JOIN prefix_grade_categories AS gc ON gc.courseid = c.id <br />
# back from categories to grade items to get aggregations and weights<br />
JOIN prefix_grade_items AS gic ON gic.courseid = c.id AND gic.itemtype = 'category' AND gic.aggregationcoef != 0 AND (LOCATE(gic.iteminstance, gc.path) OR (gc.parent IS NULL))<br />
<br />
# attach activities to course<br />
JOIN prefix_course_modules AS cm ON cm.course = c.id <br />
# attach grade items to activities<br />
LEFT JOIN prefix_grade_items AS gi ON gi.courseid = c.id AND gi.iteminstance = cm.instance AND gi.itemtype = 'mod' AND gi.categoryid = gc.id AND gi.hidden != 1<br />
<br />
# attach manual grade items to course-- they don't have modules<br />
LEFT JOIN prefix_grade_items AS mgi ON mgi.courseid = c.id and mgi.itemtype = 'manual' AND mgi.categoryid = gc.id<br />
<br />
WHERE <br />
cm.visible = 1<br />
AND c.id = %%COURSEID%%<br />
<br />
GROUP BY gc.id<br />
ORDER BY gc.id<br />
<br />
</code><br />
<br />
===Pre-Term Course Review===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
Provides an overview of the readiness of ONLINE, HYBRID, and BLENDED courses in the Staging category and all subcategories. Links to each course are provided. Other details:<br />
<br />
# "Required blocks" include Instructor Block (mooprofile), Activities, and the Research block.<br />
# "Instructor Details" block is not the "Instructor" block (mooprofile) automatically provided by the system. It is an optional block that can be edited by the instructor. If not edited to remove boilerplate text, it should be hidden.<br />
# All courses should be in the "Collapsed Topics" format with the "Weeks" structure.<br />
# "Weeks defined in course settings" is taken from our SIS when the course shells are created, but can be edited by faculty. "# of weeks named and visible" should usually match or exceed this value.<br />
# We recommend that each week contain at least one forum, at least one graded activity, and at least one ungraded resource.<br />
# "Syllabus updated" date is for the first attached file found with the text "syllabus" in the name. The "Days ago" calculation is included for convenience.<br />
<br />
'''Note''': At our institution, we construct categories each term, and insert a text string "staging" in the Category ID for pre-term courses during the preparation or "staging" phase of course development. We remove this text string (and change it to "production") when courses go live at the start of the new term.<br />
<br />
<code sql><br />
SELECT CONCAT('<a target="_blank" href="%%WWWROOT%%/course/view.php',CHAR(63),'id=',c.id,'">',c.shortname,'</a>') AS Course<br />
<br />
#,RIGHT(c.idnumber,2) AS Type # Specific to GSC "Instructional Method" storage<br />
<br />
#, substring_index(substr(c.shortname FROM locate('.',c.shortname)+1),'-',1) AS Section # Specific to GSC<br />
<br />
,(SELECT CONCAT('<a target="_blank" href="%%WWWROOT%%/user/view.php',CHAR(63),'id=',u.id,'">',u.lastname,', ', u.firstname,'</a>')<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS 'Instructor' <br />
<br />
,(SELECT IF((u2.description IS NULL) OR (u2.description LIKE ''),'NO', 'YES')<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u2 ON u2.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS 'Profile Has Bio'<br />
<br />
,(SELECT IF(u3.picture > 0,'YES','NO')<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u3 ON u3.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS 'Profile Has Picture'<br />
<br />
, IF(((bpi.visible IS NULL) OR (bpi.visible !=0)) AND ((bpm.visible IS NULL) OR (bpm.visible !=0)) AND ((bpa.visible IS NULL) OR (bpa.visible !=0)) AND ((bpr.visible IS NULL) OR (bpr.visible !=0)),'YES','NO') AS 'Required blocks visible'<br />
#, IF((bpm.visible IS NULL) OR (bpm.visible !=0),'YES','NO') AS 'Messages block visible'<br />
#, IF((bpa.visible IS NULL) OR (bpa.visible !=0),'YES','NO') AS 'activities block visible'<br />
#, IF((bpr.visible IS NULL) OR (bpr.visible !=0),'YES','NO') AS 'research block visible'<br />
<br />
#, IF(SUM(IF(bi.configdata LIKE 'Tzo4OiJzdGRDbGFzcyI6Mzp7czo1OiJ0aXRsZSI7czoxODoiSW5zdHJ1Y3RvciBEZXRhaWxzI%',1,0)) AND (bip.visible !=0),'YES','') AS 'Instructor Details Block visible' # This is a hack based on UUencoded string data from the title of HTML "Instructor Details" block<br />
<br />
#, IF(bi.configdata LIKE '%ZGl0IHRoaXMgYmxvY2s%','NO','') AS 'Instructor Details Block Updated' # HTML block has string 'dit this block'<br />
<br />
#, IF(COUNT(bi.id) - SUM(IF(bi.configdata LIKE 'Tzo4OiJzdGRDbGFzcyI6Mzp7czo1OiJ0aXRsZSI7czoxODoiSW5zdHJ1Y3RvciBEZXRhaWxzI%',1,0)),'YES','') AS 'possible extra instructor blocks' #looking for any HTML block with "instructor" in the title<br />
<br />
, IF(c.format='topcoll','YES', c.format) AS 'Collapsed Topics course format' # change this if you want to test for a different format<br />
, IF(cfo.value = 2, 'YES','NO') AS 'weeks structure'<br />
<br />
, cfw.value AS 'weeks defined in course settings'<br />
<br />
, COUNT(DISTINCT IF(((cs.name IS NOT NULL) AND (cs.visible = 1) AND (cs.section != '0') AND (cs.sequence IS NOT NULL)),cs.id,NULL)) AS '# of weeks named & visible (includes orphans)'<br />
<br />
, COUNT(DISTINCT IF(m.name LIKE 'forum', cm.id, NULL)) AS 'Forums'<br />
, COUNT(DISTINCT IF(m.name LIKE 'forum' ,cs.id , NULL)) AS 'Weeks with Forum'<br />
<br />
, COUNT(DISTINCT IF(gi.id, cm.id, NULL)) AS 'Activities'<br />
, COUNT(DISTINCT IF(gi.id, cs.id, NULL)) AS 'Weeks with Activities'<br />
, COUNT(DISTINCT mgi.id) AS 'Manual Grade Items'<br />
<br />
, COUNT(DISTINCT IF((gi.id IS NULL) AND (m.name NOT IN ('forum','label')),cm.id,NULL)) AS 'Resources'<br />
, COUNT(DISTINCT IF((gi.id IS NULL) AND (m.name NOT IN ('forum','label')), cs.id, NULL)) AS 'Weeks with Resources'<br />
<br />
# Here are some other things you could check for per course<br />
#,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm JOIN prefix_modules AS m ON cm.module = m.id WHERE cm.course = c.id AND m.name LIKE '%forum%') AS Forums<br />
<br />
#,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm JOIN prefix_modules AS m ON cm.module = m.id WHERE cm.course = c.id AND m.name LIKE '%quiz%') AS Quizzes<br />
<br />
#,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm JOIN prefix_modules AS m ON cm.module = m.id WHERE cm.course = c.id AND m.name LIKE '%assign%') AS Assignments<br />
<br />
#,(SELECT COUNT(prefix_resource.id) FROM prefix_resource JOIN prefix_course ON prefix_course.id = prefix_resource.course WHERE c.id = prefix_resource.course) AS Files<br />
<br />
#,(SELECT COUNT(prefix_url.id) FROM prefix_url JOIN prefix_course ON prefix_course.id = prefix_url.course WHERE c.id = prefix_url.course) AS Links<br />
<br />
,(SELECT FROM_UNIXTIME(MAX(prefix_resource.timemodified))<br />
FROM prefix_resource<br />
JOIN prefix_course ON prefix_course.id = prefix_resource.course WHERE c.id = prefix_resource.course AND prefix_resource.name LIKE '%syllabus%') AS SyllabusDate<br />
<br />
,(SELECT TO_DAYS(NOW())-TO_DAYS(FROM_UNIXTIME(MAX(prefix_resource.timemodified)))<br />
FROM prefix_resource<br />
JOIN prefix_course ON prefix_course.id = prefix_resource.course WHERE c.id = prefix_resource.course AND prefix_resource.name LIKE '%syllabus%') AS DaysAgo<br />
<br />
, IF(COUNT(DISTINCT IF(f.type LIKE 'news', f.id,NULL)),'YES','NO' ) AS 'Announcement Forum Visible'<br />
<br />
, IF(COUNT(DISTINCT IF(f.type LIKE 'news', fd.id,NULL)),'YES','NO' ) AS 'Announcement posted'<br />
<br />
FROM prefix_course AS c<br />
LEFT JOIN prefix_course_categories as cc ON c.category = cc.id<br />
LEFT JOIN prefix_context AS ctxx ON c.id = ctxx.instanceid <br />
<br />
LEFT JOIN prefix_block_positions AS bpi ON bpi.contextid = ctxx.id AND bpi.blockinstanceid = '43692' # mooprofile<br />
LEFT JOIN prefix_block_positions AS bpm ON bpm.contextid = ctxx.id AND bpm.blockinstanceid = '43962' # messages<br />
LEFT JOIN prefix_block_positions AS bpa ON bpa.contextid = ctxx.id AND bpa.blockinstanceid = '43963' # activities<br />
LEFT JOIN prefix_block_positions AS bpr ON bpr.contextid = ctxx.id AND bpr.blockinstanceid = '38368' # html research help<br />
<br />
LEFT JOIN prefix_course_sections AS cs ON cs.course = c.id AND cs.visible = 1 AND cs.sequence IS NOT NULL<br />
LEFT JOIN prefix_course_modules AS cm ON cm.course = c.id AND cm.section = cs.id <br />
LEFT JOIN prefix_modules AS m ON m.id = cm.module<br />
LEFT JOIN prefix_grade_items AS gi ON gi.courseid = c.id AND gi.itemmodule = m.name AND gi.iteminstance = cm.instance<br />
<br />
LEFT JOIN prefix_forum AS f ON f.course = c.id AND cm.instance = f.id AND cm.visible = 1<br />
LEFT JOIN prefix_forum_discussions AS fd ON fd.forum = f.id<br />
<br />
# attach manual grade items to course-- they don't have modules<br />
LEFT JOIN prefix_grade_items AS mgi ON mgi.courseid = c.id and mgi.itemtype = 'manual'<br />
<br />
LEFT JOIN prefix_course_format_options AS cfo ON cfo.courseid = c.id AND cfo.name = 'layoutstructure'<br />
LEFT JOIN prefix_course_format_options AS cfw ON cfw.courseid = c.id AND cfw.name = 'numsections'<br />
<br />
LEFT JOIN prefix_block_instances AS bi ON bi.parentcontextid = ctxx.id AND bi.blockname = 'html' AND (bi.configdata LIKE '%SW5zdHJ1Y3Rvc%' or bi.configdata LIKE '%bnN0cnVjdG9y%')<br />
LEFT JOIN prefix_block_positions AS bip ON bip.blockinstanceid = bi.id<br />
<br />
WHERE RIGHT(c.idnumber,2) IN ('OL', 'BL', 'HY') <br />
# AND substring(cc.path,2,2) IN ('26') # Staging<br />
#AND substring(cc.path,2,3) IN ('158') # UG<br />
AND cc.idnumber LIKE '%staging%'<br />
AND ctxx.contextlevel = 50<br />
<br />
GROUP BY c.shortname<br />
</code><br />
<br />
===Module instances + Module HITs by role teacher and student in course===<br />
<code sql><br />
SELECT <br />
m.name AS "Module name"<br />
, COUNT(*) AS "Module count"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_log AS l <br />
WHERE l.course = cm.course AND l.module = m.name ) AS "Hits"<br />
<br />
,(SELECT COUNT(*)<br />
FROM prefix_log AS l<br />
JOIN prefix_context AS con ON con.instanceid= l.course AND con.contextlevel=50<br />
JOIN prefix_role_assignments AS ra ON ra.contextid= con.id AND ra.userid= l.userid AND ra.roleid = 5 <br />
WHERE l.course = cm.course AND l.module = m.name) AS "Students HITs"<br />
<br />
,(SELECT COUNT(*)<br />
FROM prefix_log AS l<br />
JOIN prefix_context AS con ON con.instanceid= l.course AND con.contextlevel=50<br />
JOIN prefix_role_assignments AS ra ON ra.contextid= con.id AND ra.userid= l.userid AND ra.roleid = 3 <br />
WHERE l.course = cm.course AND l.module = m.name) AS "Teachers HITs"<br />
<br />
FROM mdl_course_modules AS cm<br />
JOIN mdl_modules AS m on m.id = cm.module<br />
WHERE cm.course = '%%COURSEID%%'<br />
GROUP BY cm.module<br />
</code><br />
<br />
===Course Syllabus===<br />
Contributed by Elizabeth Dalton, Granite State College / Moodle HQ<br />
<br />
This report requires ELIS. It runs from within a course and constructs a course syllabus based on content in the course and in the ELIS entries related to the course (Class Instance, Course Description, and Program). It is a proof-of-concept of an automated syllabus production tool. Fields such as "Course Policies" and "Teaching Philosophy" are added to the Class Instance records, and instructors enter them there. The Instructor Bio is pulled from the User Profile of all users with the Teacher role in the course.<br />
<br />
<code sql><br />
SELECT <br />
<br />
c.fullname AS 'fullname'<br />
, ec.idnumber AS 'elis-id'<br />
, DATE_FORMAT(FROM_UNIXTIME(ec.startdate), '%b %e, %Y') AS 'start'<br />
, DATE_FORMAT(FROM_UNIXTIME(ec.enddate), '%b %e, %Y') AS 'end'<br />
, ecd.name AS 'longname'<br />
, ecd.code AS 'coursecode'<br />
, ecd.credits AS 'coursecredits'<br />
, ecd.syllabus AS 'description'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'learning-outcomes'<br />
WHERE ctxecd.id = eft.contextid) AS 'outcomes'<br />
<br />
,(SELECT CONCAT('<a target="_blank" href="%%WWWROOT%%/user/view.php',CHAR(63),'id=',u.id,'">',u.firstname,' ', u.lastname,'</a> ', u.email)<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS 'Instructor' <br />
<br />
, (SELECT efc.data<br />
FROM prefix_local_eliscore_fld_data_char AS efc<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = efc.fieldid AND ef.shortname = 'term-code'<br />
WHERE ctxci.id = efc.contextid) AS 'termcode'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'prerequisites'<br />
WHERE ctxecd.id = eft.contextid) AS 'prerequisites'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'textbooks'<br />
WHERE ctxci.id = eft.contextid) AS 'textbooks'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'other-class-materials'<br />
WHERE ctxci.id = eft.contextid) AS 'other-class-materials'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'course-policies'<br />
WHERE ctxci.id = eft.contextid) AS 'course-policies'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'teaching-philosophy'<br />
WHERE ctxci.id = eft.contextid) AS 'teaching-philosophy'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'course-methods'<br />
WHERE ctxci.id = eft.contextid) AS 'course-methods'<br />
<br />
,(SELECT u2.description<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u2 ON u2.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS 'Bio'<br />
<br />
,(SELECT<br />
<br />
GROUP_CONCAT(DISTINCT CONCAT(<br />
<br />
'<tr><td style="border: solid #000 .5px">',IF(gc.parent IS NOT NULL, gc.fullname, 'None')<br />
, ' </td><td style="border: solid #000 .5px"> '<br />
,IF(gc.parent IS NOT NULL, ROUND(gic.aggregationcoef, 2), ROUND( gi.aggregationcoef, 2)+ROUND(mgi.aggregationcoef, 2))<br />
<br />
) SEPARATOR '</td></tr>')<br />
#get grade categories<br />
FROM prefix_grade_categories AS gc <br />
# back from categories to grade items to get aggregations and weights<br />
LEFT JOIN prefix_grade_items AS gic ON gic.courseid = gc.courseid AND gic.itemtype = 'category' AND gic.aggregationcoef != 0 AND (LOCATE(gic.iteminstance, gc.path) OR (gc.parent IS NULL))<br />
# attach grade items to activities<br />
LEFT JOIN prefix_grade_items AS gi ON gi.courseid = gc.courseid AND gi.itemtype = 'mod' AND gi.categoryid = gc.id AND gi.hidden != 1<br />
# attach manual grade items to course-- they don't have modules<br />
LEFT JOIN prefix_grade_items AS mgi ON mgi.courseid = gc.courseid and mgi.itemtype = 'manual' AND mgi.categoryid = gc.id<br />
WHERE gc.courseid = c.id ) AS 'grade categories'<br />
<br />
, '<table width = "50%" >' AS 'table start'<br />
, '<table width = "100%" >' AS 'table start 2'<br />
, '</table>' AS 'table end'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'activities-schedule'<br />
WHERE ctxci.id = eft.contextid) AS 'activities'<br />
<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'schedule'<br />
WHERE ctxci.id = eft.contextid) AS 'schedule'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'grading-scale'<br />
WHERE ctxepm.id = eft.contextid) AS 'gradescale'<br />
<br />
FROM<br />
prefix_course AS c <br />
<br />
# connect moodle course to ELIS class instance<br />
LEFT JOIN prefix_local_elisprogram_cls_mdl AS ecm ON ecm.moodlecourseid = c.id<br />
LEFT JOIN prefix_local_elisprogram_cls AS ec ON ec.id = ecm.classid<br />
# class instance context<br />
LEFT JOIN prefix_context AS ctxci ON ctxci.instanceid = ec.id AND ctxci.contextlevel = '14'<br />
<br />
# connect ELIS class instance to ELIS course description<br />
LEFT JOIN prefix_local_elisprogram_crs AS ecd ON ecd.id = ec.courseid<br />
# course description context<br />
LEFT JOIN prefix_context AS ctxecd ON ctxecd.instanceid = ecd.id AND ctxecd.contextlevel = '13'<br />
<br />
#connect ELIS program to ELIS Course Description<br />
LEFT JOIN prefix_local_elisprogram_pgm_crs AS epc ON epc.courseid = ecd.id<br />
LEFT JOIN prefix_local_elisprogram_pgm AS epm ON epm.id = epc.curriculumid<br />
# course program context<br />
LEFT JOIN prefix_context AS ctxepm ON ctxepm.instanceid = epm.id AND ctxepm.contextlevel = '11'<br />
<br />
WHERE<br />
<br />
c.id = %%COURSEID%%<br />
</code><br />
<br />
===Course Activities Helper===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
This report provides a list of the graded activities in a course.<br />
* '''Note''': Only graded activities are displayed.<br />
* '''Note''': This is a "Global" report. Run it within a course to see a summary of the contents of that course.<br />
* '''Note''': This report assumes that course sections each last one week.<br />
<br />
<code sql><br />
# 303 Course Activities Helper<br />
<br />
SELECT <br />
<br />
gi.itemmodule AS 'activity type'<br />
# cs.section AS 'section number'<br />
<br />
# Calculation assumes each section lasts one week<br />
, CONCAT(DATE_FORMAT(FROM_UNIXTIME(c.startdate + (7*24*60*60* (cs.section-1))), '%b %e, %Y'),' - <br>',DATE_FORMAT(FROM_UNIXTIME(c.startdate + (7*24*60*60* (cs.section))), '%b %e, %Y')) AS 'Date'<br />
<br />
, gi.itemname AS 'activity name'<br />
<br />
#, (SELECT asg.intro FROM prefix_assign AS asg WHERE asg.id = cm.instance) AS 'intro'<br />
<br />
#, (SELECT f.intro FROM prefix_forum AS f WHERE f.id = cm.instance) AS 'f intro'<br />
<br />
, CASE gi.itemmodule <br />
WHEN 'assign' THEN (SELECT asg.intro FROM prefix_assign AS asg WHERE asg.id = gi.iteminstance) <br />
WHEN 'forum' THEN (SELECT f.intro FROM prefix_forum AS f WHERE f.id = gi.iteminstance) <br />
WHEN 'quiz' THEN (SELECT q.intro FROM prefix_quiz AS q WHERE q.id = gi.iteminstance) <br />
END AS 'test case'<br />
<br />
#, (SELECT GROUP_CONCAT(CONCAT(' - ',gi.itemname) SEPARATOR '<BR>') FROM prefix_grade_items AS gi JOIN prefix_course_modules AS cm ON gi.iteminstance = cm.instance WHERE gi.gradetype = 1 AND gi.hidden != 1 AND gi.courseid = c.id AND cm.course = c.id AND cm.section = cs.id ) AS 'activities'<br />
<br />
<br />
FROM<br />
prefix_course AS c <br />
<br />
#get grade sections<br />
LEFT JOIN prefix_course_sections AS cs ON cs.course = c.id AND cs.section > 0 AND cs.section <=14<br />
LEFT JOIN prefix_course_modules AS cm ON cm.course = c.id AND cm.section = cs.id<br />
<br />
#LEFT JOIN prefix_assign AS asg ON asg.id = cm.instance<br />
<br />
JOIN prefix_grade_items AS gi ON gi.iteminstance = cm.instance AND gi.gradetype = 1 AND gi.hidden != 1 AND gi.courseid = c.id AND cm.course = c.id AND cm.section = cs.id<br />
<br />
WHERE<br />
c.id = %%COURSEID%%<br />
AND cs.visible = 1<br />
<br />
ORDER BY gi.itemmodule, cs.section<br />
</code><br />
<br />
==Grade and Course Completion Reports==<br />
===Site-Wide Grade Report with All Items===<br />
Shows grades for all course items along with course totals for each student. Works with ad-hoc reports or Configurable Reports<br />
<code sql><br />
SELECT u.firstname AS 'First' , u.lastname AS 'Last', <br />
u.firstname + ' ' + u.lastname AS 'Display Name', <br />
c.fullname AS 'Course', <br />
cc.name AS 'Category',<br />
<br />
CASE <br />
WHEN gi.itemtype = 'course' <br />
THEN c.fullname + ' Course Total'<br />
ELSE gi.itemname<br />
END AS 'Item Name',<br />
<br />
ROUND(gg.finalgrade,2) AS Grade,<br />
DATEADD(ss,gg.timemodified,'1970-01-01') AS Time<br />
<br />
FROM prefix_course AS c<br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid<br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
JOIN prefix_grade_grades AS gg ON gg.userid = u.id<br />
JOIN prefix_grade_items AS gi ON gi.id = gg.itemid<br />
JOIN prefix_course_categories as cc ON cc.id = c.category<br />
<br />
WHERE gi.courseid = c.id <br />
ORDER BY lastname<br />
</code><br />
For MySQL users, you'll need to use the MySQL DATE_ADD function instead of DATEADD. Replace the line:<br />
<code><br />
DATEADD(ss,gg.timemodified,'1970-01-01') AS Time<br />
</code><br />
with:<br />
<code><br />
FROM_UNIXTIME(gg.timemodified) AS Time<br />
</code><br />
And:<br />
<code><br />
u.firstname + ' ' + u.lastname AS 'Display Name', <br />
</code><br />
with:<br />
<code><br />
CONCAT(u.firstname,' ',u.lastname) AS 'Display Name', <br />
</code><br />
<br />
===Site-Wide Grade Report with Just Course Totals===<br />
A second site-wide grade report for all students that just shows course totals. Works with ad-hoc reports or Configurable Reports<br />
<code sql><br />
SELECT u.firstname AS 'First' , u.lastname AS 'Last', u.firstname + ' ' + u.lastname AS 'Display Name', <br />
cc.name AS 'Category',<br />
CASE <br />
WHEN gi.itemtype = 'course' <br />
THEN c.fullname + ' Course Total'<br />
ELSE gi.itemname<br />
END AS 'Item Name',<br />
<br />
ROUND(gg.finalgrade,2) AS Grade,<br />
DATEADD(ss,gg.timemodified,'1970-01-01') AS Time<br />
<br />
FROM prefix_course AS c<br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid<br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
JOIN prefix_grade_grades AS gg ON gg.userid = u.id<br />
JOIN prefix_grade_items AS gi ON gi.id = gg.itemid<br />
JOIN prefix_course_categories as cc ON cc.id = c.category<br />
<br />
WHERE gi.courseid = c.id AND gi.itemtype = 'course'<br />
<br />
ORDER BY lastname<br />
</code><br />
<br />
For MySQL users:<br />
<code sql><br />
SELECT u.firstname AS 'First' , u.lastname AS 'Last', CONCAT(u.firstname , ' ' , u.lastname) AS 'Display Name', <br />
c.fullname AS 'Course', <br />
cc.name AS 'Category',<br />
CASE <br />
WHEN gi.itemtype = 'course' <br />
THEN CONCAT(c.fullname, ' - Total')<br />
ELSE gi.itemname<br />
END AS 'Item Name',<br />
<br />
ROUND(gg.finalgrade,2) AS Grade,<br />
FROM_UNIXTIME(gg.timemodified) AS TIME<br />
<br />
FROM prefix_course AS c<br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid<br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
JOIN prefix_grade_grades AS gg ON gg.userid = u.id<br />
JOIN prefix_grade_items AS gi ON gi.id = gg.itemid<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
<br />
WHERE gi.courseid = c.id AND gi.itemtype = 'course'<br />
ORDER BY lastname<br />
</code><br />
<br />
===Learner report by Learner with grades===<br />
Which Learners in which course and what are the grades<br />
<code sql><br />
SELECT u.firstname AS 'Name' , u.lastname AS 'Surname', c.fullname AS 'Course', cc.name AS 'Category', <br />
CASE WHEN gi.itemtype = 'Course' <br />
THEN c.fullname + ' Course Total' <br />
ELSE gi.itemname <br />
END AS 'Item Name', ROUND(gg.finalgrade,2) AS Score,ROUND(gg.rawgrademax,2) AS Max, ROUND(gg.finalgrade / gg.rawgrademax * 100 ,2) as Percentage,<br />
<br />
if (ROUND(gg.finalgrade / gg.rawgrademax * 100 ,2) > 79,'Yes' , 'No') as Pass<br />
<br />
FROM prefix_course AS c <br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid <br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id <br />
JOIN prefix_user AS u ON u.id = ra.userid <br />
JOIN prefix_grade_grades AS gg ON gg.userid = u.id <br />
JOIN prefix_grade_items AS gi ON gi.id = gg.itemid <br />
JOIN prefix_course_categories AS cc ON cc.id = c.category <br />
WHERE gi.courseid = c.id and gi.itemname != 'Attendance'<br />
ORDER BY `Name` ASC<br />
</code><br />
<br />
===User Course Completion===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
A very simple report with a list of course completion status by username. Completions are noted by date, blank otherwise. <br />
<br />
<code sql><br />
SELECT <br />
u.username, <br />
c.shortname, <br />
DATE_FORMAT(FROM_UNIXTIME(p.timecompleted),'%Y-%m-%d') AS completed<br />
FROM prefix_course_completions AS p<br />
JOIN prefix_course AS c ON p.course = c.id<br />
JOIN prefix_user AS u ON p.userid = u.id<br />
WHERE c.enablecompletion = 1<br />
ORDER BY u.username<br />
</code><br />
<br />
===User Course Completion with Criteria===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
A report with course completions by username, with Aggregation method, Criteria types, and Criteria detail where available.<br />
<br />
<code sql><br />
SELECT u.username AS user, <br />
c.shortname AS course,<br />
DATE_FORMAT(FROM_UNIXTIME(t.timecompleted),'%Y-%m-%d') AS completed,<br />
CASE<br />
WHEN (SELECT a.method FROM prefix_course_completion_aggr_methd AS a WHERE (a.course = c.id AND a.criteriatype IS NULL) = 1) THEN "Any"<br />
ELSE "All"<br />
END AS aggregation,<br />
CASE <br />
WHEN p.criteriatype = 1 THEN "Self"<br />
WHEN p.criteriatype = 2 THEN "By Date"<br />
WHEN p.criteriatype = 3 THEN "Unenrol Status"<br />
WHEN p.criteriatype = 4 THEN "Activity"<br />
WHEN p.criteriatype = 5 THEN "Duration"<br />
WHEN p.criteriatype = 6 THEN "Course Grade"<br />
WHEN p.criteriatype = 7 THEN "Approve by Role"<br />
WHEN p.criteriatype = 8 THEN "Previous Course"<br />
END AS criteriatype,<br />
CASE <br />
WHEN p.criteriatype = 1 THEN "*"<br />
WHEN p.criteriatype = 2 THEN DATE_FORMAT(FROM_UNIXTIME(p.timeend),'%Y-%m-%d')<br />
WHEN p.criteriatype = 3 THEN t.unenroled<br />
WHEN p.criteriatype = 4 THEN <br />
CONCAT('<a target="_new" href="%%WWWROOT%%/mod/',p.module,'/view.php?id=',p.moduleinstance,'">',p.module,'</a>')<br />
WHEN p.criteriatype = 5 THEN p.enrolperiod<br />
WHEN p.criteriatype = 6 THEN CONCAT('Needed: ',ROUND(p.gradepass,2),' Achieved: ',ROUND(t.gradefinal,2)) <br />
WHEN p.criteriatype = 7 THEN p.role<br />
WHEN p.criteriatype = 8 THEN (SELECT pc.shortname FROM prefix_course AS pc WHERE pc.id = p.courseinstance)<br />
END AS criteriadetail <br />
FROM prefix_course_completion_crit_compl AS t<br />
JOIN prefix_user AS u ON t.userid = u.id<br />
JOIN prefix_course AS c ON t.course = c.id<br />
JOIN prefix_course_completion_criteria AS p ON t.criteriaid = p.id<br />
<br />
</code><br />
<br />
===Courses with Completion Enabled and their settings===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
List of all courses with completion enabled and their Aggregation setting, Criteria types, and Criteria details.<br />
<br />
<code sql><br />
<br />
SELECT c.shortname AS Course, <br />
CASE<br />
WHEN (SELECT a.method FROM prefix_course_completion_aggr_methd AS a WHERE (a.course = t.course AND a.criteriatype IS NULL)) = 2 THEN "All"<br />
ELSE "Any"<br />
END AS Course_Aggregation,<br />
CASE<br />
WHEN t.criteriatype = 1 THEN "Self completion"<br />
WHEN t.criteriatype = 2 THEN "Date done by" <br />
WHEN t.criteriatype = 3 THEN "Unenrolement" <br />
WHEN t.criteriatype = 4 THEN "Activity completion" <br />
WHEN t.criteriatype = 5 THEN "Duration in days" <br />
WHEN t.criteriatype = 6 THEN "Final grade" <br />
WHEN t.criteriatype = 7 THEN "Approve by role" <br />
WHEN t.criteriatype = 8 THEN "Previous course"<br />
END AS Criteria_type,<br />
CASE<br />
WHEN t.criteriatype = 1 THEN "On"<br />
WHEN t.criteriatype = 2 THEN DATE_FORMAT(FROM_UNIXTIME(t.timeend),'%Y-%m-%d')<br />
WHEN t.criteriatype = 3 THEN "On"<br />
WHEN t.criteriatype = 4 THEN<br />
CONCAT('<a target="_new" href="%%WWWROOT%%/mod/',t.module,'/view.php?id=',t.moduleinstance,'">',t.module,'</a>')<br />
WHEN t.criteriatype = 5 THEN ROUND(t.enrolperiod/86400)<br />
WHEN t.criteriatype = 6 THEN ROUND(t.gradepass,2)<br />
WHEN t.criteriatype = 7 THEN (SELECT r.shortname FROM prefix_role AS r WHERE r.id = t.role)<br />
WHEN t.criteriatype = 8 THEN (SELECT pc.shortname FROM prefix_course AS pc WHERE pc.id = t.courseinstance)<br />
END AS Criteria_detail<br />
FROM prefix_course_completion_criteria as t<br />
JOIN prefix_course AS c ON t.course = c.id<br />
WHERE c.enablecompletion = 1<br />
ORDER BY course<br />
</code><br />
<br />
===Course Completion Report with custom dates===<br />
<br />
List of users who completed multiple or single course/s from a start date to end date chosen by the user. The output gives username, name, course name, completion date and score<br />
<br />
<code sql><br />
<br />
SELECT u.username AS 'User Name',<br />
CONCAT(u.firstname , ' ' , u.lastname) AS 'Name',<br />
c.shortname AS 'Course Name', <br />
DATE_FORMAT(FROM_UNIXTIME(p.timecompleted),'%W %e %M, %Y') AS 'Completed Date',<br />
ROUND(c4.gradefinal,2) AS 'Score'<br />
FROM prefix_course_completions AS p<br />
JOIN prefix_course AS c ON p.course = c.id<br />
JOIN prefix_user AS u ON p.userid = u.id<br />
JOIN prefix_course_completion_crit_compl AS c4 ON u.id = c4.userid<br />
WHERE c.enablecompletion = 1 AND (p.timecompleted IS NOT NULL OR p.timecompleted !='') <br />
AND (p.timecompleted>= :start_date AND p.timecompleted<=:end_date)<br />
GROUP BY u.username<br />
ORDER BY c.shortname<br />
<br />
</code><br />
<br />
===Scales used in activities===<br />
<code sql><br />
SELECT scale.name<br />
,CONCAT('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS Course<br />
,CONCAT('<a target="_new" href="%%WWWROOT%%/mod/',gi.itemmodule,'/view.php?id=',cm.id,'">',gi.itemname,'</a>') AS "Module View"<br />
,CONCAT('<a target="_new" href="%%WWWROOT%%/course/modedit.php?up','date=',cm.id,'">',gi.itemname,'</a>') AS "Module Settings"<br />
<br />
FROM prefix_grade_items AS gi<br />
JOIN prefix_course AS c ON c.id = gi.courseid<br />
JOIN prefix_course_modules AS cm ON cm.course = gi.courseid AND cm.instance = gi.iteminstance<br />
JOIN prefix_scale AS scale ON scale.id = gi.scaleid<br />
WHERE gi.scaleid IS NOT NULL<br />
</code><br />
<br />
<br />
===Extra Credit Items by Name Only===<br />
Contributed by Eric Strom<br />
<br />
This query identifies grade items in visible courses with student enrollment that have "extra credit" in the name of the item but set as extra credit in the grade settings. Includes the defined course start date, count of students and instructors, and a clickable email link of instructor (first found record if more than one).<br />
<br />
<code sql><br />
SELECT DATE(FROM_UNIXTIME(c.startdate)) AS StartDate, <br />
concat('<a target="_new" href="%%WWWROOT%%/grade/edit/tree/index.php',CHAR(63),'id=',<br />
c.id,'">',c.idnumber,'</a>') AS Course_ID, gi.itemname AS Item_Name<br />
<br />
,(SELECT COUNT( ra.userid ) FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = c.id) AS Students<br />
<br />
,(SELECT COUNT( ra.userid ) FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id) AS Instructors<br />
<br />
,(SELECT DISTINCT concat('<a href="mailto:',u.email,'">',u.email,'</a>')<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_user AS u ON ra.userid = u.id<br />
JOIN prefix_context AS ctx ON ctx.id = ra.contextid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id AND ctx.contextlevel = 50 LIMIT 1) AS 'Instructor_Email'<br />
<br />
,now() AS Report_Timestamp<br />
<br />
FROM prefix_grade_items AS gi<br />
JOIN prefix_course AS c ON gi.courseid = c.id<br />
<br />
WHERE gi.itemname LIKE '%extra credit%' <br />
AND gi.gradetype = '1' <br />
AND gi.hidden = '0' <br />
AND gi.aggregationcoef = '0' <br />
AND c.visible = 1<br />
AND (SELECT COUNT( ra.userid ) FROM prefix_role_assignments AS ra JOIN prefix_context AS ctx ON ra.contextid = ctx.id WHERE ra.roleid = 5 AND ctx.instanceid = c.id) > 0<br />
<br />
GROUP BY Course_ID, gi.id<br />
ORDER BY StartDate, Course_ID<br />
<br />
%%FILTER_SEARCHTEXT:Course_ID:~%%<br />
</code><br />
<br />
===Site Wide Number of Courses Completed by User===<br />
Contributed by Ken St. John<br />
<br />
Simple report that shows the number of completed courses for all users site wide<br />
<br />
<code sql><br />
SELECT u.lastname, u.firstname,<br />
COUNT(p.timecompleted) AS TotalCompletions<br />
FROM prefix_course_completions AS p<br />
JOIN prefix_user AS u ON p.userid = u.id<br />
GROUP BY p.userid<br />
ORDER BY u.lastname<br />
</code><br />
<br />
==Activity Module Reports==<br />
<br />
=== User activity completions with dates===<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
This report shows the users completion status of activities across all courses. It is intended to be uses with Configurable Reports filters for user, start and end times, and also to be able to search the Module names. <br />
<br />
Note: The CASE statement with module numbers may differ on different systems, depending on the number give to the module when the site was created or the module added to the site. These are common default numbers, but you should check your id numbers for them in the course_modules table and adjust as required. You can also add other, third-party plugins too if you wish. <br />
<br />
<code sql><br />
SELECT<br />
u.username As 'User',<br />
c.shortname AS 'Course',<br />
m.name AS Activitytype, <br />
CASE <br />
WHEN cm.module = 1 THEN (SELECT a1.name FROM prefix_assign a1 WHERE a1.id = cm.instance)<br />
WHEN cm.module = 2 THEN (SELECT a2.name FROM prefix_assignment a2 WHERE a2.id = cm.instance)<br />
WHEN cm.module = 3 THEN (SELECT a3.name FROM prefix_book a3 WHERE a3.id = cm.instance)<br />
WHEN cm.module = 4 THEN (SELECT a4.name FROM prefix_chat a4 WHERE a4.id = cm.instance)<br />
WHEN cm.module = 5 THEN (SELECT a5.name FROM prefix_choice a5 WHERE a5.id = cm.instance)<br />
WHEN cm.module = 6 THEN (SELECT a6.name FROM prefix_data a6 WHERE a6.id = cm.instance)<br />
WHEN cm.module = 7 THEN (SELECT a7.name FROM prefix_feedback a7 WHERE a7.id = cm.instance)<br />
WHEN cm.module = 8 THEN (SELECT a8.name FROM prefix_folder a8 WHERE a8.id = cm.instance)<br />
WHEN cm.module = 9 THEN (SELECT a9.name FROM prefix_forum a9 WHERE a9.id = cm.instance)<br />
WHEN cm.module = 10 THEN (SELECT a10.name FROM prefix_glossary a10 WHERE a10.id = cm.instance)<br />
WHEN cm.module = 11 THEN (SELECT a11.name FROM prefix_imscp a11 WHERE a11.id = cm.instance)<br />
WHEN cm.module = 12 THEN (SELECT a12.name FROM prefix_label a12 WHERE a12.id = cm.instance)<br />
WHEN cm.module = 13 THEN (SELECT a13.name FROM prefix_lesson a13 WHERE a13.id = cm.instance)<br />
WHEN cm.module = 14 THEN (SELECT a14.name FROM prefix_lti a14 WHERE a14.id = cm.instance)<br />
WHEN cm.module = 15 THEN (SELECT a15.name FROM prefix_page a15 WHERE a15.id = cm.instance)<br />
WHEN cm.module = 16 THEN (SELECT a16.name FROM prefix_quiz a16 WHERE a16.id = cm.instance)<br />
WHEN cm.module = 17 THEN (SELECT a17.name FROM prefix_resource a17 WHERE a17.id = cm.instance)<br />
WHEN cm.module = 18 THEN (SELECT a18.name FROM prefix_scorm a18 WHERE a18.id = cm.instance)<br />
WHEN cm.module = 19 THEN (SELECT a19.name FROM prefix_survey a19 WHERE a19.id = cm.instance)<br />
WHEN cm.module = 20 THEN (SELECT a20.name FROM prefix_url a20 WHERE a20.id = cm.instance)<br />
WHEN cm.module = 21 THEN (SELECT a21.name FROM prefix_wiki a21 WHERE a21.id = cm.instance)<br />
WHEN cm.module = 22 THEN (SELECT a22.name FROM prefix_workshop a22 WHERE a22.id = cm.instance)<br />
END AS Actvityname,<br />
# cm.section AS Coursesection,<br />
CASE<br />
WHEN cm.completion = 0 THEN '0 None'<br />
WHEN cm.completion = 1 THEN '1 Self'<br />
WHEN cm.completion = 2 THEN '2 Auto'<br />
END AS Activtycompletiontype, <br />
CASE<br />
WHEN cmc.completionstate = 0 THEN 'In Progress'<br />
WHEN cmc.completionstate = 1 THEN 'Completed'<br />
WHEN cmc.completionstate = 2 THEN 'Completed with Pass'<br />
WHEN cmc.completionstate = 3 THEN 'Completed with Fail'<br />
ELSE 'Unknown'<br />
END AS 'Progress', <br />
DATE_FORMAT(FROM_UNIXTIME(cmc.timemodified), '%Y-%m-%d %H:%i') AS 'When'<br />
FROM prefix_course_modules_completion cmc <br />
JOIN prefix_user u ON cmc.userid = u.id<br />
JOIN prefix_course_modules cm ON cmc.coursemoduleid = cm.id<br />
JOIN prefix_course c ON cm.course = c.id<br />
JOIN prefix_modules m ON cm.module = m.id<br />
# skip the predefined admin and guest user<br />
WHERE u.id > 2<br />
# config reports filters<br />
%%FILTER_USERS:u.username%%<br />
%%FILTER_SEARCHTEXT:m.name:~%%<br />
%%FILTER_STARTTIME:cmc.timemodified:>%% %%FILTER_ENDTIME:cmc.timemodified:<%%<br />
<br />
ORDER BY u.username<br />
<br />
</code><br />
<br />
===How many SCORM activities are used in each Course===<br />
<code sql><br />
SELECT cm.course,c.fullname ,m.name <br />
,concat('<a target="_new" href="%%WWWROOT%%/mod/scorm/index.php?id=',c.id,'">',count(cm.id),'</a>') AS Counter<br />
<br />
FROM `prefix_course_modules` as cm <br />
JOIN prefix_modules as m ON cm.module=m.id <br />
JOIN prefix_course as c ON cm.course = c.id <br />
WHERE m.name LIKE '%scorm%' <br />
GROUP BY cm.course,cm.module <br />
ORDER BY count(cm.id) desc<br />
</code><br />
<br />
===SCORM Usage by Course Start Date===<br />
Contributed by Elizabeth Dalton, Granite State College <br />
<br />
Report of number of inclusions of SCORM activities in courses, filtered by course start date.<br />
<br />
<code sql><br />
SELECT <br />
<br />
CONCAT('<a target="_blank" href="%%WWWROOT%%/course/view.php',CHAR(63),'id=',c.id,'">',c.shortname,'</a>') AS 'course'<br />
<br />
, cc.name AS 'Category'<br />
, scm.name AS 'Sample Activity Name'<br />
, FROM_UNIXTIME(c.startdate) AS 'Course Start Date'<br />
, COUNT(DISTINCT cm.id) AS 'Resources Used'<br />
#, FROM_UNIXTIME(cm.added) AS 'resource added'<br />
<br />
<br />
FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id AND m.name LIKE 'SCO%'<br />
<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
JOIN prefix_scorm AS scm ON scm.id = cm.instance<br />
<br />
WHERE<br />
1<br />
<br />
%%FILTER_STARTTIME:c.startdate:>%%<br />
%%FILTER_ENDTIME:c.startdate:<%%<br />
<br />
GROUP BY c.shortname, m.name<br />
ORDER BY c.startdate, c.shortname <br />
</code><br />
<br />
=== LTI (External Tool) Usage by Course Start Date===<br />
Contributed by Elizabeth Dalton, Granite State College <br />
<br />
Report of number of inclusions of LTI (External Tool) Usage activities in courses, filtered by course start date.<br />
<br />
<code sql><br />
SELECT <br />
<br />
CONCAT('<a target="_blank" href="%%WWWROOT%%/course/view.php',CHAR(63),'id=',c.id,'">',c.shortname,'</a>') AS 'course'<br />
<br />
, cc.name AS 'Category'<br />
, lti.name AS 'Sample Activity Name'<br />
, FROM_UNIXTIME(c.startdate) AS 'Course Start Date'<br />
, COUNT(DISTINCT cm.id) AS 'Resources Used'<br />
#, FROM_UNIXTIME(cm.added) AS 'resource added'<br />
<br />
<br />
FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id AND m.name LIKE 'lti'<br />
<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
JOIN prefix_lti AS lti ON lti.id = cm.instance<br />
WHERE<br />
1<br />
<br />
%%FILTER_STARTTIME:c.startdate:>%%<br />
%%FILTER_ENDTIME:c.startdate:<%%<br />
<br />
GROUP BY c.shortname, m.name<br />
ORDER BY c.startdate, c.shortname <br />
</code><br />
<br />
===Detailed ACTIONs for each MODULE===<br />
<code sql><br />
SELECT module,action,count(id) as counter<br />
FROM prefix_log<br />
GROUP BY module,action<br />
ORDER BY module,counter desc<br />
</code><br />
<br />
===Most popular ACTIVITY===<br />
<code sql><br />
SELECT COUNT(l.id) hits, module<br />
FROM prefix_log l<br />
WHERE module != 'login' AND module != 'course' AND module != 'role'<br />
GROUP BY module<br />
ORDER BY hits DESC<br />
</code><br />
<br />
===System wide use of ACTIVITIES and RESOURCES===<br />
<code sql><br />
SELECT count( cm.id ) AS counter, m.name<br />
FROM `prefix_course_modules` AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
GROUP BY cm.module<br />
ORDER BY counter DESC<br />
</code><br />
<br />
===LOG file ACTIONS per MODULE per COURSE (IDs)===<br />
<code sql><br />
select course,module,action,count(action) as summa from prefix_log<br />
where action <> 'new'<br />
group by course,action,module<br />
order by course,module,action<br />
</code><br />
<br />
===System Wide usage count of various course Activities===<br />
(Tested and works fine in Moodle 2.x)<br />
Like: Forum, Wiki, Blog, Assignment, Database,<br />
#Within specific category<br />
#Teacher name in course<br />
<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') as Course<br />
<br />
,(SELECT CONCAT(u.firstname,' ', u.lastname) AS Teacher<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS Teacher <br />
<br />
,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%') AS Wikis<br />
,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
WHERE cm.course = c.id AND m.name LIKE '%blog%') AS Blogs<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
WHERE cm.course = c.id AND m.name LIKE '%forum%') AS Forums<br />
<br />
,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
WHERE cm.course = c.id AND m.name LIKE '%data%') AS Databses<br />
<br />
,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
WHERE cm.course = c.id AND m.name LIKE '%assignment%') AS Assignments<br />
<br />
,(SELECT Count( ra.userid ) AS Users FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = c.id) AS Students<br />
<br />
FROM prefix_course AS c<br />
WHERE c.category IN ( 18)<br />
ORDER BY Wikis DESC,Blogs DESC, Forums DESC<br />
</code><br />
<br />
===Course wiki usage/activity over the last 6 semesters===<br />
<code sql><br />
SELECT "Courses with Wikis"<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%'<br />
and c.fullname LIKE CONCAT('%','2010','%') and c.fullname LIKE '%Semester A%') AS '2010 <br/> Semester A'<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%'<br />
and c.fullname LIKE CONCAT('%','2010','%') and c.fullname LIKE '%Semester B%') AS '2010 <br/> Semester B'<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%'<br />
and c.fullname LIKE CONCAT('%','תשעא','%') and c.fullname LIKE '%סמסטר א%') AS 'תשעא <br/> סמסטר א'<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%'<br />
and c.fullname LIKE CONCAT('%','תשעא','%') and c.fullname LIKE '%סמסטר ב%') AS 'תשעא <br/> סמסטר ב'<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%'<br />
and c.fullname LIKE CONCAT('%','תשעב','%') and c.fullname LIKE '%סמסטר א%') AS 'תשעב <br/> סמסטר א'<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%'<br />
and c.fullname LIKE CONCAT('%','תשעב','%') and c.fullname LIKE '%סמסטר ב%') AS 'תשעב <br/> סמסטר ב'<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%'<br />
and c.fullname LIKE CONCAT('%','תשעג','%') and c.fullname LIKE '%סמסטר א%') AS 'תשעג <br/> סמסטר א'<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%'<br />
and c.fullname LIKE CONCAT('%','תשעג','%') and c.fullname LIKE '%סמסטר ב%') AS 'תשעג <br/> סמסטר ב'<br />
</code><br />
<br />
===Detailed WIKI activity (per wiki per course)===<br />
Including Number of Students in course (for reference)<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',cm.course,'">',c.fullname,'</a>') as CourseID <br />
,(SELECT Count( ra.userid ) AS Users<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = c.id ) AS Students<br />
,m.name<br />
, ( SELECT count(id) FROM prefix_log WHERE cmid = cm.id AND action LIKE '%updat%' ) as 'UPDAT E'<br />
, ( SELECT count(id) FROM prefix_log WHERE cmid = cm.id AND action LIKE '%annotate%' ) as ANNOTATE<br />
, ( SELECT count(id) FROM prefix_log WHERE cmid = cm.id AND action LIKE '%comment%' ) as COMMENT<br />
, ( SELECT count(id) FROM prefix_log WHERE cmid = cm.id AND action LIKE '%add%' ) as 'A DD'<br />
, ( SELECT count(id) FROM prefix_log WHERE cmid = cm.id AND action LIKE '%edit%' ) as EDIT<br />
, ( SELECT count(id) FROM prefix_log WHERE cmid = cm.id AND action NOT LIKE '%view%' ) as 'All (NO View)'<br />
FROM `prefix_course_modules` as cm <br />
JOIN prefix_modules as m ON cm.module=m.id <br />
JOIN prefix_course as c ON cm.course = c.id <br />
WHERE m.name LIKE '%wiki%'<br />
GROUP BY cm.course,cm.module<br />
ORDER BY 'All (NO View)' DESC<br />
</code><br />
<br />
===Wiki usage, system wide===<br />
(you can filter the output by selecting some specific course categories : "WHERE c.category IN ( 8,13,15)")<br />
<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') as Course<br />
<br />
,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%') AS Wikis<br />
<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.course = c.id AND l.module LIKE '%wiki%') AS 'WikiActivity<br/>ALL'<br />
<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.course = c.id AND l.module LIKE '%wiki%' and l.action LIKE '%add%' ) AS 'WikiActivity<br/>ADD'<br />
<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.course = c.id AND l.module LIKE '%wiki%' and l.action LIKE '%edit%' ) AS 'WikiActivity<br/>EDIT'<br />
<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.course = c.id AND l.module LIKE '%wiki%' and l.action LIKE '%annotate%' ) AS 'WikiActivity<br/>ANNOTATE'<br />
<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.course = c.id AND l.module LIKE '%wiki%' and l.action LIKE '%comments%' ) AS 'WikiActivity<br/>Comments'<br />
<br />
,(SELECT Count( ra.userid ) AS Users FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = c.id) AS Students<br />
<br />
,(SELECT count(*) FROM prefix_ouwiki_pages as ouwp<br />
JOIN prefix_ouwiki as ouw ON ouw.id = ouwp.subwikiid<br />
WHERE ouw.course = c.id GROUP BY ouw.course ) as OUWikiPages<br />
<br />
,(SELECT count( DISTINCT nwp.pagename ) FROM prefix_wiki_pages AS nwp<br />
JOIN prefix_wiki AS nw ON nw.id = nwp.dfwiki WHERE nw.course = c.id ) As NWikiPages<br />
<br />
FROM prefix_course AS c<br />
WHERE c.category IN ( 8,13,15)<br />
HAVING Wikis > 0<br />
ORDER BY 'WikiActivity<br/>ALL' DESC<br />
</code><br />
<br />
===Aggregated Teacher activity by "WEB2" Modules===<br />
(Tested and works fine in Moodle 2.x)<br />
The NV column shows activity without VIEW log activity<br />
<code sql><br />
SELECT ra.userid, u.firstname,u.lastname<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.userid = u.id AND l.module LIKE '%wiki%') AS Wiki<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.userid = u.id AND l.module LIKE '%wiki%' AND l.action NOT LIKE '%view%') AS Wiki_NV<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.userid = u.id AND l.module LIKE '%forum%') AS Forum<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.userid = u.id AND l.module LIKE '%forum%' AND l.action NOT LIKE '%view%') AS Forum_NV<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.userid = u.id AND l.module LIKE '%blog%') AS Blog<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.userid = u.id AND l.module LIKE '%blog%' AND l.action NOT LIKE '%view%') AS Blog_NV<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.userid = u.id AND l.module LIKE '%assignment%') AS Assignment<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.userid = u.id AND l.module LIKE '%assignment%' AND l.action NOT LIKE '%view%') AS Assignment_NV<br />
FROM prefix_role_assignments AS ra <br />
JOIN prefix_user AS u ON u.id = ra.userid <br />
WHERE ra.roleid = 3 <br />
GROUP BY ra.userid<br />
</code><br />
<br />
===List all the certificates issued, sort by variables in the custom profile fields===<br />
Note: The SQL queries look intimidating at first, but isn't really that difficult to learn. I've seen in the forums that users wanted to do 'site-wide' groups in 1.9x. This is sort of the idea. It pulls all the certificates issued to all users sorted by the custom profile fields, which in my case is the Units or Depts (i.e. my site wide groups). Why certificates? I've explored with both grades and quizzes, the course admins are not really interested in the actual grades but whether the learner received a certificate (i.e. passed the course with x, y, z activities). It also saves me from creating groups and assigning them into the right groups. Even assigning in bulk is not efficient, since I have upward of 25 groups per course and constantly new learners enrolling in courses. The limitation is something to do with the server? as it only pull 5000 rows of data. If anyone figured out how to change this, please let me know. In the meantime, the work around is to pull only a few units/depts at a time to limit the number of rows. This is fine at the moment, since each course admin are only responsible for certain units/depts.<br />
<br />
<code sql><br />
SELECT<br />
DATE_FORMAT( FROM_UNIXTIME(prefix_certificate_issues.timecreated), '%Y-%m-%d' ) AS Date,<br />
prefix_certificate_issues.classname AS Topic,<br />
prefix_certificate.name AS Certificate,<br />
prefix_certificate_issues.studentname as Name,<br />
prefix_user_info_data.data AS Units<br />
<br />
FROM<br />
prefix_certificate_issues<br />
<br />
INNER JOIN prefix_user_info_data<br />
on prefix_certificate_issues.userid = prefix_user_info_data.userid<br />
<br />
INNER JOIN prefix_certificate<br />
on prefix_certificate_issues.certificateid = prefix_certificate.id<br />
<br />
WHERE prefix_user_info_data.data='Unit 1'<br />
OR prefix_user_info_data.data='Unit 2'<br />
OR prefix_user_info_data.data='Unit 3'<br />
<br />
ORDER BY Units, Name, Topic ASC<br />
</code><br />
<br />
<br />
=== All Simple Certificates Earned in the Site===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
Basic report of all certificates earned with the Simple Certificate plugin module in the whole site, sorted by most recent first. (Note: this uses the MySQL [http://www.mysqltutorial.org/mysql-date_format/ DATE_FORMAT] function.)<br />
<br />
<code sql><br />
SELECT<br />
CONCAT (u.firstname, ' ',u.lastname) As 'User',<br />
c.fullname AS 'Course',<br />
sc.name AS 'Certificate',<br />
DATE_FORMAT( FROM_UNIXTIME(sci.timecreated), '%Y-%m-%d' ) As 'Date Awarded'<br />
# sci.code 'CertificateId'<br />
FROM prefix_simplecertificate_issues sci<br />
JOIN prefix_user u ON sci.userid = u.id<br />
JOIN prefix_simplecertificate sc ON sci.certificateid = sc.id<br />
JOIN prefix_course AS c ON sc.course = c.id<br />
ORDER BY sci.timecreated DESC<br />
</code><br />
<br />
If you want to limit this to the most recent ones, you can add a condition to limit it to a certain number of days past. For example, adding this WHERE clause (above the ORDER BY) will show only those earned in the last 30 days:<br />
<code sql><br />
WHERE DATEDIFF(NOW(),FROM_UNIXTIME(sci.timecreated) ) < 30<br />
</code><br />
<br />
===Counter Blog usage in Courses,system wide===<br />
What teachers in what courses, uses blogs and how many + student count in that course.<br />
<code sql><br />
<br />
SELECT ( @counter := @counter+1) as counter, <br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') as Course<br />
<br />
,( SELECT DISTINCT CONCAT(u.firstname,' ',u.lastname)<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_user AS u ON ra.userid = u.id<br />
JOIN prefix_context AS ctx ON ctx.id = ra.contextid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id AND ctx.contextlevel = 50 LIMIT 1) AS Teacher<br />
<br />
,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
WHERE cm.course = c.id AND m.name LIKE '%blog%') AS Blogs<br />
<br />
,(SELECT Count( ra.userid ) AS Users FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = c.id) AS Students<br />
<br />
FROM prefix_course AS c, (SELECT @counter := 0) as s_init<br />
WHERE c.category IN ( 8,13,15)<br />
HAVING Blogs > 0<br />
ORDER BY Blogs DESC<br />
</code><br />
<br />
=== Elluminate (Blackboard Collaborate) - system wide usage===<br />
<code sql><br />
SELECT e.name As Session ,er.recordingsize<br />
,c.fullname As Course<br />
,u.firstname,u.lastname <br />
,DATE_FORMAT(FROM_UNIXTIME(e.timestart),'%d-%m-%Y') AS dTimeStart<br />
,concat('<a target="_new" href="%%WWWROOT%%/moodle/mod/elluminate/loadrecording.php?id=',er.id,'">Show</a>') AS RecordedSession<br />
<br />
FROM prefix_elluminate_recordings AS er<br />
JOIN prefix_elluminate AS e ON e.meetingid = er.meetingid<br />
JOIN prefix_course as c ON c.id = e.course<br />
JOIN prefix_user AS u ON u.id = e.creator <br />
ORDER BY er.recordingsize DESC<br />
</code><br />
<br />
<br />
=== Choice ===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
Results of the Choice activity. For all courses, shows course shortname, username, the Choice text, and the answer chosen by the user.<br />
<br />
<code sql><br />
SELECT c.shortname AS course, u.username, h.name as question, o.text AS answer<br />
FROM prefix_choice AS h<br />
JOIN prefix_course AS c ON h.course = c.id<br />
JOIN prefix_choice_answers AS a ON h.id = a.choiceid<br />
JOIN prefix_user AS u ON a.userid = u.id<br />
JOIN prefix_choice_options AS o ON a.optionid = o.id<br />
</code><br />
<br />
=== Assignment type usage in courses ===<br />
<code sql><br />
SELECT <br />
<br />
CONCAT('<a target="_new" href="%%WWWROOT%%/mod/assign/index.php?id=',c.id,'">',c.fullname,'</a>') AS "List assignments"<br />
<br />
,(SELECT COUNT(*) FROM prefix_assign WHERE c.id = course) AS Assignments<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_assign_plugin_config AS apc<br />
JOIN prefix_assign AS iassign ON iassign.id = apc.assignment <br />
WHERE iassign.course = c.id AND apc.plugin = 'file' AND apc.subtype = 'assignsubmission' AND apc.name = 'enabled' AND apc.value = '1'<br />
#GROUP BY apc.plugin<br />
) AS "File Assignments"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_assign_plugin_config AS apc<br />
JOIN prefix_assign AS iassign ON iassign.id = apc.assignment <br />
WHERE iassign.course = c.id AND apc.plugin = 'onlinetext' AND apc.subtype = 'assignsubmission' AND apc.name = 'enabled' AND apc.value = '1'<br />
) AS "Online Assignments"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_assign_plugin_config AS apc<br />
JOIN prefix_assign AS iassign ON iassign.id = apc.assignment <br />
WHERE iassign.course = c.id AND apc.plugin = 'pdf' AND apc.subtype = 'assignsubmission' AND apc.name = 'enabled' AND apc.value = '1'<br />
) AS "PDF Assignments"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_assign_plugin_config AS apc<br />
JOIN prefix_assign AS iassign ON iassign.id = apc.assignment <br />
WHERE iassign.course = c.id AND apc.plugin = 'offline' AND apc.subtype = 'assignsubmission' AND apc.name = 'enabled' AND apc.value = '1'<br />
) AS "Offline Assignments"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_assign_plugin_config AS apc<br />
JOIN prefix_assign AS iassign ON iassign.id = apc.assignment <br />
WHERE iassign.course = c.id AND apc.plugin = 'comments' AND apc.subtype = 'assignsubmission' AND apc.name = 'enabled' AND apc.value = '1'<br />
) AS "Assignments Comments"<br />
<br />
FROM prefix_assign AS assign<br />
JOIN prefix_course AS c ON c.id = assign.course<br />
GROUP BY c.id <br />
</code><br />
<br />
==Moodle Learning Analytics Reports==<br />
<br />
===Average Cognitive Depth and Social Breadth===<br />
<br />
Here is a simple SQL snippet to calculate average cognitive depth and social breadth indicators for all students in the system. This one ignores indicator values of 0, as they are nulls as defined in this model.<br />
Contributed by Elizabeth Dalton, Moodle HQ<br />
<br />
<code sql><br />
SELECT<br />
<br />
i.contextid,<br />
i.sampleid,<br />
<br />
TRUNC(AVG(CASE<br />
WHEN i.indicator LIKE '%cognitive%' THEN i.value <br />
ELSE '0'<br />
END),2) AS "Average Cognitive Depth",<br />
<br />
TRUNC(AVG(CASE<br />
WHEN i.indicator LIKE '%social%' THEN i.value <br />
ELSE '0'<br />
END),2) AS "Average Social Breadth"<br />
<br />
FROM prefix_analytics_indicator_calc as i<br />
WHERE<br />
i.value != 0<br />
GROUP BY i.contextid, i.sampleid<br />
</code><br />
<br />
==Assignment Module Reports==<br />
===All Ungraded Assignments===<br />
<br />
'''NOTE: This query is for the deprecated old Assignment module from Moodle 2.2, not the new Assignments module. Please update this query if you are the author or it will be removed as the 2.2 Assignment module is no longer supported since release 2.7.<br />
''' See: [https://docs.moodle.org/dev/Moodle_2.7_release_notes#Assignment]<br />
<br />
Returns all the submitted assignments that still need grading<br />
<code sql><br />
select <br />
u.firstname AS "First",<br />
u.lastname AS "Last",<br />
c.fullname AS "Course",<br />
a.name AS "Assignment"<br />
<br />
from prefix_assignment_submissions as asb<br />
join prefix_assignment as a ON a.id = asb.assignment<br />
join prefix_user as u ON u.id = asb.userid<br />
join prefix_course as c ON c.id = a.course<br />
join prefix_course_modules as cm ON c.id = cm.course<br />
<br />
where asb.grade < 0 and cm.instance = a.id<br />
and cm.module = 1<br />
<br />
order by c.fullname, a.name, u.lastname<br />
</code><br />
<br />
===All Ungraded Assignments w/ Link===<br />
<br />
'''NOTE: This query is for the deprecated old Assignment module from Moodle 2.2, not the new Assignments module. Please update this query if you are the author or it will be removed as the 2.2 Assignment module is no longer supported since release 2.7.<br />
''' See: [https://docs.moodle.org/dev/Moodle_2.7_release_notes#Assignment]<br />
<br />
<br />
Returns all the submitted assignments that still need grading, along with a link that goes directly to the submission to grade it. The links work if you view the report within Moodle.<br />
<code sql><br />
select <br />
u.firstname AS "First",<br />
u.lastname AS "Last",<br />
c.fullname AS "Course",<br />
a.name AS "Assignment",<br />
<br />
'<a href="http://education.varonis.com/mod/assignment/submissions.php' + char(63) +<br />
+ 'id=' + cast(cm.id as varchar) + '&userid=' + cast(u.id as varchar) <br />
+ '&mode=single&filter=0&offset=2">' + a.name + '</a>'<br />
AS "Assignmentlink"<br />
<br />
<br />
from prefix_assignment_submissions as asb<br />
join prefix_assignment as a ON a.id = asb.assignment<br />
join prefix_user as u ON u.id = asb.userid<br />
join prefix_course as c ON c.id = a.course<br />
join prefix_course_modules as cm ON c.id = cm.course<br />
<br />
where asb.grade < 0 and cm.instance = a.id and cm.module = 1<br />
<br />
order by c.fullname, a.name, u.lastname<br />
</code><br />
<br />
===Assignments (and Quizzes) waiting to be graded===<br />
<br />
'''NOTE: This query is for the deprecated old Assignment module from Moodle 2.2, not the new Assignments module. Please update this query if you are the author or it will be removed as the 2.2 Assignment module is no longer supported since release 2.7.<br />
''' See: [https://docs.moodle.org/dev/Moodle_2.7_release_notes#Assignment]<br />
<br />
<br />
This report requires a YEAR filter to be added (Available when using the latest block/configurable_reports)<br />
<br />
Which you can always remove, to make this query work on earlier versions.<br />
<br />
The report includes: <br />
*number of quizzes<br />
*unFinished Quiz attempts<br />
*Finished Quiz attempts<br />
*number of students<br />
*number of Assignments<br />
*number of submitted answers by students <br />
*number of unchecked assignments (waiting for the Teacher) in a Course.<br />
<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS Course<br />
<br />
,(SELECT CONCAT(u.firstname,' ', u.lastname) AS Teacher<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS Teacher <br />
<br />
,concat('<a target="_new" href="%%WWWROOT%%/mod/assignment/index.php?id=',c.id,'">מטלות</a>') AS Assignments<br />
<br />
,concat('<a target="_new" href="%%WWWROOT%%/mod/quiz/index.php?id=',c.id,'">בחנים</a>') AS 'Quizzes'<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_course_modules cm <br />
JOIN prefix_modules as m ON m.id = cm.module <br />
WHERE m.name LIKE 'quiz' AND cm.course = c.id <br />
GROUP BY cm.course <br />
) AS 'nQuizzes'<br />
<br />
,(SELECT COUNT(*)<br />
FROM prefix_quiz_attempts AS qa<br />
JOIN prefix_quiz AS q ON q.id = qa.quiz<br />
WHERE q.course = c.id<br />
AND qa.timefinish = 0<br />
GROUP BY q.course) AS 'unFinished Quiz attempts'<br />
<br />
,(SELECT COUNT(*)<br />
FROM prefix_quiz_attempts AS qa<br />
JOIN prefix_quiz AS q ON q.id = qa.quiz<br />
WHERE q.course = c.id<br />
AND qa.timefinish > 0<br />
GROUP BY q.course) AS 'finished quiz attempts'<br />
<br />
,(SELECT Count( ra.userid ) AS Users<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5<br />
AND ctx.instanceid = c.id<br />
) AS nStudents<br />
<br />
<br />
,(<br />
SELECT count(a.id)<br />
FROM prefix_assignment AS a <br />
JOIN prefix_course_modules AS cm ON a.course = cm.course <br />
WHERE cm.instance = a.id AND cm.module = 1 AND a.course = c.id<br />
) nAssignments<br />
<br />
,(<br />
SELECT count(*)<br />
FROM prefix_assignment AS a <br />
WHERE a.course = c.id AND FROM_UNIXTIME(a.timedue) > NOW()<br />
GROUP BY a.course<br />
) 'Open <br/>Assignments'<br />
<br />
, CONCAT(ROUND( (100 / iAssignments ) * iOpenAssignments ) ,'%') 'unFinished <br/>Assignments <br/>(percent)'<br />
<br />
,(<br />
SELECT count(asb.id)<br />
FROM prefix_assignment_submissions AS asb<br />
JOIN prefix_assignment AS a ON a.id = asb.assignment<br />
JOIN prefix_course_modules AS cm ON a.course = cm.course <br />
WHERE asb.grade < 0 AND cm.instance = a.id AND cm.module = 1 AND a.course = c.id<br />
) 'unChecked <br/>Submissions' <br />
<br />
,(<br />
SELECT count(asb.id)<br />
FROM prefix_assignment_submissions AS asb<br />
JOIN prefix_assignment AS a ON a.id = asb.assignment<br />
JOIN prefix_course_modules AS cm ON a.course = cm.course <br />
WHERE cm.instance = a.id AND cm.module = 1 AND a.course = c.id<br />
) 'Submitted <br/>Assignments'<br />
<br />
FROM prefix_course AS c<br />
LEFT JOIN (<br />
SELECT course, count(*) AS iAssignments<br />
FROM prefix_assignment AS a <br />
GROUP BY a.course <br />
) AS tblAssignmentsCount ON tblAssignmentsCount.course = c.id<br />
<br />
LEFT JOIN (<br />
SELECT course, count(*) AS iOpenAssignments<br />
FROM prefix_assignment AS a <br />
WHERE FROM_UNIXTIME(a.timedue) > NOW()<br />
GROUP BY a.course <br />
) AS tblOpenAssignmentsCount ON tblOpenAssignmentsCount.course = c.id<br />
<br />
WHERE 1=1 <br />
#AND c.fullname LIKE '%תשעג%'<br />
%%FILTER_YEARS:c.fullname%%<br />
## You can enable the SEMESTER filter as well, <br />
## by uncommenting the following line:<br />
## %%FILTER_SEMESTERS:c.fullname%%<br />
ORDER BY 'Open <br/>Assignments' DESC<br />
</code><br />
<br />
===Rubrics without zero values in criteria===<br />
Contributed by Eric Strom<br />
<br />
Rubric calculations in Moodle can fail to align with instructors expectations if they lack a zero value for each criterion used in the assessment. From documentation at https://docs.moodle.org/32/en/Rubrics#Grade_calculation:<br />
<br />
"For example, when the teacher in the previous example chose both levels with 1 point, the plain sum would be 2 points. But that is actually the lowest possible score so it maps to the grade 0 in Moodle.<br />
TIP: To avoid confusion from this sort of thing, we recommend including a level with 0 points in every rubric criterion."<br />
<br />
This report identifies rubrics having criteria without a zero value level and the courses they live in. This also refines to only assignments with active rubrics that are visible to students in the course. Links to the each rubric id is the direct link to edit the rubric. Fix by adding a zero level for each criteria that is missing it. In general, the grading changes that result will be in the students' favor.<br />
<br />
Includes search filter of course idnumber.<br />
<br />
<code sql><br />
SELECT cat.name AS Department, concat('<a target="_new" href="%%WWWROOT%%/course/view.php',CHAR(63),'id=',<br />
c.id,'">',c.idnumber,'</a>') AS Course_ID, <br />
c.fullname AS Course_Name, <br />
concat('<a target="_new" href="%%WWWROOT%%/grade/grading/form/rubric/edit.php',CHAR(63),'areaid=',gd.areaid,'">',gd.areaid,'</a>') AS Rubric<br />
FROM prefix_course AS c<br />
JOIN prefix_course_categories AS cat <br />
ON cat.id = c.category<br />
JOIN prefix_course_modules AS cm <br />
ON c.id=cm.course<br />
JOIN prefix_context AS ctx <br />
ON cm.id = ctx.instanceid<br />
JOIN prefix_grading_areas AS garea <br />
ON ctx.id = garea.contextid<br />
JOIN prefix_grading_definitions AS gd <br />
ON garea.id = gd.areaid<br />
JOIN prefix_gradingform_rubric_criteria AS crit <br />
ON gd.id = crit.definitionid<br />
JOIN prefix_gradingform_rubric_levels AS levels <br />
ON levels.criterionid = crit.id<br />
WHERE cm.visible='1' AND garea.activemethod = 'rubric' AND (crit.id NOT IN<br />
(SELECT crit.id<br />
FROM prefix_gradingform_rubric_criteria AS crit<br />
JOIN prefix_gradingform_rubric_levels AS levels <br />
ON levels.criterionid = crit.id WHERE levels.score = '0'))<br />
<br />
GROUP BY Rubric<br />
ORDER BY Course_ID, Rubric<br />
<br />
%%FILTER_SEARCHTEXT:c.idnumber:~%%<br />
</code><br />
<br />
===Who is using "Single File Upload" assignment===<br />
<code sql><br />
SELECT <br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS Course<br />
<br />
,(SELECT CONCAT(u.firstname,' ', u.lastname) AS Teacher<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS Teacher <br />
<br />
,ass.name as "Assignment Name"<br />
<br />
FROM <br />
prefix_assignment as ass<br />
<br />
JOIN <br />
prefix_course as c ON c.id = ass.course<br />
<br />
WHERE `assignmenttype` LIKE 'uploadsingle'<br />
</code><br />
<br />
==Feedback Module Reports==<br />
===List the answers to all the Feedback activities within the current course, submitted by the current user===<br />
<code sql><br />
SELECT /* crs.fullname as "Course name", f.name AS "Journal name", CONCAT(u.firstname,' ',UPPER(u.lastname)) as "Participant", */ /* include these fields if you want to check the composition of the recordset */<br />
DATE_FORMAT(FROM_UNIXTIME(c.timemodified),'%W %e %M, %Y') as "Answer Date",<br />
CASE i.typ WHEN 'label' THEN i.presentation ELSE i.name END as "Topic", /* usually labels are used as section titles, so you'd want them present in the recordset */<br />
v.value as "My Answer"<br />
<br />
FROM prefix_feedback AS f<br />
INNER JOIN prefix_course as crs on crs.id=f.course %%FILTER_COURSES:f.course%% <br />
INNER JOIN prefix_feedback_item AS i ON f.id=i.feedback<br />
INNER JOIN prefix_feedback_completed AS c on f.id=c.feedback %%FILTER_COURSEUSER:c.userid%% <br />
LEFT JOIN prefix_feedback_value AS v on v.completed=c.id AND v.item=i.id<br />
INNER JOIN prefix_user AS u on c.userid=u.id<br />
<br />
WHERE c.id = %%COURSEID%% AND u.id = %%USERID%% AND c.anonymous_response = 1 /* This clause limits the recordset to the current course and the current user and includes/ excludes the anonymous responses as needed */<br />
<br />
ORDER BY f.id, c.timemodified, i.id<br />
</code><br />
<br />
===Show all Feedbacks from all courses for all users including showing names of anonymous users===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
Shows all Feedbacks in all Courses with all multi-choice questions and answers of all users including showing the username of anonymous users. Also shows tryly anonymous users on the front page as 'Not-logged-in' users. This is a rough report, not a pretty report, and is limited to multiple-choice type questions, but is shows the answer number and the list of possible answers in raw form. I post it here as a basis for further reports, and also as away to get the identities of anonymous users if needed.<br />
<br />
<code sql><br />
SELECT <br />
c.shortname AS Course, <br />
f.name AS Feedback,<br />
# i.id AS Itemid,<br />
i.name AS Itemname,<br />
i.label AS Itemlabel,<br />
CASE <br />
WHEN f.anonymous = 1 AND u.id != 0 THEN CONCAT(u.username, ' :ANON')<br />
WHEN fc.userid = 0 THEN 'Not-logged-in'<br />
ELSE u.username<br />
END AS 'User',<br />
DATE_FORMAT(FROM_UNIXTIME(fc.timemodified),'%Y-%m-%d %H:%i') AS "Completed",<br />
v.value AS "Choice",<br />
CASE <br />
WHEN i.typ = 'multichoice' THEN<br />
IF ( SUBSTRING(i.presentation,1,6)='d>>>>>',<br />
SUBSTRING(i.presentation,7),<br />
i.presentation)<br />
ELSE i.presentation<br />
END AS "Answers",<br />
i.typ,<br />
i.dependitem,<br />
i.dependvalue<br />
<br />
FROM prefix_feedback f<br />
JOIN prefix_course c ON c.id=f.course <br />
JOIN prefix_feedback_item AS i ON f.id=i.feedback<br />
JOIN prefix_feedback_completed fc ON f.id=fc.feedback<br />
LEFT JOIN prefix_feedback_value v ON v.completed=fc.id AND v.item=i.id<br />
LEFT JOIN prefix_user AS u ON fc.userid=u.id<br />
WHERE i.typ != 'pagebreak'<br />
</code><br />
<br />
==Resource Module Reports==<br />
===List "Recently uploaded files"===<br />
see what users are uploading<br />
<code sql><br />
SELECT FROM_UNIXTIME(time,'%Y %M %D %h:%i:%s') as time ,ip,userid,url,info <br />
FROM `prefix_log` <br />
WHERE `action` LIKE 'upload' <br />
ORDER BY `prefix_log`.`time` DESC<br />
</code><br />
<br />
===List Courses that loaded a specific file: "X"===<br />
Did the Teacher (probably) uploaded course's Syllabus ?<br />
<code sql><br />
SELECT c.id, c.fullname FROM `prefix_log` as l <br />
JOIN prefix_course as c ON c.id = l.course <br />
WHERE `action` LIKE '%upload%' AND ( info LIKE '%Syllabus%' OR info LIKE '%Sylabus%' ) GROUP BY c.id<br />
</code><br />
<br />
===All resources that link to some specific external website===<br />
+ link to course<br />
+ who's the teacher<br />
+ link to external resource<br />
<code sql><br />
SELECT<br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS Course<br />
,c.shortname,r.name<br />
,(SELECT CONCAT(u.firstname,' ', u.lastname) AS Teacher<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS Teacher<br />
,concat('<a target="_new" href="%%WWWROOT%%/mod/resource/view.php?id=',r.id,'">',r.name,'</a>') AS Resource<br />
FROM prefix_resource AS r <br />
JOIN prefix_course AS c ON r.course = c.id<br />
WHERE r.reference LIKE 'http://info.oranim.ac.il/home%' <br />
</code><br />
<br />
==="Compose Web Page" RESOURCE count===<br />
<code sql><br />
SELECT course,prefix_course.fullname, COUNT(*) AS Total<br />
FROM `prefix_resource`<br />
JOIN `prefix_course` ON prefix_course.id = prefix_resource.course<br />
WHERE type='html'<br />
GROUP BY course<br />
</code><br />
<br />
===Resource count in courses===<br />
+ (First)Teacher name<br />
+ Where course is inside some specific Categories<br />
<code sql><br />
SELECT <br />
COUNT(*) AS count<br />
,r.course <br />
,c.shortname shortname<br />
,c.fullname coursename<br />
,( SELECT DISTINCT CONCAT(u.firstname,' ',u.lastname)<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_user as u ON ra.userid = u.id<br />
JOIN prefix_context AS ctx ON ctx.id = ra.contextid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = r.course AND ctx.contextlevel = 50 LIMIT 1) AS Teacher<br />
FROM prefix_resource r <br />
JOIN prefix_course c ON r.course = c.id<br />
WHERE c.category IN (10,13,28,18,26)<br />
GROUP BY r.course<br />
ORDER BY COUNT(*) DESC<br />
</code><br />
<br />
===Delete all the automated backup files===<br />
Prepare bash cli script to delete all the automated backup files on the file system. (clean up some disk space)<br />
<code sql><br />
SELECT CONCAT( 'rm -f /var/moodledatanew/filedir/', SUBSTRING( contenthash, 1, 2 ) , '/', SUBSTRING( contenthash, 3, 2 ) , '/', contenthash ) <br />
FROM `mdl_files` <br />
WHERE `filename` LIKE '%mbz%'<br />
AND filearea = 'automated'<br />
</code><br />
<br />
Find out how much disk space is used by all automated backup files:<br />
<code sql><br />
SELECT SUM(filesize)/(1024*1024*1024) FROM `mdl_files` WHERE `filename` LIKE '%mbz%' AND filearea = 'automated'<br />
</code><br />
<br />
==Forum Module Reports==<br />
===print all User's post in course Forums===<br />
%%COURSEID%% is a variable the is replace by the current CourseID you are running the sql report from. if you are using the latest block/configurable_reports ! (You can always change it to a fixed course or remove it to display all courses.)<br />
<code sql><br />
SELECT <br />
concat('<a target="_new" href="%%WWWROOT%%/mod/forum/user.php?course=',c.id,'&id=',u.id,'&mode=posts">',CONCAT(u.firstname,' ', u.lastname),'</a>') As Fullname<br />
,concat('<a target="_new" href="%%WWWROOT%%/mod/forum/view.php?f=',fd.forum,'">',f.name,'</a>') AS Forum<br />
,count(*) as Posts<br />
,(SELECT count(*) FROM prefix_forum_discussions AS ifd JOIN prefix_forum as iforum ON iforum.id = ifd.forum WHERE ifd.userid = fp.userid AND iforum.id = f.id) AS cAllDiscussion<br />
<br />
FROM prefix_forum_posts AS fp <br />
JOIN prefix_user as u ON u.id = fp.userid <br />
JOIN prefix_forum_discussions AS fd ON fp.discussion = fd.id <br />
JOIN prefix_forum AS f ON f.id = fd.forum <br />
JOIN prefix_course as c ON c.id = fd.course <br />
WHERE fd.course = %%COURSEID%% <br />
GROUP BY f.id,u.id<br />
ORDER BY u.id<br />
</code><br />
<br />
===FORUM use Count per COURSE -- not including NEWS Forum!===<br />
<code sql><br />
SELECT prefix_course.fullname, prefix_forum.course, count(*) as total FROM prefix_forum<br />
INNER JOIN prefix_course<br />
ON prefix_course.id = prefix_forum.course<br />
WHERE NOT(prefix_forum.type = 'news')<br />
GROUP BY prefix_forum.course<br />
ORDER BY total desc<br />
</code><br />
<br />
===FORUM use Count per COURSE by type -- not including NEWS Forum!===<br />
<code sql><br />
SELECT prefix_course.fullname, prefix_forum.course, prefix_forum.type, count(*) as total FROM prefix_forum<br />
INNER JOIN prefix_course<br />
ON prefix_course.id = prefix_forum.course<br />
WHERE NOT(prefix_forum.type = 'news')<br />
GROUP BY prefix_forum.course,prefix_forum.type<br />
ORDER BY total desc<br />
</code><br />
<br />
===Forum activity - system wide===<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.id,'</a>') AS CourseID<br />
,( SELECT DISTINCT CONCAT(u.firstname,' ',u.lastname)<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_user AS u ON ra.userid = u.id<br />
JOIN prefix_context AS ctx ON ctx.id = ra.contextid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id AND ctx.contextlevel = 50 LIMIT 1) AS Teacher<br />
,c.fullname as Course<br />
,f.type<br />
,(SELECT Count( ra.userid ) AS Users FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = c.id) AS Students<br />
, fd.forum, f.name,count(*) AS cPostAndDisc<br />
,(SELECT count(*) FROM prefix_forum_discussions AS ifd WHERE ifd.forum = f.id) AS cDiscussion<br />
FROM prefix_forum_posts AS fp<br />
JOIN prefix_forum_discussions AS fd ON fd.id = fp.discussion<br />
JOIN prefix_forum AS f ON f.id = fd.forum<br />
JOIN prefix_course AS c ON c.id = f.course<br />
WHERE f.type != 'news' AND c.fullname LIKE '%2013%'<br />
## WHERE 1=1 <br />
## %%FILTER_YEARS:c.fullname%%<br />
## You can enable the SEMESTER filter as well, <br />
## by uncommenting the following line:<br />
## %%FILTER_SEMESTERS:c.fullname%%<br />
<br />
GROUP BY fd.forum<br />
ORDER BY count( * ) DESC<br />
</code><br />
<br />
===Activity In Forums===<br />
Trying to figure out how much real activity we have in Forums by aggregating:<br />
Users in Course, Number of Posts, Number of Discussions, Unique student post, Unique student discussions, Number of Teachers , Number of Students, ratio between unique Student posts and the number of students in the Course...<br />
<code sql><br />
SELECT c.fullname,f.name,f.type <br />
,(SELECT count(id) FROM prefix_forum_discussions as fd WHERE f.id = fd.forum) as Discussions<br />
,(SELECT count(distinct fd.userid) FROM prefix_forum_discussions as fd WHERE fd.forum = f.id) as UniqueUsersDiscussions<br />
,(SELECT count(fp.id) FROM prefix_forum_discussions fd JOIN prefix_forum_posts as fp ON fd.id = fp.discussion WHERE f.id = fd.forum) as Posts<br />
,(SELECT count(distinct fp.userid) FROM prefix_forum_discussions fd JOIN prefix_forum_posts as fp ON fd.id = fp.discussion WHERE f.id = fd.forum) as UniqueUsersPosts<br />
,(SELECT Count( ra.userid ) AS Students<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid =5<br />
AND ctx.instanceid = c.id<br />
) AS StudentsCount<br />
,(SELECT Count( ra.userid ) AS Teachers<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid =3<br />
AND ctx.instanceid = c.id<br />
) AS 'Teacher<br/>Count'<br />
,(SELECT Count( ra.userid ) AS Users<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid IN (3,5)<br />
AND ctx.instanceid = c.id<br />
) AS UserCount<br />
, (SELECT (UniqueUsersDiscussions / StudentsCount )) as StudentDissUsage<br />
, (SELECT (UniqueUsersPosts /StudentsCount)) as StudentPostUsage<br />
FROM prefix_forum as f <br />
JOIN prefix_course as c ON f.course = c.id<br />
WHERE `type` != 'news'<br />
ORDER BY StudentPostUsage DESC<br />
</code><br />
<br />
===All Forum type:NEWS===<br />
<code sql><br />
SELECT f.id, f.name<br />
FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_forum AS f ON cm.instance = f.id<br />
WHERE m.name = 'forum'<br />
AND f.type = 'news'<br />
</code><br />
<br />
===All new forum NEWS items (discussions) from all my Courses===<br />
change "userid = 26" and "id = 26" to a new user id<br />
<code sql><br />
SELECT c.shortname,f.name,fd.name,FROM_UNIXTIME(fd.timemodified ,"%d %M %Y ") as Date<br />
FROM prefix_forum_discussions as fd <br />
JOIN prefix_forum as f ON f.id = fd.forum <br />
JOIN prefix_course as c ON c.id = f.course <br />
JOIN prefix_user_lastaccess as ul ON (c.id = ul.courseid AND ul.userid = 26)<br />
WHERE fd.timemodified > ul.timeaccess <br />
AND fd.forum IN (SELECT f.id<br />
FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_forum AS f ON cm.instance = f.id<br />
WHERE m.name = 'forum'<br />
AND f.type = 'news')<br />
AND c.id IN (SELECT c.id<br />
FROM prefix_course AS c<br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid<br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE u.id = 26) ORDER BY `fd`.`timemodified` DESC<br />
</code><br />
<br />
<br />
===News Forum - Discussions COUNT===<br />
Which is actually... How much instructions students get from their teachers<br />
<code sql><br />
SELECT c.shortname ,<br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS Course<br />
,( SELECT DISTINCT CONCAT(u.firstname,' ',u.lastname)<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_user AS u ON ra.userid = u.id<br />
JOIN prefix_context AS ctx ON ctx.id = ra.contextid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id AND ctx.contextlevel = 50 LIMIT 1) AS Teacher<br />
,concat('<a target="_new" href="%%WWWROOT%%/mod/forum/view.php?f=',fd.forum,'">',count(fd.id),'</a>') AS DiscussionsSum<br />
FROM prefix_forum_discussions AS fd<br />
INNER JOIN prefix_forum AS f ON f.id = fd.forum<br />
INNER JOIN prefix_course AS c ON c.id = f.course<br />
WHERE f.type = 'news' AND c.category IN (10,13,28,18,26)<br />
GROUP BY fd.forum<br />
ORDER BY count(fd.id) DESC<br />
</code><br />
<br />
===Cantidad de foros que han sido posteados por profesor===<br />
<br />
(Number of forums that have been posted by teacher/Google translator)<br />
<br />
Queriamos saber cuales son las acciones del profesor dentro de los foros de cada curso, por ello se hizo este informe.<br />
<br />
(We wanted to know what the teacher's actions are in the forums of each course, so this report was made. /Google translator)<br />
<code sql><br />
SELECT <br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.shortname,'</a>') AS curso,<br />
CONCAT(u.firstname ,' ',u.lastname) AS Facilitador,<br />
<br />
(SELECT COUNT( m.name ) AS COUNT FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
WHERE cm.course = c.id AND m.name LIKE '%forum%') AS foros,<br />
<br />
COUNT(*) AS Posts<br />
<br />
FROM prefix_forum_posts AS fp <br />
JOIN prefix_forum_discussions AS fd ON fp.discussion = fd.id <br />
JOIN prefix_forum AS f ON f.id = fd.forum <br />
JOIN prefix_course AS c ON c.id = fd.course<br />
JOIN prefix_user AS u ON u.id = fp.userid <br />
<br />
WHERE fp.userid =<br />
(<br />
select distinct prefix_user.id<br />
from prefix_user <br />
join prefix_role_assignments as ra on ra.userid = prefix_user.id <br />
where ra.roleid = 3 <br />
and userid = fp.userid<br />
limit 1<br />
)<br />
<br />
and c.shortname like '%2014-2-1%'<br />
GROUP BY c.id, u.id<br />
</code><br />
<br />
<br />
===List all the Posts in all the Forums that got high rating===<br />
We setup a scale that let teachers and students Rate forum post with "Important, interesting, valuable, not rated" scale<br />
And then add a link to the following report at the begining of the course "Link to all interesting posts"<br />
<code sql><br />
SELECT <br />
CONCAT('<a target="_new" href="%%WWWROOT%%/mod/forum/view.php?f=',f.id,'">',f.name,'</a>') AS 'Forum name,<br />
CONCAT('<a target="_new" href="%%WWWROOT%%/mod/forum/discuss.php?d=',fd.id,'#p',fp.id,'">',fp.subject,'</a>') AS 'Post link',<br />
SUM(r.rating) AS 'Rating'<br />
FROM mdl_rating AS r<br />
JOIN mdl_forum_posts AS fp ON fp.id = r.itemid<br />
JOIN mdl_forum_discussions AS fd ON fd.id = fp.discussion<br />
JOIN mdl_forum AS f ON f.id = fd.forum<br />
WHERE r.component = 'mod_forum' AND r.ratingarea = 'post' AND f.course = %%COURSEID%%<br />
GROUP BY r.itemid<br />
ORDER BY SUM(r.rating) DESC<br />
</code><br />
<br />
===List all the Posts in all Discussions of a single Forum===<br />
This report is used to help export all the student's posts and discussions of a single forum, by passing the context module id as a parameter to the report using "&filter_var=cmid"<br />
<code sql><br />
SELECT <br />
CONCAT('<a target="_new" href="%%WWWROOT%%/mod/forum/view.php?f=', f.id, '">', f.name, '</a>') AS 'Forum name',<br />
fd.name AS 'Discussion', <br />
CONCAT('<a target="_new" href="%%WWWROOT%%/mod/forum/discuss.php?d=', fd.id, '#p', fp.id, '">', fp.subject, '</a>') AS 'Post (link)',<br />
fp.message<br />
<br />
FROM mdl_forum_posts AS fp <br />
JOIN mdl_forum_discussions AS fd ON fd.id = fp.discussion<br />
JOIN mdl_forum AS f ON f.id = fd.forum<br />
JOIN mdl_course_modules AS cm ON cm.module = 9 AND cm.instance = f.id<br />
WHERE cm.id = %%FILTER_VAR%%<br />
ORDER BY f.id, fd.id<br />
</code><br />
<br />
==Quiz Module Reports==<br />
===Generate a list of instructors and their email addresses for those courses that has "essay questions" in their quizzes===<br />
<code sql><br />
SELECT qu.id AS quiz_id, qu.course AS course_id, qu.questions,<br />
co.fullname AS course_fullname, co.shortname AS course_shortname,<br />
qu.name AS quiz_name, FROM_UNIXTIME(qu.timeopen) AS quiz_timeopen, FROM_UNIXTIME(qu.timeclose) AS quiz_timeclose,<br />
u.firstname, u.lastname, u.email,<br />
FROM prefix_quiz qu, prefix_course co, prefix_role re, prefix_context ct, prefix_role_assignments ra, prefix_user u<br />
WHERE FROM_UNIXTIME(timeopen) > '2008-05-14' AND<br />
qu.course = co.id AND<br />
co.id = ct.instanceid AND<br />
ra.roleid = re.id AND<br />
re.name = 'Teacher' AND<br />
ra.contextid = ct.id AND<br />
ra.userid = u.id<br />
<br />
SELECT Count('x') As NumOfStudents<br />
FROM prefix_role_assignments a<br />
JOIN prefix_user u ON userid = u.id<br />
WHERE roleid = 5 AND contextid = (SELECT id FROM prefix_context WHERE instanceid = 668 AND contextlevel = 50)<br />
</code><br />
<br />
===Number of Quizes per Course===<br />
<code sql><br />
SELECT count(*)<br />
,concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS Course<br />
,concat('<a target="_new" href="%%WWWROOT%%/mod/quiz/index.php?id=',c.id,'">Link</a>') AS Quizes<br />
<br />
FROM prefix_course_modules cm<br />
JOIN prefix_course c ON c.id = cm.course<br />
JOIN prefix_modules as m ON m.id = cm.module<br />
WHERE m.name LIKE 'quiz'<br />
GROUP BY c.id<br />
</code><br />
<br />
===List all MultiAnswer (Cloze) Questions===<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/mod/quiz/attempt.php?q=', quiz.id, '">', quiz.name, '</a>') AS Quiz<br />
,question.id question_id, question.questiontext <br />
FROM prefix_question question<br />
JOIN prefix_quiz_question_instances qqi ON question.id = qqi.question<br />
JOIN prefix_quiz quiz ON qqi.quiz = quiz.id<br />
WHERE `qtype` LIKE 'multianswer'<br />
</code><br />
<br />
===List courses with MANUAL grades===<br />
Which is basically and indication to teachers using Moodle to hold offline grades inside Moodle's Gradebook,<br />
So grades could be uploaded into an administrative SIS. Use with Configurable Reports.<br />
<code sql><br />
SELECT COUNT( * )<br />
,concat('<a target="_new" href="%%WWWROOT%%/grade/edit/tree/index.php?showadvanced=1&id=',c.id,'">',c.fullname,'</a>') AS Course<br />
FROM prefix_grade_items AS gi<br />
JOIN prefix_course as c ON c.id = gi.courseid<br />
WHERE `itemtype` = 'manual'<br />
GROUP BY courseid<br />
</code><br />
===List the users that did not took the Quiz===<br />
Do not forget to change "c.id = 14" and q.name LIKE '%quiz name goes here%'<br />
<code sql><br />
SELECT<br />
user2.id AS ID,<br />
ul.timeaccess,<br />
user2.firstname AS Firstname,<br />
user2.lastname AS Lastname,<br />
user2.email AS Email,<br />
user2.username AS IDNumber,<br />
user2.institution AS Institution,<br />
<br />
IF (user2.lastaccess = 0,'never',<br />
DATE_FORMAT(FROM_UNIXTIME(user2.lastaccess),'%Y-%m-%d')) AS dLastAccess<br />
<br />
,(SELECT DATE_FORMAT(FROM_UNIXTIME(timeaccess),'%Y-%m-%d') FROM prefix_user_lastaccess WHERE userid=user2.id AND courseid=c.id) AS CourseLastAccess<br />
<br />
,(SELECT r.name<br />
FROM prefix_user_enrolments AS uenrol<br />
JOIN prefix_enrol AS e ON e.id = uenrol.enrolid<br />
JOIN prefix_role AS r ON e.id = r.id<br />
WHERE uenrol.userid=user2.id AND e.courseid = c.id) AS RoleName<br />
<br />
FROM prefix_user_enrolments AS ue<br />
JOIN prefix_enrol AS e ON e.id = ue.enrolid<br />
JOIN prefix_course AS c ON c.id = e.courseid<br />
JOIN prefix_user AS user2 ON user2 .id = ue.userid<br />
LEFT JOIN prefix_user_lastaccess AS ul ON ul.userid = user2.id<br />
WHERE c.id=14 and ue.userid NOT IN (SELECT qa.userid FROM prefix_quiz_attempts AS qa<br />
JOIN prefix_quiz AS q ON qa.quiz = q.id<br />
JOIN prefix_course AS c ON q.course = c.id<br />
WHERE c.id = 14 AND q.name LIKE '%quiz name goes here%')<br />
</code><br />
<br />
<br />
===List Questions in each Quiz===<br />
<br />
<code sql><br />
SELECT quiz.id,quiz.name, q.id, q.name<br />
FROM mdl_quiz AS quiz<br />
JOIN mdl_question AS q ON FIND_IN_SET(q.id, quiz.questions)<br />
WHERE quiz.course = %%COURSEID%%<br />
ORDER BY quiz.id ASC<br />
</code><br />
<br />
Note: this query does not work in Moodle 2.8. There is no mdl_quiz.questions field. It will need to be rewritten to use the usage/contextid organization.<br />
<br />
===Quiz activity research===<br />
This report was made to extract student full activity in quizzes for an academic research about adapting instructional design teaching methods in online learning. The students do not use the Quiz module as a standard quiz but more as Study booklets or mini courses with embedded questions and hints to assist students evaluate their progress (Similar to what you expect to find in a SCORM activity)<br />
<br />
<code sql><br />
SELECT <br />
cm.course "course_id", cm.id "moduel_id", q.id "quiz_id", q.name "quiz_name",<br />
<br />
CASE q.grademethod<br />
WHEN 1 THEN "GRADEHIGHEST"<br />
WHEN 2 THEN "GRADEAVERAGE"<br />
WHEN 3 THEN "ATTEMPTFIRST"<br />
WHEN 4 THEN "ATTEMPTLAST"<br />
END "grade method"<br />
<br />
, q.attempts "quiz_attempts_allowed", cm.groupmode "group_mode"<br />
, qa.id "attempt_id", qa.state "attempt_state", qa.sumgrades "attempt_grade", qg.grade "user_final_grade", q.grade "quiz_max_grade"<br />
,(SELECT GROUP_CONCAT(g.name) FROM mdl_groups AS g<br />
JOIN mdl_groups_members AS m ON g.id = m.groupid WHERE g.courseid = q.course AND m.userid = u.id) "user_groups",<br />
DATE_FORMAT(FROM_UNIXTIME(qa.timestart), '%d-%m-%Y %h:%k') "attempt_start",<br />
DATE_FORMAT(FROM_UNIXTIME(qa.timefinish), '%d-%m-%Y %h:%k') "attempt_finish",<br />
u.id "user_id", u.firstname, u.lastname,<br />
question.id "question_id", question.name "question_name",<br />
qas.state "question_step_state",qas.fraction "question_grade", qh.hint, question.qtype "question_type"<br />
<br />
FROM mdl_quiz as q<br />
JOIN mdl_course_modules as cm ON cm.instance = q.id and cm.module = 14 <br />
JOIN mdl_quiz_attempts qa ON q.id = qa.quiz<br />
LEFT JOIN mdl_quiz_grades as qg ON qg.quiz = q.id and qg.userid = qa.userid<br />
JOIN mdl_user as u ON u.id = qa.userid<br />
JOIN mdl_question_usages as qu ON qu.id = qa.uniqueid<br />
JOIN mdl_question_attempts as qatt ON qatt.questionusageid = qu.id<br />
JOIN mdl_question as question ON question.id = qatt.questionid<br />
JOIN mdl_question_attempt_steps as qas ON qas.questionattemptid = qatt.id<br />
LEFT JOIN mdl_question_hints as qh ON qh.questionid = q.id<br />
#WHERE q.id = "SOME QUIZ ID"<br />
WHERE cm.course = "SOME COURSE ID"<br />
</code><br />
<br />
===Quiz Usage in Courses by Date===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
This report lists the courses containing quizzes with the course start date between the two values, and provides a summary of the types of questions in the quizzes in each course and whether question randomization and answer randomization functions were used.<br />
<br />
"Multiple Choice" questions include true/false and matching question types.<br />
<br />
"Short Answer" are questions that accept a single phrase.<br />
<br />
"Other" questions include fixed numerical, calculated, essay, and various drag and drop types.<br />
<br />
"Min Quiz Age" and "Max Quiz Age" provide data about the last modified date for the quizzes in the course, compared to the course start date. The values are expressed in units of days. A negative value indicates that a quiz was edited after the start of the course. A value greater than 90 days indicates that the quiz may have been used in an earlier term (cohort) without modification.<br />
<br />
'''Note''': In Configurable Reports, the Date Filter is not applied until the "Apply" button is clicked.<br />
<br />
<code sql><br />
SELECT <br />
<br />
c.shortname AS 'Course'<br />
#, u.lastname AS 'Instructor'<br />
, COUNT(DISTINCT q.id) AS 'Quizzes'<br />
, COUNT(DISTINCT qu.id) AS 'Questions'<br />
, SUM(IF (qu.qtype = 'multichoice', 1, 0 )) + SUM(IF (qu.qtype = 'truefalse', 1, 0 )) + SUM(IF (qu.qtype = 'match', 1, 0 )) AS 'multichoice'<br />
<br />
, SUM(IF (qu.qtype = 'shortanswer', 1, 0 )) AS 'shortanswer'<br />
<br />
, COUNT( qu.id) - SUM(IF (qu.qtype = 'multichoice', 1, 0 )) - SUM(IF (qu.qtype = 'truefalse', 1, 0 )) - SUM(IF (qu.qtype = 'match', 1, 0 )) - SUM(IF (qu.qtype = 'shortanswer', 1, 0 )) AS 'Other'<br />
<br />
, (SUM(IF (qu.qtype = 'multichoice', 1, 0 )) + SUM(IF (qu.qtype = 'truefalse', 1, 0 )) + SUM(IF (qu.qtype = 'match', 1, 0 )))/COUNT( qu.id) AS 'Percent MC'<br />
<br />
#, SUM(IF (qu.qtype = 'numerical', 1, 0 )) AS 'numerical'<br />
#, SUM(IF (qu.qtype LIKE 'calc%', 1, 0 )) AS 'calculated'<br />
#, SUM(IF (qu.qtype = 'random', 1, 0 )) AS 'random'<br />
#, SUM(IF (qu.qtype = 'shortanswer', 1, 0 )) AS 'shortanswer'<br />
#, SUM(IF (qu.qtype = 'essay', 1, 0 )) AS 'essay'<br />
<br />
<br />
, IF(q.shufflequestions > 0,'Yes','No') AS 'Randomized Questions'<br />
, IF(q.shuffleanswers > 0,'Yes','No') AS 'Randomized Answers'<br />
<br />
#, FROM_UNIXTIME(c.startdate) AS 'Course Start Date'<br />
#, FROM_UNIXTIME(MIN(q.timemodified)) AS 'Last Modified'<br />
<br />
#, DATEDIFF(FROM_UNIXTIME(c.startdate),FROM_UNIXTIME(MIN(q.timemodified))) AS 'Quiz age'<br />
<br />
, MIN(DATEDIFF(FROM_UNIXTIME(c.startdate),FROM_UNIXTIME(q.timemodified))) AS 'Min Quiz Age' <br />
, MAX(DATEDIFF(FROM_UNIXTIME(c.startdate),FROM_UNIXTIME(q.timemodified))) AS 'Max Quiz Age' <br />
<br />
#, SUM(IF (DATEDIFF(FROM_UNIXTIME(c.startdate),FROM_UNIXTIME(q.timemodified)) < 90, 1,0)) AS 'new quizzes'<br />
<br />
FROM prefix_quiz AS q<br />
JOIN prefix_course AS c on c.id = q.course<br />
JOIN prefix_quiz_question_instances AS qqi ON qqi.quiz = q.id<br />
LEFT JOIN prefix_question AS qu ON qu.id = qqi.question<br />
<br />
WHERE<br />
1<br />
%%FILTER_STARTTIME:c.startdate:>%% %%FILTER_ENDTIME:c.startdate:<%%<br />
<br />
GROUP BY c.id<br />
<br />
ORDER BY c.shortname<br />
</code><br />
<br />
===Student responses (answers) to quiz questions===<br />
(Contributed by Juan F with help from Tim hunt and fellow Moodlers on the forums)<br />
A report that targets a specific quiz for all of our Biology courses, a summary of all questions and how many students get them right/wrong.<br />
<code sql><br />
SELECT<br />
concat( u.firstname, " ", u.lastname ) AS "Student Name",<br />
u.id,<br />
quiza.userid,<br />
q.course,<br />
q.name,<br />
quiza.attempt,<br />
qa.slot,<br />
que.questiontext AS 'Question',<br />
qa.rightanswer AS 'Correct Answer',<br />
qa.responsesummary AS 'Student Answer'<br />
<br />
FROM mdl_quiz_attempts quiza<br />
JOIN mdl_quiz q ON q.id=quiza.quiz<br />
JOIN mdl_question_usages qu ON qu.id = quiza.uniqueid<br />
JOIN mdl_question_attempts qa ON qa.questionusageid = qu.id<br />
JOIN mdl_question que ON que.id = qa.questionid<br />
JOIN mdl_user u ON u.id = quiza.userid<br />
<br />
WHERE q.name = "BIO 208 Post Test Assessment"<br />
AND q.course = "17926"<br />
<br />
ORDER BY quiza.userid, quiza.attempt, qa.slot<br />
</code><br />
<br />
==SCORM Activity Reports==<br />
<br />
===Lists All completed SCORM activites by Course name===<br />
This report will list all completed attempts for all SCORM activities. It is ordered first by Course name, then student's last name, then student's first name, then attempt number. Please note: the FROM_UNIXTIME command is for MySQL.<br />
<code sql><br />
SELECT u.firstname First,u.lastname Last,c.fullname Course, st.attempt Attempt,st.value Status,FROM_UNIXTIME(st.timemodified,"%m-%d-%Y") Date <br />
FROM prefix_scorm_scoes_track AS st <br />
JOIN prefix_user AS u ON st.userid=u.id<br />
JOIN prefix_scorm AS sc ON sc.id=st.scormid<br />
JOIN prefix_course AS c ON c.id=sc.course<br />
WHERE st.value='completed' <br />
ORDER BY c.fullname, u.lastname,u.firstname, st.attempt<br />
</code><br />
<br />
===Lists SCORM status for all enrolled users by Course name===<br />
This report will list the SCORM status for all users enrolled in the course. It is ordered first by Course name, then student's last name, then student's first name, then attempt number. This can be limited to individual courses by adding to the where clause the course id to report on. <br />
<code sql><br />
SELECT<br />
u.firstname AS First,<br />
u.lastname AS Last, <br />
u.idnumber AS Employee_ID, <br />
u.city AS City,<br />
uid.data AS State,<br />
u.country AS Country,<br />
g.name AS Group_name,<br />
c.fullname AS Course, <br />
st.attempt AS Attempt,<br />
st.value AS Status,<br />
FROM_UNIXTIME(st.timemodified,"%m-%d-%Y") AS Date <br />
<br />
FROM prefix_scorm_scoes_track AS st <br />
JOIN prefix_user AS u ON st.userid=u.id<br />
JOIN prefix_user_info_data AS uid ON uid.userid = u.id <br />
JOIN prefix_scorm AS sc ON sc.id=st.scormid<br />
JOIN prefix_course AS c ON c.id=sc.course<br />
JOIN prefix_groups AS g ON g.courseid = c.id<br />
JOIN prefix_groups_members AS m ON g.id = m.groupid<br />
<br />
WHERE st.element='cmi.core.lesson_status' AND m.userid=u.id<br />
<br />
UNION<br />
<br />
SELECT<br />
user2.firstname AS First,<br />
user2.lastname AS Last,<br />
user2. idnumber AS Employee_ID,<br />
user2.city AS City,<br />
uid.data AS State,<br />
user2.country AS Country,<br />
g.name AS Group_name,<br />
c.fullname AS Course,<br />
"-" AS Attempt,<br />
"not_started" AS Status,<br />
"-" AS Date<br />
<br />
FROM prefix_user_enrolments AS ue<br />
JOIN prefix_enrol AS e ON e.id = ue.enrolid<br />
JOIN prefix_course AS c ON c.id = e.courseid<br />
JOIN prefix_user AS user2 ON user2 .id = ue.userid<br />
JOIN prefix_user_info_data AS uid ON uid.userid = user2.id <br />
JOIN prefix_groups AS g ON g.courseid = c.id<br />
JOIN prefix_groups_members AS m ON g.id = m.groupid<br />
JOIN prefix_scorm AS sc ON sc.course=c.id<br />
Left Join prefix_scorm_scoes_track AS st on st.scormid=sc.id AND st.userid=user2.id<br />
<br />
WHERE st.timemodified IS NULL AND m.userid=user2.id<br />
<br />
ORDER BY Course, Last, First, Attempt<br />
<br />
</code><br />
<br />
== Badges==<br />
<br />
=== All badges issued, by User ===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
This report will show you all the badges on a site that have been issued, both site and all courses, by the username of each user issued a badge. Includes the type of criteria passed (activity, course completion, manual), date issued, date expires, and a direct link to that issued badge page so you can see all the other details for that badge.<br />
<br />
<code sql><br />
SELECT u.username, b.name AS badgename, <br />
CASE<br />
WHEN b.courseid IS NOT NULL THEN<br />
(SELECT c.shortname<br />
FROM prefix_course AS c<br />
WHERE c.id = b.courseid)<br />
WHEN b.courseid IS NULL THEN "*"<br />
END AS Context,<br />
CASE <br />
WHEN t.criteriatype = 1 AND t.method = 1 THEN "Activity Completion (All)"<br />
WHEN t.criteriatype = 1 AND t.method = 2 THEN "Activity Completion (Any)"<br />
WHEN t.criteriatype = 2 AND t.method = 2 THEN "Manual Award"<br />
WHEN t.criteriatype = 4 AND t.method = 1 THEN "Course Completion (All)"<br />
WHEN t.criteriatype = 4 AND t.method = 2 THEN "Course Completion (Any)"<br />
ELSE CONCAT ('Other: ', t.criteriatype)<br />
END AS Criteriatype,<br />
DATE_FORMAT( FROM_UNIXTIME( d.dateissued ) , '%Y-%m-%d' ) AS dateissued,<br />
DATE_FORMAT( FROM_UNIXTIME( d.dateexpire ), '%Y-%m-%d' ) AS dateexpires,<br />
CONCAT ('<a target="_new" href="%%WWWROOT%%/badges/badge.php?hash=',d.uniquehash,'">link</a>') AS Details<br />
FROM prefix_badge_issued AS d <br />
JOIN prefix_badge AS b ON d.badgeid = b.id<br />
JOIN prefix_user AS u ON d.userid = u.id<br />
JOIN prefix_badge_criteria AS t on b.id = t.badgeid <br />
WHERE t.criteriatype <> 0<br />
ORDER BY u.username<br />
</code><br />
<br />
Please note: the FROM_UNIXTIME command is for MySQL.<br />
<br />
=== All badges available in the system, with Earned count ===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
Report of all badges in the system, with badge name and description, context, course shortname if a course badge, whether it is active and available, and a count of how many users have been issued that badge.<br />
<br />
<code sql><br />
SELECT b.id, b.name, b.description,<br />
CASE<br />
WHEN b.type = 1 THEN "System"<br />
WHEN b.type = 2 THEN "Course"<br />
END AS Context, <br />
CASE<br />
WHEN b.courseid IS NOT NULL THEN <br />
(SELECT c.shortname <br />
FROM prefix_course AS c <br />
WHERE c.id = b.courseid)<br />
WHEN b.courseid IS NULL THEN "*"<br />
END AS Course, <br />
CASE<br />
WHEN b.status = 0 OR b.status = 2 THEN "No"<br />
WHEN b.status = 1 OR b.status = 3 THEN "Yes"<br />
WHEN b.status = 4 THEN "x"<br />
END AS Available,<br />
CASE<br />
WHEN b.status = 0 OR b.status = 1 THEN "0"<br />
WHEN b.status = 2 OR b.status = 3 OR b.status = 4 THEN <br />
(SELECT COUNT(*) <br />
FROM prefix_badge_issued AS d<br />
WHERE d.badgeid = b.id<br />
)<br />
END AS Earned<br />
FROM prefix_badge AS b<br />
<br />
</code><br />
<br />
=== Badges Leaderboard ===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
A simple list of usernames and how many badges they have earned overall.<br />
<br />
<code sql><br />
SELECT u.username, (SELECT COUNT(*) FROM prefix_badge_issued AS d WHERE d.userid = u.id) AS earned<br />
FROM prefix_user AS u<br />
ORDER BY earned DESC, u.username ASC<br />
</code><br />
<br />
=== Manage badges (System & Course) ===<br />
<br />
List system wide badges, course and system level badges + a link to relevant "manage badges" page.<br />
<br />
<code sql><br />
SELECT b.id, b.name, b.description <br />
,CASE <br />
WHEN b.type = 1 THEN 'System'<br />
WHEN b.type = 2 THEN 'Course'<br />
END AS Level<br />
,CONCAT('<a target="_new" href="%%WWWROOT%%/badges/index.php?type=', b.type, '&id=',<br />
c.id, '">Manage badges in: ', c.fullname, '</a>') AS Manage <br />
FROM prefix_badge AS b<br />
JOIN prefix_course AS c ON c.id = b.courseid<br />
</code><br />
<br />
==Administrator Reports==<br />
<br />
===Config changes in Export friendly form===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
The Administrative report Config changes is very useful but it would be nice to have it in a format that could be easily exported in one listing. Here is code to do that.<br />
<br />
<code sql><br />
SELECT <br />
DATE_FORMAT( FROM_UNIXTIME( g.timemodified ) , '%Y-%m-%d' ) AS date, <br />
u.username AS user, <br />
g.name AS setting, <br />
CASE <br />
WHEN g.plugin IS NULL THEN "core"<br />
ELSE g.plugin<br />
END AS plugin, <br />
g.value AS new_value, <br />
g.oldvalue AS original_value<br />
FROM prefix_config_log AS g<br />
JOIN prefix_user AS u ON g.userid = u.id<br />
ORDER BY date DESC<br />
</code><br />
<br />
===Cohorts by user===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
How to get a list of all users and which cohorts they belong to.<br />
<br />
<code sql><br />
SELECT u.firstname, u.lastname, h.idnumber, h.name<br />
FROM prefix_cohort AS h<br />
JOIN prefix_cohort_members AS hm ON h.id = hm.cohortid<br />
JOIN prefix_user AS u ON hm.userid = u.id<br />
ORDER BY u.firstname<br />
</code><br />
<br />
===Cohorts with Courses===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
List of all cohorts with name, id, visibility, and which courses they are enrolled in.<br />
<br />
<code sql><br />
SELECT<br />
# h.id,<br />
# e.customint1,<br />
h.name AS Cohort,<br />
h.idnumber AS Cohortid,<br />
CASE <br />
WHEN h.visible = 1 THEN 'Yes'<br />
ELSE '-'<br />
END AS Cohortvisible,<br />
CONCAT('<a target="_new" href="%%WWWROOT%%/course/view.php', CHAR(63),'id=',c.id,'">',c.fullname,'</a>') AS Course<br />
FROM prefix_cohort h<br />
JOIN prefix_enrol e ON h.id = e.customint1<br />
JOIN prefix_course c ON c.id = e.courseid %%FILTER_COURSES:e.courseid%% <br />
WHERE e.enrol = 'cohort' AND e.roleid = 5<br />
</code><br />
<br />
===Courses created And Active courses by Year===<br />
Active courses is counting course that have at least one Hit, And "Active_MoreThan100Hits" counts courses that have at least 100 Hits<br />
<code sql><br />
SELECT <br />
<br />
YEAR( FROM_UNIXTIME( `timecreated` ) ) AS YEAR, COUNT( * ) AS Counter<br />
<br />
, (SELECT COUNT( DISTINCT course ) <br />
FROM prefix_log AS l<br />
WHERE YEAR( FROM_UNIXTIME( l.`time` ) ) = YEAR( FROM_UNIXTIME( `timecreated` ) )<br />
) AS "Active"<br />
<br />
,(SELECT COUNT(*) FROM ( <br />
SELECT COUNT( * ),time <br />
FROM prefix_log AS l <br />
GROUP BY course <br />
HAVING COUNT(*) > 100) AS courses_log<br />
WHERE YEAR( FROM_UNIXTIME( courses_log.`time` ) ) = YEAR( FROM_UNIXTIME( `timecreated` ) )<br />
) AS "Active_MoreThan100Hits"<br />
<br />
FROM `prefix_course` <br />
GROUP BY YEAR( FROM_UNIXTIME( `timecreated` ) ) <br />
</code><br />
<br />
===Users created And Active users by Year===<br />
Active users is counting users that have at least one Hit, And "Active_MoreThan500Hits" counts users that have at least 500 Hits<br />
<code sql><br />
SELECT <br />
<br />
YEAR( FROM_UNIXTIME( `firstaccess` ) ) AS YEAR, COUNT( * ) AS Counter<br />
<br />
, (SELECT COUNT( DISTINCT userid ) <br />
FROM prefix_log AS l<br />
WHERE YEAR( FROM_UNIXTIME( l.`time` ) ) = YEAR( FROM_UNIXTIME( `firstaccess` ) )<br />
) AS "Active"<br />
<br />
,(SELECT COUNT(*) FROM ( <br />
SELECT COUNT( * ),time <br />
FROM prefix_log AS l <br />
GROUP BY userid <br />
HAVING COUNT(*) > 500) AS users_log<br />
WHERE YEAR( FROM_UNIXTIME( users_log.`time` ) ) = YEAR( FROM_UNIXTIME( `firstaccess` ) )<br />
) AS "Active_MoreThan500Hits"<br />
<br />
FROM `prefix_user` <br />
GROUP BY YEAR( FROM_UNIXTIME( `timecreated` ) ) <br />
</code><br />
<br />
===Course Aggregation Report===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
If you are considering upgrading from Moodle 2.6 to 2.8 or later, your grades may be changed. This report can help quantify and identify the courses at risk of changes.<br />
<br />
In particular, be on the lookout for any courses with the following combinations of parameters, which are known to cause changes in calculations:<br />
<br />
# mean of grades set with aggregate with subcategory.<br />
# Simple weighted mean of grades with aggregate with sub category and drop the lowest<br />
# Sum of grades drop the lowest<br />
<br />
Also review:<br />
https://tracker.moodle.org/browse/MDL-48618<br />
https://tracker.moodle.org/browse/MDL-48634<br />
https://tracker.moodle.org/browse/MDL-49257<br />
https://tracker.moodle.org/browse/MDL-50089<br />
https://tracker.moodle.org/browse/MDL-50062<br />
<br />
<code sql><br />
SELECT<br />
<br />
COUNT(c.shortname) AS 'Count of Courses'<br />
<br />
# If you want to display all the courses for each aggregation type, uncomment the next line and change GROUP BY settings<br />
#, c.shortname AS 'course name'<br />
<br />
# If you need to display grade categories for each aggregation type, uncomment the next line and change GROUP BY settings<br />
#, gc.fullname AS 'grade category name'<br />
<br />
, gc.aggregation AS 'aggregation method'<br />
<br />
#These aggregation text strings appear to be hard-coded. I couldn't find a table for them. If you have aggregation types I haven't included here, they'll be blank in your report results.<br />
, CASE gc.aggregation<br />
WHEN 0 THEN 'Mean of Grades'<br />
WHEN 2 THEN 'Median of Grades'<br />
WHEN 6 THEN 'Highest Grade'<br />
WHEN 8 THEN 'Mode of Grades'<br />
WHEN 10 THEN 'Weighted Mean of Grades'<br />
WHEN 11 THEN 'Simple Weighted Mean of Grades'<br />
WHEN 12 THEN 'Mean of Grades (with extra credits)'<br />
WHEN 13 THEN 'Sum of Grades'<br />
END AS 'aggregation name'<br />
<br />
# Note that gc.aggregatesubcats column is eliminated in 2.8 and later per MDL-47503, so comment that line on updated systems or you'll get an error<br />
, gc.keephigh AS 'keep high'<br />
, gc.droplow AS 'dr0p low'<br />
, gc.aggregateonlygraded AS 'Aggregate only graded'<br />
, gc.aggregateoutcomes AS 'aggregate outcomes'<br />
, gc.aggregatesubcats AS 'aggregate subcategories'<br />
<br />
# If you are displaying data about individual courses, you may want to know how old they are<br />
#, FROM_UNIXTIME(c.startdate) AS 'course start date'<br />
<br />
# If you are trying to use this report to check to see if final grades have changed after an upgrade, you might want these data items, but calculations can still change later when the courses are actually viewed. Also, you'll need to uncomment the necessary JOINs below<br />
#, gi.itemname AS 'grade item'<br />
#, gg.finalgrade AS 'final grade'<br />
<br />
FROM<br />
<br />
prefix_course AS c<br />
JOIN prefix_grade_categories AS gc ON gc.courseid = c.id<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
<br />
#LEFT JOIN prefix_grade_items AS gi ON gi.courseid = c.id #AND gi.categoryid=gc.id<br />
#LEFT JOIN prefix_grade_grades AS gg ON gg.itemid = gi.id AND gg.userid = u.id<br />
<br />
WHERE<br />
1<br />
#AND gc.aggregation = 13 #only the dreaded Sum of Grades aggregations<br />
#AND gc.depth = 1 # if for some reason you only want course aggregations, not subcategories<br />
<br />
<br />
GROUP BY gc.aggregation, gc.keephigh, gc.droplow, gc.aggregateonlygraded, gc.aggregateoutcomes, gc.aggregatesubcats<br />
<br />
</code><br />
<br />
=== Running Cron jobs (task_scheduled) ===<br />
<code sql><br />
SELECT classname<br />
,DATE_FORMAT(FROM_UNIXTIME(lastruntime), '%H:%i [%d]') AS 'last'<br />
,DATE_FORMAT(now(), '%H:%i') AS 'now'<br />
,DATE_FORMAT(FROM_UNIXTIME(nextruntime), '%H:%i [%d]') AS 'next'<br />
,DATE_FORMAT(FROM_UNIXTIME(UNIX_TIMESTAMP()-nextruntime), '%i') AS 'next in min'<br />
FROM mdl_task_scheduled<br />
WHERE now() > FROM_UNIXTIME(nextruntime)<br />
</code><br />
<br />
=== All Meta courses with Parent and Child course relationships ===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
This shows the list of courses with Meta course link enrollments in them ('Parent course'), and the courses which are connected to them to provide enrollments ('Child courses').<br />
<br />
<code sql><br />
SELECT <br />
c.fullname AS 'Parent course name',<br />
c.shortname AS 'Parent course shortname',<br />
en.courseid AS 'Parent course id',<br />
(SELECT fullname FROM prefix_course WHERE prefix_course.id = en.customint1) As 'Child course name',<br />
(SELECT shortname FROM prefix_course WHERE prefix_course.id = en.customint1) As 'Child course shortname',<br />
en.customint1 AS 'Child course id'<br />
FROM prefix_enrol en<br />
JOIN prefix_course c ON c.id = en.courseid<br />
WHERE en.enrol = 'meta'<br />
ORDER BY c.fullname<br />
</code><br />
<br />
== Useful sub queries ==<br />
<br />
IN this section please put any short one purpose sub queries that show how common procedures often useful as part of larger queries.<br />
<br />
=== All teachers in the course ===<br />
<br />
<br />
This snippet shows how to get teachers from a course. The contextevel for course objects is 50. And the default Teacher role is role id 3.<br />
<br />
<code sql><br />
,(SELECT GROUP_CONCAT( CONCAT( u.firstname, " ", u.lastname ) ) <br />
FROM prefix_course ic<br />
JOIN prefix_context con ON con.instanceid = ic.id<br />
JOIN prefix_role_assignments ra ON con.id = ra.contextid AND con.contextlevel = 50<br />
JOIN prefix_role r ON ra.roleid = r.id<br />
JOIN prefix_user u ON u.id = ra.userid<br />
WHERE r.id = 3 AND ic.id = c.id<br />
GROUP BY ic.id<br />
) AS TeacherNames<br />
</code><br />
<br />
=== Get custom User profile fields for a user ===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
This snippet of code shows how to connect a user with their custom profile field data. This will list all users with all custom profile fields and data. Custom profile fields have two tables, one for the definition of the profile field (user_info_field) and its settings, and a separate table to hold the data entered by users (user_info_data). <br />
<br />
<code sql><br />
SELECT u.username, uif.name, uid.data<br />
FROM prefix_user AS u<br />
JOIN prefix_user_info_data AS uid ON uid.userid = u.id<br />
JOIN prefix_user_info_field AS uif ON uid.fieldid = uif.id <br />
</code><br />
<br />
If you want to limit it to one of those fields, you can restrict it by shortname of the custom profile field, so:<br />
<br />
<code sql><br />
SELECT u.username, uif.name, uid.data<br />
FROM prefix_user AS u<br />
JOIN prefix_user_info_data AS uid ON uid.userid = u.id<br />
JOIN prefix_user_info_field AS uif ON (uid.fieldid = uif.id AND uif.shortname = 'shortname1')<br />
</code><br />
<br />
will show you only the data from the custom profile field with the shortname 'shortname1'.<br />
<br />
If you want to do this with two or more custom profile fields, you will need to have a JOIN and table alias for each with a restriction for each profile field shortname. Example:<br />
<br />
<code sql><br />
SELECT u.username, d1.data AS 'Profile One', d2.data As 'Profile Two'<br />
FROM prefix_user u<br />
JOIN prefix_user_info_data d1 ON d1.userid = u.id<br />
JOIN prefix_user_info_field f1 ON d1.fieldid = f1.id AND f1.shortname = 'shortname1'<br />
JOIN prefix_user_info_data d2 ON d2.userid = u.id<br />
JOIN prefix_user_info_field f2 ON d2.fieldid = f2.id AND f2.shortname = 'shortname2'<br />
</code><br />
<br />
==== NOTE: Alternate Method ====<br />
<br />
If you have more than a couple of fields you need to use, then this query may time out or not return data due to too many joins. The limit seems to be around 10 custom profile fields. <br />
<br />
Instead you should use an alternate method which uses Subselects for each of the profile fields. Details and sample code are in this forum discussion: https://moodle.org/mod/forum/discuss.php?d=355502#p1434854. A sample of the style is:<br />
<br />
<code sql><br />
SELECT u.username<br />
<br />
,(SELECT d1.data FROM prefix_user_info_data d1<br />
JOIN prefix_user_info_field f1 ON d1.fieldid = f1.id AND f1.shortname = 'shortname1'<br />
WHERE d1.userid = u.id<br />
) AS thefirstfield<br />
<br />
,(SELECT d1.data FROM prefix_user_info_data d1<br />
JOIN prefix_user_info_field f1 ON d1.fieldid = f1.id AND f1.shortname = 'shortname2'<br />
WHERE d1.userid = u.id<br />
) AS thesecondfield<br />
<br />
FROM prefix_user u<br />
</code><br />
<br />
=== How to use Configurable Reports Date Time Filters===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
In the Configurable Reports block, you can set the Time and Date filter to allow you to pick your report Start date/time and End date/time interactively. This will work on any column in a table that is a timestamp.<br />
<br />
Here is a simple example:<br />
<br />
<code sql><br />
SELECT u.username, <br />
DATE_FORMAT(FROM_UNIXTIME(u.firstaccess),'%Y-%m-%d %H:%i') AS 'FirstAccess',<br />
DATE_FORMAT(FROM_UNIXTIME(u.lastaccess),'%Y-%m-%d %H:%i') AS 'LastAccess' <br />
FROM prefix_user u<br />
<br />
WHERE 1=1<br />
%%FILTER_STARTTIME:u.firstaccess:>%% <br />
%%FILTER_ENDTIME:u.lastaccess:<%% <br />
</code><br />
<br />
1) You will need to replace name of the table and column for the filter to use the time and date column you need for your query. In the example above, it filters on the firstaccess and lastaccess columns in the user table. If you were doing a report on course completion, you might put the timecompleted column, and so forth.<br />
<br />
2) You MUST then add the Start / End date filter on the Filters tab of the Report. If you don't, the report will still run, probably, but the filter will be ignored.<br />
<br />
Note: the WHERE 1=1 statement is a peculiarity of the filters in Config reports: if you don't have a WHERE statement in your query already, then you must add this dummy WHERE to keep the statement valid. If you already have a WHERE statement in your code, simply add the %%FILTER%% placeholders after it (and before any GROUP or ORDER BY statements.)<br />
<br />
==See also==<br />
* [https://github.com/jleyva/moodle-configurable_reports_repository Configurable Reports Repository on GitHub]<br />
* [https://moodleschema.zoola.io/index.html Moodle DB schema explorer] - searching and filtering tables, fields and external key connections between tables.<br />
<br />
[[Category:Contributed code]]<br />
<br />
[[es:Reportes específicos hechos por usuarios]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=ad-hoc_contributed_reports&diff=133236ad-hoc contributed reports2019-03-07T09:12:00Z<p>Fox: /* System wide, daily unique user hits for the last 7 days */ Use prefix_ (and not mdl_)</p>
<hr />
<div>{{Sitewide reports}}<br />
==User and Role Report==<br />
<br />
===Count number of distinct learners and teachers enrolled per category (including all its sub categories)===<br />
<code sql>SELECT COUNT(DISTINCT lra.userid) AS learners, COUNT(DISTINCT tra.userid) as teachers<br />
FROM prefix_course AS c #, mdl_course_categories AS cats<br />
LEFT JOIN prefix_context AS ctx ON c.id = ctx.instanceid<br />
JOIN prefix_role_assignments AS lra ON lra.contextid = ctx.id<br />
JOIN prefix_role_assignments AS tra ON tra.contextid = ctx.id<br />
JOIN prefix_course_categories AS cats ON c.category = cats.id<br />
WHERE c.category = cats.id<br />
AND (<br />
cats.path LIKE '%/CATEGORYID/%' #Replace CATEGORYID with the category id you want to count (eg: 80)<br />
OR cats.path LIKE '%/CATEGORYID'<br />
)<br />
AND lra.roleid=5<br />
AND tra.roleid=3</code><br />
<br />
===Detailed ACTIONs for each ROLE (TEACHER, NON-EDITING TEACHER and STUDENT)===<br />
<code sql><br />
SELECT r.name, l.action, COUNT( l.userid ) AS counter<br />
FROM prefix_log AS l<br />
JOIN prefix_context AS context ON context.instanceid = l.course AND context.contextlevel = 50<br />
JOIN prefix_role_assignments AS ra ON l.userid = ra.userid AND ra.contextid = context.id<br />
JOIN prefix_role AS r ON ra.roleid = r.id<br />
WHERE ra.roleid IN ( 3, 4, 5 ) <br />
GROUP BY roleid, l.action<br />
</code><br />
<br />
===Student (user) COUNT in each Course===<br />
Including (optional) filter by: year (if included in course fullname).<br />
<code sql><br />
SELECT CONCAT('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',course.id,'">',course.fullname,'</a>') AS Course<br />
,CONCAT('<a target="_new" href="%%WWWROOT%%/user/index.php?contextid=',context.id,'">Show users</a>') AS Users<br />
, COUNT(course.id) AS Students<br />
FROM prefix_role_assignments AS asg<br />
JOIN prefix_context AS context ON asg.contextid = context.id AND context.contextlevel = 50<br />
JOIN prefix_user AS user ON user.id = asg.userid<br />
JOIN prefix_course AS course ON context.instanceid = course.id<br />
WHERE asg.roleid = 5 <br />
# AND course.fullname LIKE '%2013%'<br />
GROUP BY course.id<br />
ORDER BY COUNT(course.id) DESC<br />
</code><br />
<br />
=== Enrolment count in each Course ===<br />
<br />
Shows the total number of enroled users of all roles in each course. Sorted by course name.<br />
<br />
<code sql><br />
SELECT c.fullname, COUNT(ue.id) AS Enroled<br />
FROM prefix_course AS c <br />
JOIN prefix_enrol AS en ON en.courseid = c.id<br />
JOIN prefix_user_enrolments AS ue ON ue.enrolid = en.id<br />
GROUP BY c.id<br />
ORDER BY c.fullname<br />
</code><br />
<br />
===LIST of all site USERS by COURSE enrollment (Moodle 2.x)===<br />
<br />
<code sql><br />
SELECT<br />
user2.firstname AS Firstname,<br />
user2.lastname AS Lastname,<br />
user2.email AS Email,<br />
user2.city AS City,<br />
course.fullname AS Course<br />
,(SELECT shortname FROM prefix_role WHERE id=en.roleid) as Role<br />
,(SELECT name FROM prefix_role WHERE id=en.roleid) as RoleName<br />
<br />
FROM prefix_course as course <br />
JOIN prefix_enrol AS en ON en.courseid = course.id<br />
JOIN prefix_user_enrolments AS ue ON ue.enrolid = en.id<br />
JOIN prefix_user AS user2 ON ue.userid = user2.id<br />
</code><br />
<br />
===Enrolled users,which did not login into the Course, even once (Moodle 2)===<br />
Designed forMoodle 2 table structure and uses special plugin filter : %%FILTER_SEARCHTEXT:table.field%%<br />
<br />
<code sql><br />
SELECT<br />
user2.id as ID,<br />
ul.timeaccess,<br />
user2.firstname AS Firstname,<br />
user2.lastname AS Lastname,<br />
user2.email AS Email,<br />
user2.city AS City,<br />
user2.idnumber AS IDNumber,<br />
user2.phone1 AS Phone,<br />
user2.institution AS Institution,<br />
<br />
IF (user2.lastaccess = 0,'never',<br />
DATE_FORMAT(FROM_UNIXTIME(user2.lastaccess),'%Y-%m-%d')) AS dLastAccess<br />
<br />
,(SELECT DATE_FORMAT(FROM_UNIXTIME(timeaccess),'%Y-%m-%d') FROM prefix_user_lastaccess WHERE userid=user2.id and courseid=c.id) as CourseLastAccess<br />
<br />
,(SELECT r.name<br />
FROM prefix_user_enrolments AS uenrol<br />
JOIN prefix_enrol AS e ON e.id = uenrol.enrolid<br />
JOIN prefix_role AS r ON e.id = r.id<br />
WHERE uenrol.userid=user2.id and e.courseid = c.id) AS RoleName<br />
<br />
FROM prefix_user_enrolments as ue<br />
JOIN prefix_enrol as e on e.id = ue.enrolid<br />
JOIN prefix_course as c ON c.id = e.courseid<br />
JOIN prefix_user as user2 ON user2 .id = ue.userid<br />
LEFT JOIN prefix_user_lastaccess as ul on ul.userid = user2.id<br />
WHERE c.id=16 AND ul.timeaccess IS NULL<br />
%%FILTER_SEARCHTEXT:user2.firstname%%<br />
</code><br />
<br />
===Role assignments on categories===<br />
<code sql><br />
SELECT <br />
concat('<a target="_new" href="%%WWWROOT%%/course/category.php?id=',cc.id,'">',cc.id,'</a>') AS id,<br />
concat('<a target="_new" href="%%WWWROOT%%/course/category.php?id=',cc.id,'">',cc.name,'</a>') AS category,<br />
cc.depth, cc.path, r.name AS role,<br />
concat('<a target="_new" href="%%WWWROOT%%/user/view.php?id=',usr.id,'">',usr.lastname,'</a>') AS name,<br />
usr.firstname, usr.username, usr.email<br />
FROM prefix_course_categories cc<br />
INNER JOIN prefix_context cx ON cc.id = cx.instanceid<br />
AND cx.contextlevel = '40'<br />
INNER JOIN prefix_role_assignments ra ON cx.id = ra.contextid<br />
INNER JOIN prefix_role r ON ra.roleid = r.id<br />
INNER JOIN prefix_user usr ON ra.userid = usr.id<br />
ORDER BY cc.depth, cc.path, usr.lastname, usr.firstname, r.name, cc.name<br />
</code><br />
<br />
===Permissions Overides on Categories===<br />
(By: [http://moodle.org/mod/forum/discuss.php?d=153059#p712834 Séverin Terrier] )<br />
<code sql><br />
SELECT rc.id, ct.instanceid, ccat.name, rc.roleid, rc.capability, rc.permission, <br />
DATE_FORMAT( FROM_UNIXTIME( rc.timemodified ) , '%Y-%m-%d' ) AS timemodified, rc.modifierid, ct.instanceid, ct.path, ct.depth<br />
FROM `prefix_role_capabilities` AS rc<br />
INNER JOIN `prefix_context` AS ct ON rc.contextid = ct.id<br />
INNER JOIN `prefix_course_categories` AS ccat ON ccat.id = ct.instanceid<br />
AND `contextlevel` =40<br />
</code><br />
<br />
===Lists "Totally Opened Courses" (visible, opened to guests, with no password)===<br />
(By: [http://moodle.org/mod/forum/discuss.php?d=153059#p712837 Séverin Terrier] )<br />
<code sql><br />
SELECT<br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.id,'</a>') AS id,<br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.shortname,'</a>') AS 'Course',<br />
concat('<a target="_new" href="%%WWWROOT%%/enrol/instances.php?id=',c.id,'">Méthodes inscription</a>') AS 'Enrollment plugins',<br />
e.sortorder<br />
FROM prefix_enrol AS e, prefix_course AS c<br />
WHERE e.enrol='guest' AND e.status=0 AND e.password='' AND c.id=e.courseid AND c.visible=1<br />
</code><br />
<br />
===Lists "loggedin users" from the last 120 days===<br />
<code sql><br />
SELECT id,username,FROM_UNIXTIME(`lastlogin`) as days <br />
FROM `prefix_user` <br />
WHERE DATEDIFF( NOW(),FROM_UNIXTIME(`lastlogin`) ) < 120<br />
</code><br />
<br />
''and user count for that same population:''<br />
<code sql><br />
SELECT COUNT(id) as Users FROM `prefix_user` <br />
WHERE DATEDIFF( NOW(),FROM_UNIXTIME(`lastlogin`) ) < 120<br />
</code><br />
<br />
==== Users loggedin within the last 7 days ====<br />
<code sql><br />
SELECT<br />
l.* FROM mdl_logstore_standard_log l<br />
WHERE<br />
l.eventname = '\\core\\event\\user_loggedin'<br />
AND FROM_UNIXTIME(l.timecreated, '%Y-%m-%d') >= DATE_SUB(NOW(), INTERVAL 7 DAY)<br />
<br />
SELECT l.eventname FROM mdl_logstore_standard_log l<br />
GROUP BY l.eventname<br />
</code><br />
<br />
===Lists the users who have only logged into the site once===<br />
<code sql><br />
SELECT id, username, firstname, lastname, idnumber<br />
FROM prefix_user<br />
WHERE prefix_user.deleted = 0<br />
AND prefix_user.lastlogin = 0 <br />
AND prefix_user.lastaccess > 0<br />
</code><br />
<br />
===Students in all courses of some institute===<br />
What is the status (deleted or not) of all Students (roleid = 5) in all courses of some Institute<br />
<code sql><br />
SELECT c.id, c.fullname, u.firstname, u.lastname, u.deleted<br />
FROM prefix_course AS c<br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid<br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE ra.roleid =5<br />
AND ctx.instanceid = c.id<br />
AND u.institution = 'please enter school name here'<br />
</code><br />
<br />
===Full User info (for deleted users)===<br />
Including extra custom profile fields (from prefix_user_info_data)<br />
<code sql><br />
SELECT * <br />
FROM prefix_user as u <br />
JOIN prefix_user_info_data as uid ON uid.userid = u.id <br />
JOIN prefix_user_info_field as uif ON (uid.fieldid = uif.id AND uif.shortname = 'class')<br />
WHERE `deleted` = "1" and `institution`="your school name" and `department` = "your department" and `data` = "class level and number"<br />
</code><br />
<br />
===User's courses===<br />
change "u.id = 2" with a new user id<br />
<code sql><br />
SELECT u.firstname, u.lastname, c.id, c.fullname<br />
FROM prefix_course AS c<br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid<br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE u.id = 2<br />
</code><br />
<br />
===List Users with extra info (email) in current course===<br />
blocks/configurable_reports replaces %%COURSEID%% with course id.<br />
<code sql><br />
SELECT u.firstname, u.lastname, u.email<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS context ON context.id = ra.contextid AND context.contextlevel = 50<br />
JOIN prefix_course AS c ON c.id = context.instanceid AND c.id = %%COURSEID%%<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
</code><br />
<br />
===List Students with enrollment and completion dates in current course===<br />
This is meant to be a "global" report in Configurable Reports containing the following:<br />
firstname, lastname, idnumber, institution, department, email, student enrolment date, student completion date<br />
Note: for PGSQL, use to_timestamp() instead of FROM_UNIXTIME()<br />
Contributed by Elizabeth Dalton, Moodle HQ<br />
<br />
<code sql><br />
SELECT <br />
u.firstname<br />
, u.lastname<br />
, u.idnumber<br />
, u.institution<br />
, u.department<br />
, u.email<br />
, FROM_UNIXTIME(cc.timeenrolled)<br />
, FROM_UNIXTIME(cc.timecompleted)<br />
<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS context ON context.id = ra.contextid AND context.contextlevel = 50<br />
JOIN prefix_course AS c ON c.id = context.instanceid AND c.id = %%COURSEID%%<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
JOIN prefix_course_completions AS cc ON cc.course = c.id AND cc.userid = u.id<br />
</code><br />
<br />
===Special Roles===<br />
<code sql><br />
SELECT ra.roleid,r.name<br />
,concat('<a target="_new" href="%%WWWROOT%%/course/user.php?id=1&user=',ra.userid,'">',u.firstname ,' ',u.lastname,'</a>') AS Username<br />
,concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS Course<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_role AS r ON r.id = ra.roleid<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
JOIN prefix_context AS ctx ON (ctx.id = ra.contextid AND ctx.contextlevel = 50)<br />
JOIN prefix_course AS c ON ctx.instanceid = c.id<br />
WHERE ra.roleid > 6<br />
</code><br />
<br />
===Courses without Teachers===<br />
Actually, shows the number of Teachers in a course.<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') as Course<br />
,(SELECT Count( ra.userid ) AS Users FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id) AS Teachers<br />
FROM prefix_course AS c<br />
ORDER BY Teachers ASC<br />
</code><br />
<br />
===List of users who have been enrolled for more than 4 weeks===<br />
For Moodle 2.2 , by Isuru Madushanka Weerarathna <br />
<code sql><br />
SELECT uenr.userid As User, IF(enr.courseid=uenr.courseid ,'Y','N') As Enrolled, <br />
IF(DATEDIFF(NOW(), FROM_UNIXTIME(uenr.timecreated))>=28,'Y','N') As EnrolledMoreThan4Weeks<br />
FROM prefix_enrol As enr, prefix_user_enrolments AS uenr<br />
WHERE enr.id = uenr.enrolid AND enr.status = uenr.status<br />
</code><br />
<br />
=== List of users with language===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
An issue with systems that do not have their default language set up properly is the need to do a mass change for all users to a localization. A common case is changing default English to American English. <br />
<br />
This will show you the language setting for all users:<br />
<code sql><br />
SELECT username, lang from prefix_user <br />
</code><br />
<br />
NOTE: UPDATE commands require the ability to alter the database directly via tools like Adminer or PHPMyAdmin or other db tools.<br />
<br />
This code will change the setting from 'en' to 'en_us' for all users:<br />
<br />
<code sql><br />
UPDATE prefix_user SET lang = 'en_us' WHERE lang = 'en'<br />
</code><br />
<br />
To do this for only users who have a particular country set, use this as an example:<br />
<code sql><br />
UPDATE prefix_user SET lang = 'en_us' WHERE country = 'US' AND lang = 'en'<br />
</code><br />
<br />
=== List of users with Authentication ===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
Sometimes you need to do mass changes of authentication methods. A common case is changing default manual to LDAP. <br />
<br />
This will show you the Authentication setting for all users:<br />
<code sql><br />
SELECT username, auth from prefix_user <br />
</code><br />
<br />
NOTE: UPDATE commands require the ability to alter the database directly via tools like Adminer or PHPMyAdmin or other db tools. <br />
<br />
This code will change the setting from 'manual' to 'ldap' for all users except for the first two accounts which are Guest and Admin. (WARNING: it is bad practice to change your admin account from manual to an external method as failure of that external method will lock you out of Moodle as admin.)<br />
<br />
<code sql><br />
UPDATE prefix_user SET auth = 'ldap' WHERE auth = 'manual' AND id > 2<br />
</code><br />
<br />
=== Compare role capability and permissions ===<br />
<code sql><br />
SELECT DISTINCT mrc.capability <br />
,(SELECT rc.permission FROM `mdl_role_capabilities` AS rc WHERE rc.capability = mrc.capability <br />
AND rc.roleid = '1' AND rc.contextid = '1') AS Manager<br />
,(SELECT rc.permission FROM `mdl_role_capabilities` AS rc WHERE rc.capability = mrc.capability <br />
AND rc.roleid = '2' AND rc.contextid = '1') AS CourseCreator<br />
,(SELECT rc.permission FROM `mdl_role_capabilities` AS rc WHERE rc.capability = mrc.capability <br />
AND rc.roleid = '3' AND rc.contextid = '1') AS Teacher<br />
,(SELECT rc.permission FROM `mdl_role_capabilities` AS rc WHERE rc.capability = mrc.capability <br />
AND rc.roleid = '4' AND rc.contextid = '1') AS AssistantTeacher<br />
,(SELECT rc.permission FROM `mdl_role_capabilities` AS rc WHERE rc.capability = mrc.capability <br />
AND rc.roleid = '5' AND rc.contextid = '1') AS Student<br />
,(SELECT rc.permission FROM `mdl_role_capabilities` AS rc WHERE rc.capability = mrc.capability <br />
AND rc.roleid = '6' AND rc.contextid = '1') AS Guest<br />
<br />
FROM `mdl_role_capabilities` AS mrc<br />
</code><br />
<br />
=== User's accumulative time spent in course ===<br />
A sum up of the time delta between logstore_standard_log user's records, considering the a 2 hour session limit.<br />
<br />
Uses: current user's id %%USERID%% and current course's id %%COURSEID%% <br />
<br />
And also using a date filter (which can be ignored) <br />
<br />
The extra "User" field is used as a dummy field for the Line chart Series field, in which I use X=id, Series=Type, Y=delta.<br />
<br />
<code sql><br />
SELECT <br />
l.id, <br />
l.timecreated, <br />
DATE_FORMAT(FROM_UNIXTIME(l.timecreated),'%d-%m-%Y') AS dTime,<br />
@prevtime := (SELECT max(timecreated) FROM mdl_logstore_standard_log <br />
WHERE userid = %%USERID%% and id < l.id ORDER BY id ASC LIMIT 1) AS prev_time,<br />
IF (l.timecreated - @prevtime < 7200, @delta := @delta + (l.timecreated-@prevtime),0) AS sumtime,<br />
l.timecreated-@prevtime AS delta,<br />
"User" as type<br />
<br />
FROM prefix_logstore_standard_log as l, <br />
(SELECT @delta := 0) AS s_init <br />
# Change UserID<br />
WHERE l.userid = %%USERID%% AND l.courseid = %%COURSEID%%<br />
%%FILTER_STARTTIME:l.timecreated:>%% %%FILTER_ENDTIME:l.timecreated:<%% <br />
</code><br />
<br />
=== Low-Participation Student Report ===<br />
Contributed by Elizabeth Dalton, Granite State College / Moodle HQ<br />
<br />
This report returns a list of students who are enrolled in courses filtered by a short-name text marker (in this case "OL-") in the specified category, but have very low participation in the course during the specified time period (fewer than 2 "Edits" to Activity Modules, indicating few active contributions to the course). The number of "Edits" is provided for each student for the time period specified.<br />
<br />
An "Edit" is defined as course activity other than viewing content. Click the "Logs" link to review the student activity. The Logs offer the option to review "View" activity as well as "Edit" activity.<br />
<br />
Only "visible" courses are included in this report. The report may be downloaded as an Excel spreadsheet.<br />
<br />
Don't forget to set up Filters: "Start / End date filter" and "Filter categories" on the Filters tab in Configurable reports.<br />
<br />
<code sql><br />
SELECT u.lastname AS Last, u.firstname AS First, u.idnumber AS IDnumber, u.email AS email, c.shortname AS CourseID, count(l.id) AS Edits, CONCAT('<a target="_new" href="https://learn.granite.edu/report/log/index.php',CHAR(63),'chooselog=1&showusers=1&showcourses=0&id=',c.id,'&user=',u.id,'&date=0&modid=&modaction=-view&logformat=showashtml','">','Logs','</a>') AS Link<br />
<br />
FROM prefix_user AS u<br />
JOIN prefix_role_assignments AS ra ON u.id = ra.userid<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
<br />
LEFT JOIN prefix_log AS l ON l.userid = u.id AND l.course = c.id AND l.action NOT LIKE "view%" %%FILTER_STARTTIME:l.TIME:>%% %%FILTER_ENDTIME:l.TIME:<%%<br />
<br />
WHERE ra.roleid =5<br />
AND ctx.instanceid = c.id<br />
AND c.visible=1<br />
# This prefix filter allows the exclusion of non-online courses at the original institution. Alter this to fit your institution, or remove it.<br />
AND c.shortname LIKE '%OL-%'<br />
%%FILTER_CATEGORIES:c.category%%<br />
<br />
GROUP BY u.idnumber<br />
<br />
HAVING Edits < 2<br />
</code><br />
<br />
=== Messages of All Users in a Specific Course ===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
NOTE: This query will probably not work at all in 3.5 now due to the changes in the structure of the Messages database. - RT<br />
<br />
This query shows the personal messages between users in a specific course, given the course id number. Properly speaking, personal messages pertain only to users and are not part of courses, but by filtering enrollments for roles in a course, you can show this. <br />
<br />
This report as is shows only the messages between Teachers and Students, as the WHERE statement contains and AND ((...))) section that restrict this report to ONLY messages between Teachers (role id = 3) and Students (role id =5). Remove that part of the statement if you wish to see _all_ messages between all users, e.g. teachers to teachers, student to student. <br />
<br />
Also, if you have created custom roles, you can replace the default id numbers with custom ones to further enhance the report.<br />
<br />
<code sql><br />
SELECT <br />
u.username AS 'From',<br />
CONCAT(u.firstname ,' ',u.lastname) AS 'From Name',<br />
u2.username AS 'To',<br />
CONCAT(u2.firstname ,' ',u2.lastname) AS 'To Name',<br />
DATE_FORMAT(FROM_UNIXTIME(me.timecreated), '%Y-%m-%d %H:%i') AS 'When',<br />
me.subject AS 'Subject', <br />
me.smallmessage AS 'Message'<br />
FROM prefix_message me<br />
JOIN prefix_role_assignments AS ra ON ra.userid = me.useridfrom AND ra.roleid IN (3,4,5) <br />
JOIN prefix_role_assignments AS ra2 ON ra2.userid = me.useridto AND ra2.roleid IN (3,4,5) <br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id AND ra2.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
JOIN prefix_user u ON u.id = me.useridfrom<br />
JOIN prefix_user u2 ON u2.id = me.useridto<br />
WHERE c.id=## <br />
AND ((ra.roleid = 3 AND ra2.roleid = 5) OR (ra.roleid = 5 AND ra2.roleid = 3)) <br />
ORDER BY me.useridfrom, me.useridto, me.timecreated<br />
</code><br />
<br />
==Log Activity Reports==<br />
===Count all Active Users by ROLE in a course category (including all of its sub-categories)===<br />
<code sql><br />
SELECT COUNT(DISTINCT l.userid) as active<br />
FROM mdl_course as c<br />
JOIN mdl_context AS ctx ON ctx.instanceid=c.id<br />
JOIN mdl_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN mdl_user_lastaccess as l ON ra.userid = l.userid<br />
JOIN mdl_course_categories AS cats ON c.category = cats.id<br />
WHERE c.category=cats.id AND (<br />
cats.path LIKE '%/80/%'<br />
OR cats.path LIKE '%/80'<br />
) <br />
AND ra.roleid=3 AND ctx.contextlevel=50 #ra.roleid= TEACHER 3, NON-EDITING TEACHER 4, STUDENT 5<br />
AND l.timeaccess > (unix_timestamp() - ((60*60*24)*NO_OF_DAYS)) #NO_OF_DAYS change to number<br />
</code><br />
===Detailed "VIEW" ACTION for each ROLE (TEACHER,NONE-EDITING TEACHER and STUDENT)===<br />
<code sql><br />
SELECT l.action, count( l.userid ) as counter , r.name<br />
FROM `prefix_log` as l<br />
JOIN `prefix_role_assignments` AS ra on l.userid = ra.userid<br />
JOIN `prefix_role` AS r ON ra.roleid = r.id<br />
WHERE (ra.roleid IN (3,4,5)) AND (l.action LIKE '%view%' )<br />
GROUP BY roleid,l.action<br />
order by r.name,counter desc<br />
</code><br />
<br />
===Total Activity of Roles:"Teacher" and "None-Editing Teacher" by Dates and by Hours===<br />
The output columns of this report table can be used as base for a Pivot-Table<br />
which will show the amount of '''activity''' per '''hour''' per '''days''' in 3D graph view.<br />
<br />
<code sql><br />
SELECT DATE_FORMAT( FROM_UNIXTIME( l.time ) , '%Y-%m-%d' ) AS grptimed ,<br />
DATE_FORMAT( FROM_UNIXTIME( l.time ) , '%k' ) AS grptimeh , count( l.userid ) AS counter <br />
FROM `prefix_log` AS l<br />
JOIN prefix_user AS u ON u.id = l.userid<br />
JOIN prefix_role_assignments AS ra ON l.userid = ra.userid<br />
JOIN prefix_role AS r ON r.id = ra.roleid<br />
WHERE ra.roleid IN (3,4)<br />
GROUP BY grptimed,grptimeh<br />
ORDER BY grptimed,grptimeh<br />
</code><br />
<br />
===How many LOGINs per user and user's Activity===<br />
+ link username to a user activity graph report<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/user.php?id=1&user=',u.id,'&mode=alllogs">',u.firstname ,' ',u.lastname,'</a>') as Username<br />
,count(*) as logins<br />
,(SELECT count(*) FROM prefix_log WHERE userid = l.userid GROUP BY userid) as Activity <br />
FROM prefix_log as l JOIN prefix_user as u ON l.userid = u.id <br />
WHERE `action` LIKE '%login%' group by userid<br />
ORDER BY Activity DESC<br />
</code><br />
===Distinct user logins per month===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
The following will show you the months of the current calendar year with the total number of distinct, unique user logins per month. Change the year in the WHERE clause to the year you need.<br />
<br />
<code sql><br />
SELECT <br />
COUNT(DISTINCT l.userid) AS 'DistinctUserLogins', <br />
DATE_FORMAT(FROM_UNIXTIME(l.timecreated), '%M') AS 'Month'<br />
FROM prefix_logstore_standard_log l<br />
WHERE l.action = 'loggedin' AND YEAR(FROM_UNIXTIME(l.timecreated)) = '2017' <br />
GROUP BY MONTH(FROM_UNIXTIME(l.timecreated))<br />
</code><br />
<br />
===Total activity per course, per unique user on the last 24h===<br />
<code sql><br />
SELECT<br />
COUNT(DISTINCT userid) AS countUsers<br />
, COUNT(l.courseid) AS countVisits<br />
, CONCAT('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">', c.fullname, '</a>') AS Course<br />
<br />
FROM mdl_logstore_standard_log AS l<br />
JOIN mdl_course AS c ON c.id = l.courseid<br />
WHERE l.courseid > 0<br />
AND FROM_UNIXTIME(l.timecreated) >= DATE_SUB(NOW(), INTERVAL 1 DAY)<br />
AND c.fullname LIKE '%תשעו%'<br />
GROUP BY l.courseid<br />
ORDER BY countVisits DESC<br />
</code><br />
<br />
===Weekly Instructor Online Participation===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
Displays participation of instructors in all courses per week of a term, including pre-term and post-term edits. An edit is defined as a change to the course, such as a discussion post, the grading of an assignment, or the uploading of file attachments, as well as alterations to course content.<br />
<br />
* To specify a subject and/or course number, use % as a wildcard, e.g. ARTS% or ARTS501%<br />
* To match part of a last name, use %, e.g. Smi% will match "Smith", "Smile", etc.<br />
<br />
At our institution, we include filters on the course name or category to constrain by terms. These are very specific to how course names and categories are constructed at our institution, so I've removed those elements from this code. Also, our terms are 12 weeks long. You would want to insert additional "SUM" lines for longer terms, or remove lines for shorter terms.<br />
<br />
'''Note''': This report can take a long time to run. While it can be run in Configurable Reports on demand, it may be more appropriate to implement it in the Ad Hoc Queries plugin as a scheduled report.<br />
<br />
'''Note''': This version uses legacy (pre-2.7) logs. See below for post-2.7 Standard Logs version.<br />
<br />
<code sql><br />
SELECT <br />
c.shortname AS CourseID<br />
, cc.name AS Category<br />
, CONCAT(u.firstname ,' ',u.lastname) AS Instructor<br />
<br />
, (SELECT COUNT( ra2.userid ) AS Users2 FROM prefix_role_assignments AS ra2<br />
JOIN prefix_context AS ctx2 ON ra2.contextid = ctx2.id<br />
WHERE ra2.roleid = 5 AND ctx2.instanceid = c.id) AS Students<br />
<br />
, c.startdate AS Course_Start_Date<br />
<br />
, c.visible AS Visible<br />
<br />
, COUNT(l.id) AS Edits<br />
<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time)) - WEEK(FROM_UNIXTIME(c.startdate))<0,1,0)) AS BeforeTerm<br />
<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=0,1,0)) AS Week1<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=1,1,0)) AS Week2<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=2,1,0)) AS Week3<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=3,1,0)) AS Week4<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=4,1,0)) AS Week5<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=5,1,0)) AS Week6<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=6,1,0)) AS Week7<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=7,1,0)) AS Week8<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=8,1,0)) AS Week9<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=9,1,0)) AS Week10<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=10,1,0)) AS Week11<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=11,1,0)) AS Week12<br />
<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))>=12,1,0)) AS AfterTerm<br />
<br />
, CONCAT('<a target="_new" href="%%WWWROOT%%/report/log/index.php',CHAR(63),'chooselog=1&showusers=1&showcourses=0&id=',c.id,'&user=',u.id,'&date=0&modid=&modaction=&logformat=showashtml','">','Logs','</a>') AS Link<br />
<br />
FROM prefix_user AS u<br />
JOIN prefix_role_assignments AS ra ON u.id = ra.userid<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
JOIN prefix_course_categories as cc ON c.category = cc.id<br />
<br />
LEFT JOIN prefix_log AS l ON l.userid = u.id AND l.course = c.id AND l.action NOT LIKE "view%"<br />
<br />
WHERE ra.roleid =3<br />
AND ctx.instanceid = c.id<br />
AND c.shortname LIKE :course<br />
AND u.lastname LIKE :last_name<br />
<br />
GROUP BY u.idnumber, c.id<br />
HAVING students > 0<br />
ORDER BY c.shortname<br />
</code><br />
<br />
'''Note''': Post-2.7 log version:<br />
<br />
<code sql><br />
SELECT <br />
c.shortname AS CourseID<br />
, cc.name AS Category<br />
, CONCAT(u.firstname ,' ',u.lastname) AS Instructor<br />
<br />
, (SELECT COUNT( ra2.userid ) AS Users2 FROM prefix_role_assignments AS ra2<br />
JOIN prefix_context AS ctx2 ON ra2.contextid = ctx2.id<br />
WHERE ra2.roleid = 5 AND ctx2.instanceid = c.id) AS Students<br />
<br />
, FROM_UNIXTIME(c.startdate) AS Course_Start_Date<br />
<br />
, c.visible AS Visible<br />
<br />
, COUNT(DISTINCT l.id) AS Edits<br />
<br />
, COUNT(DISTINCT IF((l.timecreated-c.startdate)<0,l.id,NULL)) AS 'Before Term'<br />
<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=0,l.id,NULL)) AS 'Week 1'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=1,l.id,NULL)) AS 'Week 2'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=2,l.id,NULL)) AS 'Week 3'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=3,l.id,NULL)) AS 'Week 4'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=4,l.id,NULL)) AS 'Week 5'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=5,l.id,NULL)) AS 'Week 6'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=6,l.id,NULL)) AS 'Week 7'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=7,l.id,NULL)) AS 'Week 8'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=8,l.id,NULL)) AS 'Week 9'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=9,l.id,NULL)) AS 'Week 10'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=10,l.id,NULL)) AS 'Week 11'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=11,l.id,NULL)) AS 'Week 12'<br />
<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))>=12,l.id,NULL)) AS 'After Term'<br />
<br />
, CONCAT('<a target="_new" href="%%WWWROOT%%/report/log/index.php',CHAR(63),'chooselog=1&showusers=1&showcourses=0&id=',c.id,'&user=',u.id,'&date=0&modid=&modaction=&logformat=showashtml','">','Logs','</a>') AS Link<br />
<br />
FROM prefix_user AS u<br />
LEFT JOIN prefix_role_assignments AS ra ON u.id = ra.userid<br />
LEFT JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
LEFT JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
LEFT JOIN prefix_course_categories as cc ON c.category = cc.id<br />
<br />
LEFT JOIN prefix_logstore_standard_log AS l ON l.userid = u.id AND l.courseid = c.id AND l.crud IN ('c','u')<br />
<br />
WHERE ra.roleid =3<br />
AND ctx.instanceid = c.id<br />
AND c.shortname LIKE '%OL-%'<br />
AND cc.idnumber LIKE '%current%'<br />
<br />
GROUP BY u.idnumber, c.id<br />
#HAVING students > 0<br />
ORDER BY RIGHT(c.shortname,2), c.shortname<br />
</code><br />
<br />
===Weekly Student Online Participation===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
Displays participation of students in the current course by week, including pre-term and post-term edits. An edit is defined as a change to the course, such as a discussion post, the submission of an assignment, or the completion of a quiz, as well as alterations to course content such as database entries (if permitted).<br />
<br />
Links to three other reports are also provided:<br />
<br />
* Logs: complete log entries for the student in the course, organized by date<br />
* Activity Outline: the "Outline Report" from the User Activity Reports, summarizing the student's activity in the course, organized by course content<br />
* Consolidated Activity Report: the "Complete Report" from the User Activity Reports, detailing the student's activity in the course, organized by course content (includes text of forum posts)<br />
<br />
'''Note''': This should be defined as a "Global" report (visible from within all courses). At our institution, our terms are 12 weeks long. You would want to insert additional "SUM" lines for longer terms, or remove lines for shorter terms. We pull advisor names into student user profiles as part of our configuration. These lines are present in the code below, but are commented out, as they are very specific to your Moodle configuration.<br />
<br />
'''Note''': This version of the report uses legacy (pre-2.7) logs. See below for a post-2.7 Standard Logs version.<br />
<br />
<code sql><br />
SELECT <br />
u.lastname AS 'Last Name'<br />
, u.firstname AS 'First Name'<br />
, COUNT(l.id) AS 'Edits'<br />
<br />
, SUM(IF((l.time-c.startdate)/7<0,1,0)) AS 'Before Term'<br />
<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=0,1,0)) AS 'Week 1'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=1,1,0)) AS 'Week 2'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=2,1,0)) AS 'Week 3'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=3,1,0)) AS 'Week 4'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=4,1,0)) AS 'Week 5'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=5,1,0)) AS 'Week 6'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=6,1,0)) AS 'Week 7'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=7,1,0)) AS 'Week 8'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=8,1,0)) AS 'Week 9'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=9,1,0)) AS 'Week 10'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=10,1,0)) AS 'Week 11'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=11,1,0)) AS 'Week 12'<br />
<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))>=15,1,0)) AS 'After Term'<br />
<br />
, CONCAT('<a target="_blank" href="%%WWWROOT%%/report/log/index.php',CHAR(63),'chooselog=1&showusers=1&showcourses=0&id=',c.id,'&user=',u.id,'&date=0&modid=&modaction=&logformat=showashtml','">','Logs','</a>') AS 'Logs'<br />
<br />
, CONCAT('<a target="_blank" href="%%WWWROOT%%/report/outline/user.php',CHAR(63),'id=',u.id,'&course=',c.id,'&mode=outline">','Outline','</a>') AS 'Activity Outline'<br />
<br />
, CONCAT('<a target="_blank" href="%%WWWROOT%%/report/outline/user.php',CHAR(63),'id=',u.id,'&course=',c.id,'&mode=complete">','Activity','</a>') AS 'Consolidated Activity'<br />
<br />
FROM prefix_user AS u<br />
JOIN prefix_role_assignments AS ra ON u.id = ra.userid<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
JOIN prefix_course_categories as cc ON c.category = cc.id<br />
<br />
LEFT JOIN prefix_log AS l ON l.userid = u.id AND l.course = c.id AND l.action NOT LIKE "view%"<br />
<br />
WHERE ra.roleid =5<br />
AND ctx.instanceid = c.id<br />
<br />
AND c.id = %%COURSEID%%<br />
<br />
GROUP BY u.idnumber<br />
<br />
ORDER BY u.lastname, u.firstname<br />
</code><br />
<br />
'''Note''': Post-2.7 (Standard Logs) version<br />
<br />
<code sql><br />
SELECT <br />
u.lastname AS 'Last Name'<br />
, u.firstname AS 'First Name'<br />
, COUNT(l.id) AS 'Edits'<br />
<br />
, COUNT(DISTINCT IF((l.timecreated-c.startdate)<0,l.id,NULL)) AS 'Before Term'<br />
<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=0,l.id,NULL)) AS 'Week 1'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=1,l.id,NULL)) AS 'Week 2'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=2,l.id,NULL)) AS 'Week 3'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=3,l.id,NULL)) AS 'Week 4'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=4,l.id,NULL)) AS 'Week 5'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=5,l.id,NULL)) AS 'Week 6'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=6,l.id,NULL)) AS 'Week 7'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=7,l.id,NULL)) AS 'Week 8'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=8,l.id,NULL)) AS 'Week 9'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=9,l.id,NULL)) AS 'Week 10'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=10,l.id,NULL)) AS 'Week 11'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=11,l.id,NULL)) AS 'Week 12'<br />
<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))>=12,l.id,NULL)) AS 'After Term'<br />
<br />
# Our institution stores academic advisor names and emails in custom profile fields<br />
#, CONCAT('<a href="mailto:',uce.data,'">',uid.data, '</a>') AS 'Academic Advisor'<br />
<br />
, CONCAT('<a target="_blank" href="%%WWWROOT%%/report/log/index.php',CHAR(63),'chooselog=1&showusers=1&showcourses=0&id=',c.id,'&user=',u.id,'&date=0&modid=&modaction=&logformat=showashtml','">','Logs','</a>') AS 'Logs'<br />
<br />
, CONCAT('<a target="_blank" href="%%WWWROOT%%/report/outline/user.php',CHAR(63),'id=',u.id,'&course=',c.id,'&mode=outline">','Outline','</a>') AS 'Activity Outline'<br />
<br />
, CONCAT('<a target="_blank" href="%%WWWROOT%%/report/outline/user.php',CHAR(63),'id=',u.id,'&course=',c.id,'&mode=complete">','Activity','</a>') AS 'Consolidated Activity'<br />
<br />
, CONCAT('<a target="_blank" href="%%WWWROOT%%/mod/forum/user.php',CHAR(63),'id=',u.id,'&course=',c.id,'">','Posts','</a>') AS 'Posts'<br />
<br />
FROM prefix_user AS u<br />
JOIN prefix_role_assignments AS ra ON u.id = ra.userid<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
JOIN prefix_course_categories as cc ON c.category = cc.id<br />
<br />
# student academic coach - you can include custom profile field data with these methods<br />
# LEFT JOIN prefix_user_info_data as uid ON u.id = uid.userid AND uid.fieldid = '2'<br />
# student academic coach email<br />
# LEFT JOIN prefix_user_info_data as uce on u.id = uce.userid AND uce.fieldid = '6'<br />
<br />
LEFT JOIN prefix_logstore_standard_log AS l ON l.userid = u.id AND l.courseid = c.id AND l.crud IN ('c','u')<br />
<br />
WHERE ra.roleid =5<br />
AND ctx.instanceid = c.id<br />
<br />
AND c.id = %%COURSEID%%<br />
<br />
GROUP BY u.idnumber<br />
<br />
ORDER BY u.lastname, u.firstname<br />
</code><br />
<br />
===My Weekly Online Participation===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
Displays participation of the '''current user''' in the '''current course''' by week, including pre-term and post-term submissions/edits. A submission/edit is defined as a change to the course, such as a discussion post, the submission of an assignment, or the completion of a quiz, as well as alterations to course content such as database entries or new course activities or resources (if permitted).<br />
<br />
This report uses Standard Logs (post 2.7).<br />
<br />
<code sql><br />
SELECT <br />
<br />
l.component AS 'activity'<br />
<br />
, COUNT(DISTINCT IF((l.timecreated-c.startdate)<0,l.id,NULL)) AS 'Before Term'<br />
<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=0,l.id,NULL)) AS 'Week 1'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=1,l.id,NULL)) AS 'Week 2'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=2,l.id,NULL)) AS 'Week 3'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=3,l.id,NULL)) AS 'Week 4'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=4,l.id,NULL)) AS 'Week 5'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=5,l.id,NULL)) AS 'Week 6'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=6,l.id,NULL)) AS 'Week 7'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=7,l.id,NULL)) AS 'Week 8'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=8,l.id,NULL)) AS 'Week 9'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=9,l.id,NULL)) AS 'Week 10'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=10,l.id,NULL)) AS 'Week 11'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=11,l.id,NULL)) AS 'Week 12'<br />
<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))>=12,l.id,NULL)) AS 'After Term'<br />
<br />
, COUNT(l.id) AS 'Total'<br />
<br />
FROM prefix_user AS u<br />
JOIN prefix_role_assignments AS ra ON u.id = ra.userid<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
JOIN prefix_course_categories as cc ON c.category = cc.id<br />
<br />
LEFT JOIN prefix_logstore_standard_log AS l ON l.userid = u.id AND l.courseid = c.id AND l.crud IN ('c','u')<br />
<br />
WHERE 1<br />
AND ctx.instanceid = c.id<br />
<br />
AND c.id = %%COURSEID%%<br />
AND u.id = %%USERID%%<br />
<br />
GROUP BY l.component<br />
<br />
ORDER BY l.component<br />
</code><br />
<br />
===Faculty/Student Interactions===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
Returns a count of instructor and other-student responses to student activity for the specified time period. This report can help indicate whether students' comments are being responded to, as well as summarizing post activity by students during the specified time.<br />
<br />
'''Note''': This version of the report uses legacy (pre-2.7) logs. See below for the post-2.7 Standard Logs version.<br />
<br />
'''Note''': This should be defined as a "Global" report (visible from within all courses). <br />
<br />
'''Note''': This report can take a long time to run. <br />
<br />
<br />
<code sql><br />
SELECT <br />
<br />
# Identify student<br />
CONCAT('<a target="_blank" href="%%WWWROOT%%/message/index.php?id=' , allstu.id , '">' , allstu.firstname , ' ' , allstu.lastname , '</a>' ) AS 'Student - click to send message'<br />
<br />
, IF((COUNT(DISTINCT IF(fps.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fps.id,NULL) )>0) OR (COUNT(DISTINCT IF(asb.timemodified > (UNIX_TIMESTAMP() - (7*24*60*60)),asb.id,NULL))>0) OR (SELECT COUNT(DISTINCT mfs.id) FROM prefix_message AS mfs WHERE mfs.useridfrom = allstu.id AND mfs.useridto = instr.id AND mfs.timecreated > (UNIX_TIMESTAMP() - (7*24*60*60))),'YES','NO') AS 'Student Participated This week'<br />
<br />
, IF((COUNT(DISTINCT IF(fpi.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpi.id,NULL) )>0) OR (COUNT(DISTINCT IF(asg.timemodified > (UNIX_TIMESTAMP() - (7*24*60*60)),asg.id,NULL))>0) OR (SELECT COUNT(DISTINCT mts.id) FROM prefix_message AS mts WHERE mts.useridfrom = instr.id AND mts.useridto = allstu.id AND mts.timecreated > (UNIX_TIMESTAMP() - (7*24*60*60))),'YES','NO') AS 'Student Contacted This week'<br />
<br />
## Only posts within last 7 days<br />
<br />
# Count posts by student<br />
, COUNT(DISTINCT IF(fps.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fps.id,NULL)) AS 'Forum Stu Posts - 7 days'<br />
<br />
# Count replies to student posts by instructors<br />
, COUNT(DISTINCT IF(fpi.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpi.id,NULL) ) AS 'Forum Instr Replies - 7 days'<br />
<br />
# using link back to student posts on replies, get unique student IDs responded<br />
, COUNT(DISTINCT IF(fpsr.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpsr.id,NULL)) - COUNT(DISTINCT IF(fpi.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpi.id,NULL) ) AS 'Forum Stu Replies - 7 days'<br />
<br />
# all replies<br />
, COUNT(DISTINCT IF(fpsr.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpsr.id,NULL)) AS 'Forum All Replies - 7 days'<br />
<br />
# add in count of graded assignments - 7 days<br />
, COUNT(DISTINCT IF(asb.timemodified > (UNIX_TIMESTAMP() - (7*24*60*60)),asb.id,NULL)) AS 'Assign Submit - 7 days'<br />
, COUNT(DISTINCT IF(asg.timemodified > (UNIX_TIMESTAMP() - (7*24*60*60)),asg.id,NULL)) AS 'Assign Grades - 7 days'<br />
<br />
# Messages between students and instructors - 7 days<br />
, (SELECT COUNT(DISTINCT mfs.id) FROM prefix_message AS mfs WHERE mfs.useridfrom = allstu.id AND mfs.useridto = instr.id AND mfs.timecreated > (UNIX_TIMESTAMP() - (7*24*60*60))) AS 'Msg Stu to Instr - 7 days'<br />
, (SELECT COUNT(DISTINCT mts.id) FROM prefix_message AS mts WHERE mts.useridfrom = instr.id AND mts.useridto = allstu.id AND mts.timecreated > (UNIX_TIMESTAMP() - (7*24*60*60))) AS 'Msg Instr to Stu - 7 days'<br />
<br />
## All posts in course so far<br />
# Count posts by student<br />
, COUNT(DISTINCT fps.id) AS 'Forum Stu Posts - to date'<br />
<br />
# Count replies to student posts by instructors<br />
, COUNT(DISTINCT fpi.id) AS 'Forum Instr Replies - to date'<br />
<br />
# using link back to student posts on replies, get unique student IDs responded<br />
, COUNT(DISTINCT fpsr.id) - COUNT(DISTINCT fpi.id) AS 'Forum Stu Replies - to date'<br />
<br />
# all replies<br />
, COUNT(DISTINCT fpsr.id) AS 'Forum All Replies - to date'<br />
<br />
# add in count of graded assignments - whole course<br />
, COUNT(DISTINCT asb.id) AS 'Assign Submit - to date'<br />
, COUNT(DISTINCT asg.id) AS 'Assign Grades - to date'<br />
<br />
# Messages between students and instructors - to date<br />
, (SELECT COUNT(DISTINCT mfs.id) FROM prefix_message AS mfs WHERE mfs.useridfrom = allstu.id AND mfs.useridto = instr.id ) AS 'Msg Stu to Instr - to date'<br />
, (SELECT COUNT(DISTINCT mts.id) FROM prefix_message AS mts WHERE mts.useridfrom = instr.id AND mts.useridto = allstu.id) AS 'Msg Instr to Stu - to date'<br />
<br />
## JOINS<br />
<br />
# Start by getting all the students in the course<br />
FROM prefix_user AS allstu <br />
JOIN prefix_role_assignments AS ras ON allstu.id = ras.userid AND ras.roleid = 5<br />
JOIN prefix_context AS ctx ON ras.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
JOIN prefix_course_categories as cc ON c.category = cc.id<br />
<br />
# Now we get the forums and forum discussions from this course only<br />
LEFT JOIN prefix_forum AS frm ON frm.course = c.id AND c.id = %%COURSEID%%<br />
LEFT JOIN prefix_forum_discussions AS fd ON fd.course = %%COURSEID%% AND fd.forum = frm.id<br />
<br />
# These are forum discussion posts just by students within specified time<br />
LEFT JOIN prefix_forum_posts AS fps ON fps.userid = allstu.id AND fps.discussion = fd.id<br />
<br />
# Separately, we connect the instructors of the courses<br />
# We can use the context we have already gotten for the students<br />
LEFT JOIN prefix_role_assignments AS rai ON rai.contextid = ctx.id<br />
LEFT JOIN prefix_user AS instr ON instr.id = rai.userid AND rai.roleid =3<br />
<br />
# Now we will connect to posts by instructors that are replies to student posts<br />
# This is a left join, because we don't want to eliminate any students from the list<br />
LEFT JOIN prefix_forum_posts AS fpi ON fpi.discussion = fd.id AND fpi.userid = instr.id AND fpi.parent = fps.id<br />
<br />
# To get identities of only those students who were replied to:<br />
# Connect from instr replies back up to parent posts by students again<br />
# This has to be a LEFT JOIN, we know these posts exist but don't eliminate non-responded students<br />
LEFT JOIN prefix_forum_posts AS fpir ON fpir.id = fpi.parent<br />
<br />
# We also want to know if students are replying to one another<br />
# These are posts that are replies to student posts<br />
# Again, a left join<br />
LEFT JOIN prefix_forum_posts AS fpsr ON fpsr.discussion = fd.id AND fpsr.parent = fps.id<br />
<br />
# get the activity modules<br />
LEFT JOIN prefix_course_modules AS cm ON c.id = cm.course<br />
<br />
# get the assignments<br />
LEFT JOIN prefix_assign AS a ON cm.instance = a.id<br />
LEFT JOIN prefix_assign_submission AS asb ON a.id = asb.assignment AND asb.userid=allstu.id <br />
LEFT JOIN prefix_assign_grades AS asg ON asg.assignment = a.id AND asg.userid = allstu.id AND asg.assignment = asb.assignment <br />
<br />
# We care about messages that involve both the instructor and students of this course<br />
# messages from instructor to students:<br />
# LEFT JOIN prefix_message AS mts ON mts.useridfrom = instr.id AND mts.useridto = allstu.id<br />
# LEFT JOIN prefix_message AS mfs ON mfs.useridfrom = instr.id AND mfs.useridto = allstu.id<br />
<br />
WHERE <br />
c.id = %%COURSEID%% <br />
<br />
# GROUP BY c.shortname , allstu.id<br />
GROUP BY allstu.id<br />
<br />
ORDER BY allstu.lastname<br />
</code><br />
<br />
'''Note''': Post-2.7 Standard Logs version<br />
<br />
<code sql><br />
SELECT <br />
<br />
# Identify student<br />
CONCAT('<a target="_blank" href="%%WWWROOT%%/message/index.php?id=' , allstu.id , '">' , allstu.firstname , ' ' , allstu.lastname , '</a>' ) AS 'Student - click to send message'<br />
<br />
, IF((COUNT(DISTINCT IF(fps.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fps.id,NULL) )>0) OR (COUNT(DISTINCT IF(asb.timemodified > (UNIX_TIMESTAMP() - (7*24*60*60)),asb.id,NULL))>0) OR (SELECT COUNT(DISTINCT mfs.id) FROM prefix_message AS mfs WHERE mfs.useridfrom = allstu.id AND mfs.useridto = instr.id AND mfs.timecreated > (UNIX_TIMESTAMP() - (7*24*60*60))),'YES','NO') AS 'Student Participated This week'<br />
<br />
, IF((COUNT(DISTINCT IF(fpi.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpi.id,NULL) )>0) OR (COUNT(DISTINCT IF(asg.timemodified > (UNIX_TIMESTAMP() - (7*24*60*60)),asg.id,NULL))>0) OR (SELECT COUNT(DISTINCT mts.id) FROM prefix_message AS mts WHERE mts.useridfrom = instr.id AND mts.useridto = allstu.id AND mts.timecreated > (UNIX_TIMESTAMP() - (7*24*60*60))),'YES','NO') AS 'Student Contacted This week'<br />
<br />
## Only posts within last 7 days<br />
<br />
# Count posts by student<br />
, COUNT(DISTINCT IF(fps.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fps.id,NULL)) AS 'Forum Stu Posts - 7 days'<br />
<br />
# Count replies to student posts by instructors<br />
, COUNT(DISTINCT IF(fpi.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpi.id,NULL) ) AS 'Forum Instr Replies - 7 days'<br />
<br />
# using link back to student posts on replies, get unique student IDs responded<br />
, COUNT(DISTINCT IF(fpsr.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpsr.id,NULL)) - COUNT(DISTINCT IF(fpi.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpi.id,NULL) ) AS 'Forum Stu Replies - 7 days'<br />
<br />
# all replies<br />
, COUNT(DISTINCT IF(fpsr.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpsr.id,NULL)) AS 'Forum All Replies - 7 days'<br />
<br />
# add in count of graded assignments - 7 days<br />
, COUNT(DISTINCT IF(asb.timemodified > (UNIX_TIMESTAMP() - (7*24*60*60)),asb.id,NULL)) AS 'Assign Submit - 7 days'<br />
, COUNT(DISTINCT IF(asg.timemodified > (UNIX_TIMESTAMP() - (7*24*60*60)),asg.id,NULL)) AS 'Assign Grades - 7 days'<br />
<br />
# Messages between students and instructors - 7 days<br />
, (SELECT COUNT(DISTINCT mfs.id) FROM prefix_message AS mfs WHERE mfs.useridfrom = allstu.id AND mfs.useridto = instr.id AND mfs.timecreated > (UNIX_TIMESTAMP() - (7*24*60*60))) AS 'Msg Stu to Instr - 7 days'<br />
, (SELECT COUNT(DISTINCT mts.id) FROM prefix_message AS mts WHERE mts.useridfrom = instr.id AND mts.useridto = allstu.id AND mts.timecreated > (UNIX_TIMESTAMP() - (7*24*60*60))) AS 'Msg Instr to Stu - 7 days'<br />
<br />
## All posts in course so far<br />
# Count posts by student<br />
, COUNT(DISTINCT fps.id) AS 'Forum Stu Posts - to date'<br />
<br />
# Count replies to student posts by instructors<br />
, COUNT(DISTINCT fpi.id) AS 'Forum Instr Replies - to date'<br />
<br />
# using link back to student posts on replies, get unique student IDs responded<br />
, COUNT(DISTINCT fpsr.id) - COUNT(DISTINCT fpi.id) AS 'Forum Stu Replies - to date'<br />
<br />
# all replies<br />
, COUNT(DISTINCT fpsr.id) AS 'Forum All Replies - to date'<br />
<br />
# add in count of graded assignments - whole course<br />
, COUNT(DISTINCT asb.id) AS 'Assign Submit - to date'<br />
, COUNT(DISTINCT asg.id) AS 'Assign Grades - to date'<br />
<br />
# Messages between students and instructors - to date<br />
, (SELECT COUNT(DISTINCT mfs.id) FROM prefix_message AS mfs WHERE mfs.useridfrom = allstu.id AND mfs.useridto = instr.id ) AS 'Msg Stu to Instr - to date'<br />
, (SELECT COUNT(DISTINCT mts.id) FROM prefix_message AS mts WHERE mts.useridfrom = instr.id AND mts.useridto = allstu.id) AS 'Msg Instr to Stu - to date'<br />
<br />
## JOINS<br />
<br />
# Start by getting all the students in the course<br />
FROM prefix_user AS allstu <br />
JOIN prefix_role_assignments AS ras ON allstu.id = ras.userid AND ras.roleid = 5<br />
JOIN prefix_context AS ctx ON ras.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
JOIN prefix_course_categories as cc ON c.category = cc.id<br />
<br />
# Now we get the forums and forum discussions from this course only<br />
JOIN prefix_forum AS frm ON frm.course = c.id AND c.id = %%COURSEID%%<br />
JOIN prefix_forum_discussions AS fd ON fd.course = %%COURSEID%% AND fd.forum = frm.id<br />
<br />
# These are forum discussion posts just by students within specified time<br />
LEFT JOIN prefix_forum_posts AS fps ON fps.userid = allstu.id AND fps.discussion = fd.id<br />
<br />
# Separately, we connect the instructors of the courses<br />
# We can use the context we have already gotten for the students<br />
JOIN prefix_role_assignments AS rai ON rai.contextid = ctx.id<br />
JOIN prefix_user AS instr ON instr.id = rai.userid AND rai.roleid =3<br />
<br />
# Now we will connect to posts by instructors that are replies to student posts<br />
# This is a left join, because we don't want to eliminate any students from the list<br />
LEFT JOIN prefix_forum_posts AS fpi ON fpi.discussion = fd.id AND fpi.userid = instr.id AND fpi.parent = fps.id<br />
<br />
# To get identities of only those students who were replied to:<br />
# Connect from instr replies back up to parent posts by students again<br />
# This has to be a LEFT JOIN, we know these posts exist but don't eliminate non-responded students<br />
LEFT JOIN prefix_forum_posts AS fpir ON fpir.id = fpi.parent<br />
<br />
# We also want to know if students are replying to one another<br />
# These are posts that are replies to student posts<br />
# Again, a left join<br />
LEFT JOIN prefix_forum_posts AS fpsr ON fpsr.discussion = fd.id AND fpsr.parent = fps.id<br />
<br />
# get the activity modules<br />
JOIN prefix_course_modules AS cm ON c.id = cm.course<br />
<br />
# get the assignments<br />
JOIN prefix_assign AS a ON cm.instance = a.id<br />
LEFT JOIN prefix_assign_submission AS asb ON a.id = asb.assignment AND asb.userid=allstu.id <br />
LEFT JOIN prefix_assign_grades AS asg ON asg.assignment = a.id AND asg.userid = allstu.id AND asg.assignment = asb.assignment <br />
<br />
WHERE <br />
c.id = %%COURSEID%% <br />
<br />
# GROUP BY c.shortname , allstu.id<br />
GROUP BY allstu.id<br />
<br />
ORDER BY allstu.lastname<br />
</code><br />
<br />
===Student Resource Usage===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
Displays usage by students of all activities and resources in the current course by activity. Only activities and sections which are visible in the course are included. This version requires the new "Standard Logs" from Moodle 2.7+.<br />
<br />
'''Note''': This should be defined as a "Global" report (visible from within all courses). <br />
<br />
<code sql><br />
SELECT <br />
cs.section AS 'Week'<br />
, cs.name AS 'Section Name'<br />
, m.name AS 'item type'<br />
<br />
, CONCAT(<br />
COALESCE(a.name, ''), <br />
COALESCE(b.name,''), <br />
COALESCE(cert.name,''), <br />
COALESCE(chat.name,''), <br />
COALESCE(choice.name,''), <br />
COALESCE(data.name,''), <br />
COALESCE(feedback.name,''), <br />
COALESCE(folder.name,''), <br />
COALESCE(forum.name,''), <br />
COALESCE(glossary.name,''), <br />
COALESCE(imscp.name,''), <br />
COALESCE(lesson.name,''), <br />
COALESCE(p.name,''),<br />
COALESCE(questionnaire.name,''), <br />
COALESCE(quiz.name,''), <br />
COALESCE(cr.name,''), <br />
COALESCE(scorm.name,''), <br />
COALESCE(survey.name,''), <br />
COALESCE(url.name,''), <br />
COALESCE(wiki.name,''), <br />
COALESCE(workshop.name,''), <br />
COALESCE(kalvidassign.name,''), <br />
COALESCE(attendance.name,''), <br />
COALESCE(checklist.name,''), <br />
COALESCE(flashcard.name,''), <br />
COALESCE(lti.name,''), <br />
COALESCE(oublog.name,''), <br />
COALESCE(ouwiki.name,''), <br />
COALESCE(subpage.name,''), <br />
COALESCE(journal.name,''), <br />
COALESCE(lightboxgallery.name,''), <br />
COALESCE(elluminate.name,''), <br />
COALESCE(adaptivequiz.name,''), <br />
COALESCE(hotpot.name,''), <br />
COALESCE(wiziq.name,''), <br />
COALESCE(turnitintooltwo.name,''), <br />
COALESCE(kvr.name,'')<br />
) AS 'item name'<br />
<br />
<br />
, SUM(IF(l.crud IN ('r'),1,0)) AS 'total views'<br />
, SUM(IF(l.crud IN ('c','u'),1,0)) AS 'total submissions'<br />
, COUNT(DISTINCT IF(l.crud IN ('r'),u.id,NULL)) AS 'count of students who viewed'<br />
, COUNT(DISTINCT IF(l.crud IN ('c','u'),u.id,NULL)) AS 'count of students who submitted'<br />
<br />
FROM prefix_user AS u<br />
JOIN prefix_role_assignments AS ra ON u.id = ra.userid<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
JOIN prefix_course_categories as cc ON c.category = cc.id<br />
<br />
JOIN prefix_course_sections AS cs ON cs.course = c.id AND cs.section <= 14 #AND cs.section > 0<br />
LEFT JOIN prefix_course_modules AS cm ON cm.course = c.id AND cm.section = cs.id<br />
JOIN prefix_modules AS m ON m.id = cm.module AND m.name NOT LIKE 'label'<br />
<br />
LEFT JOIN prefix_assign AS a ON a.id = cm.instance AND m.name = 'assign'<br />
LEFT JOIN prefix_book AS b ON b.id = cm.instance AND m.name = 'book'<br />
LEFT JOIN prefix_certificate AS cert ON cert.id = cm.instance AND m.name = 'certificate'<br />
LEFT JOIN prefix_chat AS chat ON chat.id = cm.instance AND m.name = 'chat'<br />
LEFT JOIN prefix_choice AS choice ON choice.id = cm.instance AND m.name = 'choice'<br />
LEFT JOIN prefix_data AS data ON data.id = cm.instance AND m.name = 'data'<br />
LEFT JOIN prefix_feedback AS feedback ON feedback.id = cm.instance AND m.name = 'feedback'<br />
LEFT JOIN prefix_folder AS folder ON folder.id = cm.instance AND m.name = 'folder'<br />
LEFT JOIN prefix_forum AS forum ON forum.id = cm.instance AND m.name = 'forum'<br />
LEFT JOIN prefix_glossary AS glossary ON glossary.id = cm.instance AND m.name = 'glossary'<br />
LEFT JOIN prefix_imscp AS imscp ON imscp.id = cm.instance AND m.name = 'imscp'<br />
LEFT JOIN prefix_lesson AS lesson ON lesson.id = cm.instance AND m.name = 'lesson'<br />
LEFT JOIN prefix_page AS p ON p.id = cm.instance AND m.name = 'page'<br />
LEFT JOIN prefix_questionnaire AS questionnaire ON questionnaire.id = cm.instance AND m.name = 'questionnaire'<br />
LEFT JOIN prefix_quiz AS quiz ON quiz.id = cm.instance AND m.name = 'quiz'<br />
LEFT JOIN prefix_resource AS cr ON cr.id = cm.instance AND m.name = 'resource'<br />
LEFT JOIN prefix_scorm AS scorm ON scorm.id = cm.instance AND m.name = 'scorm'<br />
LEFT JOIN prefix_survey AS survey ON survey.id = cm.instance AND m.name = 'survey'<br />
LEFT JOIN prefix_url AS url ON url.id = cm.instance AND m.name = 'url'<br />
LEFT JOIN prefix_wiki AS wiki ON wiki.id = cm.instance AND m.name = 'wiki'<br />
LEFT JOIN prefix_workshop AS workshop ON workshop.id = cm.instance AND m.name = 'workshop'<br />
LEFT JOIN prefix_kalvidassign AS kalvidassign ON kalvidassign.id = cm.instance AND m.name = 'kalvidassign'<br />
LEFT JOIN prefix_kalvidres AS kvr ON kvr.id = cm.instance AND m.name = 'kalvidres'<br />
LEFT JOIN prefix_attendance AS attendance ON attendance.id = cm.instance AND m.name = 'attendance'<br />
LEFT JOIN prefix_checklist AS checklist ON checklist.id = cm.instance AND m.name = 'checklist'<br />
LEFT JOIN prefix_flashcard AS flashcard ON flashcard.id = cm.instance AND m.name = 'flashcard'<br />
LEFT JOIN prefix_lti AS lti ON lti.id = cm.instance AND m.name = 'lti'<br />
LEFT JOIN prefix_oublog AS oublog ON oublog.id = cm.instance AND m.name = 'oublog'<br />
LEFT JOIN prefix_ouwiki AS ouwiki ON ouwiki.id = cm.instance AND m.name = 'ouwiki'<br />
LEFT JOIN prefix_subpage AS subpage ON subpage.id = cm.instance AND m.name = 'subpage'<br />
LEFT JOIN prefix_journal AS journal ON journal.id = cm.instance AND m.name = 'journal'<br />
LEFT JOIN prefix_lightboxgallery AS lightboxgallery ON lightboxgallery.id = cm.instance AND m.name = 'lightboxgallery'<br />
LEFT JOIN prefix_elluminate AS elluminate ON elluminate.id = cm.instance AND m.name = 'elluminate'<br />
LEFT JOIN prefix_adaptivequiz AS adaptivequiz ON adaptivequiz.id = cm.instance AND m.name = 'adaptivequiz'<br />
LEFT JOIN prefix_hotpot AS hotpot ON hotpot.id = cm.instance AND m.name = 'hotpot'<br />
LEFT JOIN prefix_wiziq AS wiziq ON wiziq.id = cm.instance AND m.name = 'wiziq'<br />
LEFT JOIN prefix_turnitintooltwo AS turnitintooltwo ON turnitintooltwo.id = cm.instance AND m.name = 'turnitintooltwo'<br />
<br />
LEFT JOIN prefix_logstore_standard_log AS l ON l.userid = u.id AND l.courseid = c.id<br />
<br />
<br />
WHERE ra.roleid =5<br />
AND ctx.instanceid = c.id<br />
AND cs.visible = 1<br />
AND cm.visible = 1<br />
<br />
AND c.id = %%COURSEID%%<br />
<br />
GROUP BY cm.id<br />
<br />
ORDER BY cs.section<br />
</code><br />
<br />
===Module activity (Hits) between dates===<br />
<code sql><br />
SELECT module, COUNT( * ) <br />
FROM prefix_logstore_standard_log AS l<br />
WHERE (FROM_UNIXTIME( l.`timecreated` ) BETWEEN '2018-10-01 00:00:00' AND '2019-09-31 00:00:00')<br />
GROUP BY module<br />
</code><br />
<br />
===Module activity (Instances and Hits) for each academic year===<br />
<code sql><br />
SELECT name<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_logstore_standard_log AS l<br />
WHERE (FROM_UNIXTIME(l.`timecreated`) BETWEEN '2017-10-01 00:00:00' AND '2018-09-31 00:00:00')<br />
AND l.module = m.name AND l.action = 'add'<br />
) AS "Added 2017"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_logstore_standard_log AS l<br />
WHERE (FROM_UNIXTIME(l.`timecreated`) BETWEEN '2017-10-01 00:00:00' AND '2018-09-31 00:00:00')<br />
AND l.module = m.name<br />
) AS "Used 2017"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_logstore_standard_log AS l<br />
WHERE (FROM_UNIXTIME(l.`timecreated`) BETWEEN '2018-10-01 00:00:00' AND '2019-09-31 00:00:00')<br />
AND l.module = m.name AND l.action = 'add'<br />
) AS "Added 2018"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_logstore_standard_log AS l<br />
WHERE (FROM_UNIXTIME(l.`timecreated`) BETWEEN '2018-10-01 00:00:00' AND '2019-09-31 00:00:00')<br />
AND l.module = m.name<br />
) AS "Used 2018"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_logstore_standard_log AS l<br />
WHERE (FROM_UNIXTIME(l.`timecreated`) BETWEEN '2019-10-01 00:00:00' AND '2020-09-31 00:00:00')<br />
AND l.module = m.name AND l.action = 'add'<br />
) AS "Added 2019"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_logstore_standard_log AS l<br />
WHERE (FROM_UNIXTIME(l.`timecreated`) BETWEEN '2019-10-01 00:00:00' AND '2020-09-31 00:00:00')<br />
AND l.module = m.name<br />
) AS "Used 2019"<br />
<br />
FROM mdl_modules AS m<br />
</code><br />
<br />
===Unique user sessions per day and month + graph===<br />
The "graph" column is used when displaying a graph (which needs at least three columns to pick from)<br />
<code sql><br />
SELECT COUNT(DISTINCT userid) AS "Unique User Logins"<br />
,DATE_FORMAT(FROM_UNIXTIME(timecreated), "%y /%m / %d") AS "Year / Month / Day", "Graph" <br />
FROM `mdl_logstore_standard_log` <br />
WHERE action LIKE 'loggedin'<br />
#AND timecreated > UNIX_TIMESTAMP('2015-01-01 00:00:00') # optional start date<br />
#AND timecreated <= UNIX_TIMESTAMP('2015-01-31 23:59:00') # optional end date<br />
GROUP BY MONTH(FROM_UNIXTIME(timecreated)), DAY(FROM_UNIXTIME(timecreated))<br />
ORDER BY MONTH(FROM_UNIXTIME(timecreated)), DAY(FROM_UNIXTIME(timecreated))<br />
</code><br />
<br />
And...<br />
<br />
Counting user's global and unique hits per day + counting individual usage of specific activities and resources (on that day),<br />
<br />
And since I am using phpMyAdmin's "Display Graph" feature (at the bottom of the query's output page), I have scaled down the "User Hits" by 10 to fit the graph. that's it.<br />
<code sql><br />
SELECT DATE_FORMAT(FROM_UNIXTIME(timecreated), "%y-%m-%d") AS "Datez"<br />
,COUNT(DISTINCT userid) AS "Unique Users"<br />
,ROUND(COUNT(*)/10) "User Hits (K)"<br />
,SUM(IF(component='mod_quiz',1,0)) "Quizzes"<br />
,SUM(IF(component='mod_forum' or component='mod_forumng',1,0)) "Forums"<br />
,SUM(IF(component='mod_assign',1,0)) "Assignments"<br />
,SUM(IF(component='mod_oublog',1,0)) "Blogs"<br />
,SUM(IF(component='mod_resource',1,0)) "Files (Resource)"<br />
,SUM(IF(component='mod_url',1,0)) "Links (Resource)"<br />
,SUM(IF(component='mod_page',1,0)) "Pages (Resource)"<br />
<br />
FROM `mdl_logstore_standard_log` <br />
WHERE 1=1<br />
AND timecreated > UNIX_TIMESTAMP('2015-03-01 00:00:00') # optional START DATE<br />
AND timecreated <= UNIX_TIMESTAMP('2015-05-31 23:59:00') # optional END DATE<br />
GROUP BY MONTH(FROM_UNIXTIME(timecreated)), DAY(FROM_UNIXTIME(timecreated))<br />
ORDER BY MONTH(FROM_UNIXTIME(timecreated)), DAY(FROM_UNIXTIME(timecreated))<br />
</code><br />
<br />
===System wide, daily unique user hits for the last 7 days===<br />
<code sql><br />
SELECT<br />
DATE_FORMAT(FROM_UNIXTIME(l.timecreated), '%m%d') 'Day'<br />
,COUNT(DISTINCT l.userid) AS 'Distinct Users Hits'<br />
,COUNT( l.userid) AS 'Users Hits'<br />
<br />
FROM prefix_logstore_standard_log AS l<br />
WHERE l.courseid > 1<br />
AND FROM_UNIXTIME(l.timecreated) >= DATE_SUB(NOW(), INTERVAL 7 DAY)<br />
GROUP BY DAY(FROM_UNIXTIME(timecreated))<br />
</code><br />
<br />
===User detailed activity in course modules===<br />
Considering only several modules: url, resource, forum, quiz, questionnaire.<br />
<br />
<code sql><br />
SELECT u.id, ra.roleid,<br />
CONCAT(u.lastname, ' ', u.firstname) AS 'Student'<br />
,COUNT(l.id) AS 'Actions'<br />
,l.component "Module type"<br />
,l.objectid "Module ID"<br />
,CASE <br />
WHEN l.component = 'mod_url' THEN (SELECT u.name FROM mdl_url AS u WHERE u.id = l.objectid )<br />
WHEN l.component = 'mod_resource' THEN (SELECT r.name FROM mdl_resource AS r WHERE r.id = l.objectid )<br />
WHEN l.component = 'mod_forum' THEN (SELECT f.name FROM mdl_forum AS f WHERE f.id = l.objectid )<br />
WHEN l.component = 'mod_quiz' THEN (SELECT q.name FROM mdl_quiz AS q WHERE q.id = l.objectid )<br />
WHEN l.component = 'mod_questionnaire' THEN (SELECT q.name FROM mdl_questionnaire AS q WHERE q.id = l.objectid )<br />
END AS 'Module name'<br />
<br />
,(SELECT GROUP_CONCAT(g.name) FROM mdl_groups AS g<br />
JOIN mdl_groups_members AS m ON g.id = m.groupid WHERE g.courseid = l.courseid AND m.userid = u.id) "user_groups"<br />
<br />
,(SELECT s.name <br />
FROM mdl_course_modules AS cm <br />
JOIN mdl_course_sections AS s ON s.course = cm.course AND s.id = cm.section <br />
WHERE cm.id = l.contextinstanceid) AS "Section name"<br />
<br />
FROM mdl_logstore_standard_log AS l <br />
JOIN mdl_user AS u ON u.id = l.userid<br />
JOIN mdl_role_assignments AS ra ON ra.userid = l.userid <br />
AND ra.contextid = (SELECT id FROM mdl_context WHERE instanceid = l.courseid AND contextlevel = 50) <br />
WHERE l.courseid = %%COURSEID%%<br />
AND l.component IN ('mod_url', 'mod_resource', 'mod_forum', 'mod_quiz', 'mod_questionnaire') <br />
%%FILTER_STARTTIME:l.timecreated:>%% %%FILTER_ENDTIME:l.timecreated:<%%<br />
<br />
GROUP BY u.id, l.component<br />
ORDER BY u.lastname, u.firstname<br />
</code><br />
<br />
===What teachers and courses considered active?===<br />
This report display several calculations and parameters that help the Online academic training team find teachers that might need more support getting their courses more supporting of online learning pedagogical methodologies. <br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',<br />
course.id,'">',course.fullname,'</a>') AS Course <br />
<br />
#,course.shortname<br />
<br />
,CASE <br />
WHEN course.fullname LIKE '%2012%' THEN '2012'<br />
WHEN course.fullname LIKE '%2013%' THEN '2013' <br />
WHEN course.fullname LIKE '%2014%' THEN '2014'<br />
WHEN course.fullname LIKE '%2015%' THEN '2015'<br />
END AS Year<br />
<br />
,CASE <br />
WHEN course.fullname LIKE '%semester a%' THEN 'Spring semester'<br />
WHEN course.fullname LIKE '%semester b%' THEN 'Fall semester'<br />
WHEN course.fullname LIKE '%semester s%' THEN 'Summer semester'<br />
END AS Semester<br />
<br />
,IF(course.startdate>0, DATE_FORMAT(FROM_UNIXTIME(startdate), '%d-%m-%Y'), 'no date') AS "Course Start Date" <br />
<br />
,(SELECT COUNT( ra.userid ) AS Users<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = course.id<br />
) AS Students<br />
<br />
,(SELECT COUNT( ra.userid ) AS Users<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 4 AND ctx.instanceid = course.id<br />
) AS "Assistant teacher"<br />
<br />
,(SELECT COUNT( ra.userid ) AS Users<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 3 AND ctx.instanceid = course.id<br />
) AS Teachers<br />
<br />
# Uncomment to use the new Moodle 2.8+ logstore<br />
#,(SELECT COUNT(*) FROM mdl_logstore_standard_log AS l WHERE l.courseid = course.id) AS Hits<br />
<br />
#,(SELECT COUNT(*)<br />
#FROM mdl_logstore_standard_log AS l<br />
#JOIN mdl_role_assignments AS ra ON ra.userid= l.userid AND ra.roleid = 5 AND ra.contextid = (SELECT id FROM mdl_context WHERE instanceid = l.courseid AND contextlevel = 50) <br />
#WHERE l.courseid = course.id ) AS "Student HITs"<br />
<br />
#,(SELECT COUNT(*)<br />
#FROM mdl_logstore_standard_log AS l<br />
#JOIN mdl_role_assignments AS ra ON ra.userid= l.userid AND ra.roleid = 3 AND ra.contextid = (SELECT id FROM mdl_context WHERE instanceid = l.courseid AND contextlevel = 50) <br />
#WHERE l.courseid = course.id ) AS "Teacher HITs"<br />
<br />
,(SELECT COUNT(*) FROM mdl_log AS l WHERE l.course = course.id) AS Hits<br />
<br />
,(SELECT COUNT(*)<br />
FROM mdl_log AS l<br />
JOIN mdl_context AS con ON con.instanceid= l.course AND con.contextlevel=50<br />
JOIN mdl_role_assignments AS ra ON ra.contextid= con.id AND ra.userid= l.userid AND ra.roleid = 5 <br />
WHERE l.course = course.id) AS "Students HITs"<br />
<br />
,(SELECT COUNT(*)<br />
FROM mdl_log AS l<br />
JOIN mdl_context AS con ON con.instanceid= l.course AND con.contextlevel=50<br />
JOIN mdl_role_assignments AS ra ON ra.contextid= con.id AND ra.userid= l.userid AND ra.roleid = 3 <br />
WHERE l.course = course.id) AS "Teachers HITs"<br />
<br />
,(SELECT GROUP_CONCAT( CONCAT( u.firstname, " ", u.lastname ) ) <br />
FROM prefix_course c<br />
JOIN prefix_context con ON con.instanceid = c.id<br />
JOIN prefix_role_assignments ra ON con.id = ra.contextid AND con.contextlevel = 50<br />
JOIN prefix_role r ON ra.roleid = r.id<br />
JOIN prefix_user u ON u.id = ra.userid<br />
WHERE r.id = 3 AND c.id = course.id<br />
GROUP BY c.id<br />
) AS Teachers<br />
<br />
,(SELECT COUNT(*) FROM prefix_course_modules cm WHERE cm.course = course.id) Modules<br />
<br />
,(SELECT COUNT(DISTINCT cm.module) FROM prefix_course_modules cm <br />
WHERE cm.course = course.id) UniqueModules<br />
<br />
,(SELECT GROUP_CONCAT(DISTINCT m.name) <br />
FROM prefix_course_modules cm <br />
JOIN mdl_modules as m ON m.id = cm.module<br />
WHERE cm.course = course.id) UniqueModuleNames<br />
<br />
,(SELECT COUNT(*) FROM mdl_course_modules cm JOIN mdl_modules as m ON m.id = cm.module <br />
WHERE cm.course = course.id AND m.name IN ( 'ouwiki', 'wiki') ) "Num Wikis"<br />
<br />
,(SELECT COUNT(*) FROM mdl_course_modules cm JOIN mdl_modules as m ON m.id = cm.module <br />
WHERE cm.course = course.id AND m.name IN ( 'oublog') ) "Num Blogs"<br />
<br />
,(SELECT COUNT(*) FROM mdl_course_modules cm JOIN mdl_modules as m ON m.id = cm.module <br />
WHERE cm.course = course.id AND m.name IN ( 'forum', 'forumng') ) "Num Forums"<br />
<br />
,(SELECT COUNT(*) FROM prefix_course_modules cm JOIN mdl_modules as m ON m.id = cm.module <br />
WHERE cm.course = course.id AND m.name IN ('resource', 'folder', 'url', 'tab', 'file', 'book', 'page') ) Resources<br />
<br />
,(SELECT COUNT(*) FROM prefix_course_modules cm JOIN mdl_modules as m ON m.id = cm.module <br />
WHERE cm.course = course.id AND m.name IN ('forum', 'forumng', 'oublog', 'page', 'file', 'url', 'wiki' , 'ouwiki') ) "Basic Activities"<br />
<br />
,(SELECT COUNT(*) FROM prefix_course_modules cm JOIN mdl_modules as m ON m.id = cm.module <br />
WHERE cm.course = course.id AND m.name IN ('advmindmap', 'assign', 'attendance', 'book', 'choice', 'folder', 'tab', 'glossary', 'questionnaire', 'quiz', 'label' ) ) "Avarage Activities"<br />
<br />
,(SELECT COUNT(*) FROM prefix_course_modules cm JOIN mdl_modules as m ON m.id = cm.module <br />
WHERE cm.course = course.id AND m.name IN ('elluminate', 'game', 'workshop') ) "Advanced Activities"<br />
<br />
FROM prefix_course AS course<br />
<br />
#WHERE course.shortname LIKE '%2015%'<br />
#WHERE 1=1<br />
#%%FILTER_SEARCHTEXT:course.shortname:~%%<br />
<br />
WHERE course.fullname LIKE '%2015%' <br />
<br />
HAVING Modules > 2<br />
ORDER BY UniqueModules DESC<br />
</code><br />
<br />
===Weekly attendance report===<br />
This report display weekly report in format HH:M:SS This MySQL query works together with AttendaceRegister module, and gather Log information from Attendanceregister_log table. <br />
<code sql><br />
SELECT u.username, SEC_TO_TIME (SUM(arsess.duration)) AS weekly_online_attendance, FROM_UNIXTIME (arsess.logout) AS Last_Logout<br />
FROM prefix_attendanceregister_session AS arsess<br />
JOIN prefix_user AS u ON arsess.userid = u.id<br />
<br />
WHERE (((arsess.logout) BETWEEN UNIX_TIMESTAMP(DATE_SUB(CURDATE(), INTERVAL 7 DAY)) AND UNIX_TIMESTAMP(CURDATE())))<br />
<br />
GROUP BY arsess.userid<br />
</code><br />
<br />
===How many distinct users connected to Moodle using the app by month===<br />
https://moodle.org/mod/forum/discuss.php?d=336086#p1354194 by <br />
Iñigo Zendegi Urzelai<br />
<code sql><br />
SELECT <br />
to_char(to_timestamp("timecreated"),'YYYY') as year, <br />
to_char(to_timestamp("timecreated"),'MM') as month, <br />
count(distinct userid) as distinct_users<br />
<br />
FROM mdl_logstore_standard_log m<br />
WHERE m.origin='ws'<br />
GROUP BY to_char(to_timestamp("timecreated"),'YYYY'), to_char(to_timestamp("timecreated"),'MM') <br />
ORDER BY to_char(to_timestamp("timecreated"),'YYYY'), to_char(to_timestamp("timecreated"),'MM');<br />
</code><br />
<br />
==Course Reports==<br />
===Most Active courses===<br />
<code sql><br />
SELECT count(l.userid) AS Views<br />
FROM `mdl_logstore_standard_log` l, `mdl_user` u, `mdl_role_assignments` r<br />
WHERE l.courseid=35<br />
AND l.userid = u.id<br />
AND (l.timecreated > UNIX_TIMESTAMP('2015-01-01 00:00:00') AND l.timecreated <= UNIX_TIMESTAMP('2015-01-31 23:59:59'))AND r.contextid= (<br />
SELECT id<br />
FROM mdl_context<br />
WHERE contextlevel=50 AND instanceid=l.courseid<br />
)<br />
AND r.roleid=5<br />
AND r.userid = u.id<br />
</code><br />
<br />
===Active courses, advanced===<br />
Including: Teacher's name, link to the course, All types of log activities, special YEAR generated field, Activities and Resource count, enrolled Student count<br />
<code sql><br />
SELECT COUNT(l.id) hits, concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS Course <br />
<br />
,(SELECT CONCAT(u.firstname,' ', u.lastname) AS Teacher<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS Teacher<br />
<br />
,CASE <br />
WHEN c.fullname LIKE '%תשע' THEN 'תשע'<br />
WHEN c.fullname LIKE '%תשעא' THEN 'תשעא'<br />
WHEN c.fullname LIKE '%תשעב' THEN 'תשעב'<br />
END AS Year<br />
<br />
,(SELECT count(*) FROM prefix_course_modules cm WHERE cm.course = l.course) Modules<br />
<br />
,(SELECT Count( ra.userid ) AS Users FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = c.id) AS Students<br />
<br />
FROM prefix_log l <br />
INNER JOIN prefix_course c ON l.course = c.id<br />
GROUP BY c.id<br />
#The following line restricts the courses returned to those having more than 2 modules. Adjust based on your needs.<br />
HAVING Modules > 2<br />
ORDER BY Year DESC, hits DESC<br />
</code><br />
<br />
=== Least active or probably empty courses===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
It is difficult to know sometimes when a course is actually empty or was never really in use. Other than the simple case where the course was created and never touched again, in which case the course timecreated and timemodified will be the same, many courses created as shells for teachers or other users may be used once or a few times and have few or no test users enrollments in them. This query helps you see the range of such courses, showing you how many days if any it was used after initial creation, and how many user are enrolled. It denotes a course never ever modified by "-1" instead of "0" so you can sort those to the top. By default it limits this to courses used within 60 days of creation, and to courses with 3 or less enrollments (for example, teacher and assistant and test student account only.) You can easily adjust these numbers. The query includes a link to the course as well. <br />
<br />
<code sql><br />
SELECT<br />
c.fullname,<br />
CONCAT('<a target="_blank" href="%%WWWROOT%%/course/view.php',CHAR(63),'id=',c.id,'">',c.shortname,'</a>') AS 'CourseLink',<br />
DATE_FORMAT(FROM_UNIXTIME(c.timecreated), '%Y-%m-%d %H:%i') AS 'Timecreated',<br />
DATE_FORMAT(FROM_UNIXTIME(c.timemodified), '%Y-%m-%d %H:%i') AS 'Timemodified',<br />
CASE<br />
WHEN c.timecreated = c.timemodified THEN '-1'<br />
ELSE DATEDIFF(FROM_UNIXTIME(c.timemodified),FROM_UNIXTIME(c.timecreated))<br />
END AS 'DateDifference',<br />
COUNT(ue.id) AS Enroled<br />
FROM prefix_course AS c<br />
JOIN prefix_enrol AS en ON en.courseid = c.id<br />
LEFT JOIN prefix_user_enrolments AS ue ON ue.enrolid = en.id<br />
WHERE DATEDIFF(FROM_UNIXTIME(c.timemodified),FROM_UNIXTIME(c.timecreated) ) < 60<br />
GROUP BY c.id<br />
HAVING COUNT(ue.id) <= 3<br />
ORDER BY c.fullname<br />
</code><br />
<br />
===Count unique teachers with courses that use at least X module (Moodle19)===<br />
You can remove the outer "SELECT COUNT(*) FROM (...) AS ActiveTeachers" SQL query and get the list of the Teachers and Courses.<br />
<code sql><br />
SELECT COUNT(*)<br />
FROM (SELECT c.id AS CourseID, c.fullname AS Course, ra.roleid AS RoleID, CONCAT(u.firstname, ' ', u.lastname) AS Teacher<br />
,(SELECT COUNT(*) FROM prefix_course_modules cm WHERE cm.course = c.id) AS Modules<br />
FROM prefix_course AS c<br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid AND ctx.contextlevel = 50 <br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE ra.roleid = 3 <br />
GROUP BY u.id<br />
HAVING Modules > 5) AS ActiveTeachers<br />
</code><br />
<br />
===RESOURCE count for each COURSE===<br />
<code sql><br />
SELECT COUNT(l.id) count, l.course, c.fullname coursename<br />
FROM prefix_resource l INNER JOIN prefix_course c on l.course = c.id<br />
GROUP BY course<br />
ORDER BY count DESC<br />
</code><br />
<br />
===Common resource types count for each Category (Moodle19)===<br />
Including sub-categories in total count.<br />
<code sql><br />
SELECT mcc.id AS mccid, CONCAT( LPAD( '', mcc.depth, '.' ) , mcc.name ) AS Category<br />
,(SELECT COUNT( * ) <br />
FROM prefix_resource AS r<br />
JOIN prefix_course AS c ON c.id = r.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%', mccid, '%' ) AND r.TYPE = 'file' AND r.reference LIKE 'http://%'<br />
) AS Links<br />
<br />
,(SELECT COUNT( * ) <br />
FROM prefix_resource AS r<br />
JOIN prefix_course AS c ON c.id = r.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%', mccid, '%' ) AND r.TYPE = 'file' AND r.reference NOT LIKE 'http://%'<br />
) AS Files<br />
<br />
,(SELECT COUNT( * ) <br />
FROM prefix_resource AS r<br />
JOIN prefix_course AS c ON c.id = r.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%', mccid, '%' ) AND r.TYPE = 'directory' <br />
) AS Folders<br />
<br />
,(SELECT COUNT( * ) <br />
FROM prefix_resource AS r<br />
JOIN prefix_course AS c ON c.id = r.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%', mccid, '%' ) AND r.TYPE = 'html' <br />
) AS Pages<br />
<br />
,(SELECT COUNT(*) <br />
FROM stats_log_context_role_course <br />
WHERE roleid = 5 AND module = 'resource' AND category = mcc.id<br />
) AS Hits<br />
<br />
FROM prefix_course_categories AS mcc<br />
ORDER BY mcc.path<br />
</code><br />
Where "stats_log_context_role_course" (in the above SQL query) is a VIEW generated by:<br />
<code sql><br />
CREATE VIEW stats_log_context_role_course AS<br />
SELECT l.course, c.category, cc.path, l.module, l.action, ra.userid, ra.roleid<br />
FROM prefix_log AS l<br />
JOIN prefix_context AS context ON context.instanceid = l.course AND context.contextlevel = 50<br />
JOIN prefix_role_assignments AS ra ON ra.userid = l.userid AND ra.contextid = context.id<br />
JOIN prefix_course AS c ON c.id = l.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
</code><br />
<br />
Same query but for Moodle2+<br />
<code sql><br />
SELECT mcc.id AS mccid, CONCAT( LPAD( '', mcc.depth, '.' ) , mcc.name ) AS Category,<br />
mcc.path,<br />
<br />
(SELECT COUNT(*) <br />
FROM prefix_url AS u<br />
JOIN prefix_course AS c ON c.id = u.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%/', mccid, '%' )<br />
) AS URLs,<br />
<br />
(SELECT COUNT(*) <br />
FROM prefix_folder AS f<br />
JOIN prefix_course AS c ON c.id = f.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%/', mccid, '%' )<br />
) AS FOLDERs,<br />
<br />
(SELECT COUNT(*) <br />
FROM prefix_page AS p<br />
JOIN prefix_course AS c ON c.id = p.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%/', mccid, '%' )<br />
) AS PAGEs,<br />
<br />
(SELECT COUNT(*) <br />
FROM prefix_book AS b<br />
JOIN prefix_course AS c ON c.id = b.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%/', mccid, '%' )<br />
) AS BOOKs,<br />
<br />
(SELECT COUNT(*) <br />
FROM prefix_label AS l<br />
JOIN prefix_course AS c ON c.id = l.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%/', mccid, '%' )<br />
) AS LABELs,<br />
<br />
(SELECT COUNT(*) <br />
FROM prefix_tab AS t<br />
JOIN prefix_course AS c ON c.id = t.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%/', mccid, '%' )<br />
) AS TABs<br />
<br />
FROM prefix_course_categories AS mcc<br />
ORDER BY mcc.path<br />
</code><br />
<br />
===Detailed Resource COUNT by Teacher in each course===<br />
<br />
Including (optional) filter by: year, semester and course id.<br />
<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS CourseID<br />
, c.id<br />
,( SELECT DISTINCT CONCAT(u.firstname,' ',u.lastname)<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_user AS u ON ra.userid = u.id<br />
JOIN prefix_context AS ctx ON ctx.id = ra.contextid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id AND ctx.contextlevel = 50 LIMIT 1) AS Teacher<br />
<br />
, (CASE <br />
WHEN c.fullname LIKE '%תשעב%' THEN '2012' <br />
WHEN c.fullname LIKE '%תשעא%' THEN '2011'<br />
END ) as Year<br />
, (CASE <br />
WHEN c.fullname LIKE '%סמסטר א%' THEN 'Semester A' <br />
WHEN c.fullname LIKE '%סמסטר ב%' THEN 'Semester B'<br />
WHEN c.fullname LIKE '%סמסטר ק%' THEN 'Semester C'<br />
END ) as Semester<br />
,COUNT(c.id) AS Total<br />
,(SELECT count(*) FROM prefix_course_modules AS cm WHERE cm.course = c.id AND cm.module= 20) AS TABs<br />
,(SELECT count(*) FROM prefix_course_modules AS cm WHERE cm.course = c.id AND cm.module= 33) AS BOOKs<br />
<br />
FROM `prefix_resource` as r <br />
JOIN `prefix_course` AS c on c.id = r.course<br />
#WHERE type= 'file' and reference NOT LIKE 'http://%' <br />
<br />
#WHERE 1=1<br />
#%%FILTER_YEARS:c.fullname%%<br />
#AND c.fullname LIKE '%2013%'<br />
<br />
GROUP BY course<br />
ORDER BY COUNT(c.id) DESC<br />
</code><br />
<br />
===Courses that are defined as using GROUPs===<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/group/index.php?id=',c.id,'">',c.fullname,'</a>') AS Course<br />
,(SELECT count(*) FROM prefix_course_modules cm WHERE cm.course = c.id) Modules<br />
,(SELECT count(*) FROM prefix_groups g WHERE g.courseid = c.id) Groups<br />
FROM `prefix_course` AS c<br />
WHERE groupmode > 0<br />
</code><br />
<br />
===Courses with Groups===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
List of all courses with Groups in them (groupmode > 0). You can also use groupmode=1 to list just Separate type groups or groupmode=2 to list Visible type groups.<br />
<br />
<code sql><br />
SELECT c.shortname, g.name, c.groupmode<br />
FROM prefix_course AS c<br />
JOIN prefix_groups AS g ON c.id = g.courseid<br />
WHERE c.groupmode > 0<br />
</code><br />
<br />
===Users enrolled in a course with groups but not assigned a group ===<br />
<br />
Displays by course all enrolled users that have not been assigned a group in courses that have groups. NOTE: This needs to be optimized.<br />
<br />
<code sql><br />
SELECT DISTINCT<br />
user2.firstname AS Firstname,<br />
user2.lastname AS Lastname,<br />
user2.email AS Email,<br />
user2.city AS City,<br />
course.fullname AS Course<br />
,(SELECT shortname FROM prefix_role WHERE id=en.roleid) AS ROLE<br />
,(SELECT name FROM prefix_role WHERE id=en.roleid) AS RoleName<br />
<br />
FROM prefix_course AS course <br />
JOIN prefix_enrol AS en ON en.courseid = course.id<br />
JOIN prefix_user_enrolments AS ue ON ue.enrolid = en.id<br />
JOIN prefix_user AS user2 ON ue.userid = user2.id<br />
JOIN prefix_groups AS g ON g.courseid = course.id<br />
<br />
WHERE ue.enrolid NOT IN (select userid from prefix_groups_members WHERE g.id=groupid)<br />
<br />
ORDER BY Course, Lastname<br />
</code><br />
<br />
===Groups in course with member list===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
List the groups in a course (replace the # by the course id number) with the members of each group.<br />
<br />
<code sql><br />
SELECT c.shortname, g.name AS Groupname, u.username<br />
FROM prefix_course AS c<br />
JOIN prefix_groups AS g ON g.courseid = c.id<br />
JOIN prefix_groups_members AS m ON g.id = m.groupid<br />
JOIN prefix_user AS u ON m.userid = u.id<br />
WHERE c.id = #<br />
</code><br />
<br />
Note: if you are using Configurable Reports block and want to perform this query on the current course you are in, then you can use a WHERE clause like this:<br />
<code sql><br />
WHERE c.id = %%COURSEID%%<br />
</code><br />
<br />
===Group Export===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
There's a [[Import_groups|group import]] function, but no export. Use this to give you a report with the proper column order and headings to export to a csv file you can then import into another course to replicate the groups. This is a simple version with just the main fields: groupname, description, enrolment key.<br />
<br />
<code sql><br />
SELECT g.name AS groupname, g.description, g.enrolmentkey<br />
FROM prefix_groups AS g <br />
JOIN prefix_course as c ON g.courseid = c.id<br />
WHERE c.id = #<br />
</code><br />
Note: if you are using Configurable Reports block and want to perform this query on the current course you are in, then you can use a WHERE clause like this:<br />
<code sql><br />
WHERE c.id = %%COURSEID%%<br />
</code><br />
<br />
===List all Courses in and below a certain category===<br />
Use this SQL code to retrieve all courses that exist in or under a set category.<br />
<br />
$s should be the id of the category you want to know about...<br />
<code sql><br />
SELECT prefix_course. * , prefix_course_categories. *<br />
FROM prefix_course, prefix_course_categories<br />
WHERE prefix_course.category = prefix_course_categories.id<br />
AND (<br />
prefix_course_categories.path LIKE '%/$s/%'<br />
OR prefix_course_categories.path LIKE '%/$s'<br />
)<br />
</code><br />
<br />
===List all Categories in one level below a certain category===<br />
Use this PHP code to retrieve a list of all categories below a certain category.<br />
<br />
$s should be the id of the top level category you are interested in.<br />
<code php><br />
<?php<br />
<br />
require_once('./config.php');<br />
<br />
$parent_id = $s;<br />
<br />
$categories= array();<br />
<br />
$categories = get_categories($parent_id);<br />
<br />
echo '<ol>';<br />
foreach ($categories as $category)<br />
{<br />
echo '<li><a href="'.$CFG->wwwroot.'/course/category.php?id='.$category->id.'">'.$category->name.'</a></li>';<br />
}<br />
echo '</ol>';<br />
<br />
?><br />
</code><br />
<br />
===Blog activity per Course (not including VIEW)===<br />
Filter activity logging to some specific Course Categories!<br />
+ link course name to actual course (for quick reference)<br />
(you can change %blog% to %wiki% to filter down all wiki activity or any other module you wish)<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',cm.course,'">',c.fullname,'</a>') as CourseID<br />
,m.name ,count(cm.id) as counter <br />
,(SELECT Count( ra.userid ) AS Users<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5<br />
AND ctx.instanceid = c.id<br />
) AS Students<br />
, ( SELECT count(id) FROM prefix_log WHERE `module` LIKE '%blog%' AND course = c.id AND action NOT LIKE '%view%' ) as BlogActivity<br />
FROM `prefix_course_modules` as cm JOIN prefix_modules as m ON cm.module=m.id JOIN prefix_course as c ON cm.course = c.id <br />
WHERE m.name LIKE '%blog%' AND c.category IN ( 8,13,15)<br />
GROUP BY cm.course,cm.module order by counter desc<br />
</code><br />
<br />
===Student's posts content in all course blogs (oublog)===<br />
<code sql><br />
SELECT <br />
b.name <br />
,op.title<br />
,op.message<br />
,( SELECT CONCAT(u.firstname, ' ',u.lastname) FROM prefix_user AS u WHERE u.id = oi.userid) AS "Username"<br />
<br />
FROM prefix_oublog_posts AS op<br />
JOIN prefix_oublog_instances AS oi ON oi.id = op.oubloginstancesid <br />
JOIN prefix_oublog as b ON b.id = oi.oublogid<br />
JOIN prefix_course AS c ON b.course = c.id<br />
<br />
WHERE c.id = %%COURSEID%%<br />
</code><br />
<br />
===All Courses which uploaded a Syllabus file===<br />
+ under specific Category<br />
+ show first Teacher in that course<br />
+ link Course's fullname to actual course<br />
<code sql><br />
SELECT<br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') as Course<br />
,c.shortname,r.name<br />
,(SELECT CONCAT(u.firstname,' ', u.lastname) as Teacher<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user as u ON u.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) as Teacher<br />
FROM prefix_resource as r <br />
JOIN prefix_course as c ON r.course = c.id<br />
WHERE ( r.name LIKE '%סילבוס%' OR r.name LIKE '%סילאבוס%' OR r.name LIKE '%syllabus%' OR r.name LIKE '%תכנית הקורס%' ) <br />
AND c.category IN (10,18,26,13,28)<br />
</code><br />
<br />
===Site-wide completed SCORM activities by Course name===<br />
This report will list all completed attempts for all SCORM activities. It is ordered first by Course name, then student's last name, then student's first name, then attempt number. Please note: the FROM_UNIXTIME command is for MySQL.<br />
<code sql><br />
SELECT u.firstname First,u.lastname Last,c.fullname Course, st.attempt Attempt,st.value Status,FROM_UNIXTIME(st.timemodified,"%m-%d-%Y") Date <br />
FROM prefix_scorm_scoes_track AS st <br />
JOIN prefix_user AS u ON st.userid=u.id<br />
JOIN prefix_scorm AS sc ON sc.id=st.scormid<br />
JOIN prefix_course AS c ON c.id=sc.course<br />
WHERE st.value='completed' <br />
ORDER BY c.fullname, u.lastname,u.firstname, st.attempt<br />
</code><br />
===All users enrolled in a course without a role===<br />
Identifies All users that are enrolled in a course but are not assigned a role.<br />
<code sql><br />
SELECT<br />
user.firstname AS Firstname,<br />
user.lastname AS Lastname,<br />
user.idnumber Employee_ID,<br />
course.fullname AS Course<br />
<br />
FROM prefix_course AS course <br />
JOIN prefix_enrol AS en ON en.courseid = course.id<br />
JOIN prefix_user_enrolments AS ue ON ue.enrolid = en.id<br />
JOIN prefix_user as user ON user.id = ue.userid<br />
<br />
WHERE user.id NOT IN (<br />
SELECT u.id<br />
FROM prefix_course AS c<br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid<br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN prefix_role AS r ON r.id = ra.roleid<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE c.id=course.id<br />
)<br />
ORDER BY Course, Lastname, Firstname<br />
<br />
</code><br />
<br />
===List course resources accumulative file size and count===<br />
This is the main (first) report, which has a link (alias) to a second report (the following on this page) which list each file in the course.<br />
<code sql><br />
SELECT c.id "CourseID", context.id "ContextID"<br />
,CONCAT('<a target="_new" href="%%WWWROOT%%/course/view.php?id=', c.id, '">', c.fullname ,'</a>') AS "Course Name"<br />
, COUNT(*) "Course Files" , ROUND( SUM( f.filesize ) /1048576 ) AS file_size_MB<br />
,CONCAT('<a target="_new" href="%%WWWROOT%%/blocks/configurable_reports/viewreport.php?alias=coursefiles&courseid=1&filter_courses=', c.id, '">List files</a>') AS "List Files"<br />
<br />
FROM mdl_files AS f<br />
JOIN mdl_context AS context ON context.id = f.contextid<br />
JOIN mdl_course AS c ON c.id = (<br />
SELECT instanceid<br />
FROM mdl_context<br />
WHERE id = SUBSTRING_INDEX( SUBSTRING_INDEX( context.path, '/' , -2 ) , '/', 1 ) )<br />
WHERE filesize >0<br />
GROUP BY c.id<br />
</code><br />
<br />
With this report, you will have to define "alias" report property to "coursefiles" for it to be able to be called from the above report.<br />
And also setup (add) a FILTER_COURSES filter. <br />
<code sql><br />
SELECT <br />
id ,CONCAT('<a target="_new" href="%%WWWROOT%%/pluginfile.php/', contextid, '/', component, '/', filearea, '/', itemid, '/', filename, '">', filename,'</a>') AS "File"<br />
,filesize, mimetype ,author, license, timecreated, component, filearea, filepath<br />
<br />
FROM mdl_files AS f<br />
WHERE filesize >0<br />
AND f.contextid<br />
IN ( SELECT id<br />
FROM mdl_context<br />
WHERE path <br />
LIKE ( SELECT CONCAT('%/',id,'/%')<br />
AS contextquery<br />
FROM mdl_context<br />
WHERE 1=1<br />
%%FILTER_COURSES:instanceid%%<br />
AND contextlevel = 50<br />
)<br />
)<br />
</code><br />
<br />
===Which courses has redundant topics===<br />
This report list several "active topics" calculations, per course. which should give an administrator some indications for which topics/sections/weeks are filled with resources and activities and which ones are empty and not used (usually, at the end of the course).<br />
<br />
The following, second SQL query, could be used to "trim" down those redundant course topics/sections/weeks by updating the course format's numsection (Number of sections) setting. (It's a per course format setting!)<br />
<br />
<code sql><br />
SELECT id, format,<br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">', c.fullname,'</a>') AS Course <br />
<br />
,(SELECT value FROM `mdl_course_format_options` WHERE `courseid` = c.id AND `format` = c.format AND `name` = 'numsections' ) AS "numsections"<br />
,(SELECT COUNT(*) FROM `mdl_course_sections` WHERE `course` = c.id AND `sequence` != '' ) AS "Non empty sections count"<br />
,(SELECT COUNT(*) FROM `mdl_course_sections` WHERE `course` = c.id ) AS "Total section count"<br />
,(SELECT COUNT(*) FROM `mdl_course_sections` WHERE `course` = c.id AND sequence IS NOT NULL) AS "Non NULL sections count"<br />
,(SELECT COUNT(*) FROM `mdl_course_sections` WHERE `course` = c.id AND name != '') AS "Non empty section Name count"<br />
,(SELECT COUNT(*) FROM mdl_course_modules cm WHERE cm.course = c.id) "Modules count"<br />
<br />
FROM mdl_course AS c<br />
</code><br />
<br />
The following SQL REPLACE query is used for "fixing" (updating) the "numsections" of a specific course format "onetopics" (you can always change it, or discard it to use this SQL REPLACE on all course formats) <br />
<code sql><br />
REPLACE INTO `mdl_course_format_options` (`id`, `courseid`, `format`, `sectionid`, `name`, `value`) <br />
SELECT NULL, c.id, 'onetopic', '0', 'numsections', (SELECT COUNT(*) FROM `mdl_course_sections` WHERE `course` = c.id AND name != '')<br />
FROM `mdl_course` c where format = 'onetopic'<br />
</code><br />
<br />
===Hidden Courses with Students Enrolled===<br />
Contributed by Eric Strom<br />
<br />
This query identifies courses with student enrollment that are currently hidden from students. Includes the defined course start date, count of students and instructors, and a clickable email link of instructor (first found record if more than one).<br />
<br />
<code sql><br />
SELECT c.visible AS Visible, <br />
DATE(FROM_UNIXTIME(c.startdate)) AS StartDate, <br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php',CHAR(63),'id=',<br />
c.id,'">',c.idnumber,'</a>') AS Course_ID,<br />
<br />
(SELECT COUNT( ra.userid ) FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = c.id) AS Students,<br />
<br />
(SELECT COUNT( ra.userid ) FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id) AS Instructors,<br />
<br />
(SELECT DISTINCT concat('<a href="mailto:',u.email,'">',u.email,'</a>')<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_user AS u ON ra.userid = u.id<br />
JOIN prefix_context AS ctx ON ctx.id = ra.contextid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id AND ctx.contextlevel = 50 LIMIT 1) AS 'Instructor_Email', <br />
<br />
now() AS Report_Timestamp<br />
<br />
FROM prefix_course AS c <br />
WHERE c.visible = 0 AND (SELECT COUNT( ra.userid ) FROM prefix_role_assignments AS ra JOIN prefix_context AS ctx ON ra.contextid = ctx.id WHERE ra.roleid = 5 AND ctx.instanceid = c.id) > 0<br />
ORDER BY StartDate, Instructor_Email, Course_ID<br />
</code><br />
<br />
<br />
==Course Design Reports==<br />
<br />
These are reports which summarize course design aspects, such as activity and resource modules per section, types of activities used, etc.<br />
<br />
===Course Content/Week===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
This report assumes that the first 14 sections in a course, not including the "0" or "Welcome" section, correspond to weeks (with "Subsections" given numbers much higher in the sequence). Of those sections, each is checked to count the number of:<br />
<br />
Forums<br />
Graded Activities (may include Forums)<br />
Resources (not including a Label)<br />
<br />
Totals of each of these types of content elements per section are provided.<br />
<br />
'''Note''': Only visible resources and activities are counted.<br />
'''Note''': this is a "Global" report. Run it within a course to see a summary of the contents of that course.<br />
<br />
<code sql><br />
SELECT<br />
<br />
cs.section AS 'Week'<br />
, cs.name AS 'Section Name'<br />
<br />
, COUNT(DISTINCT IF((gi.id IS NULL) AND (m.name NOT LIKE 'label'),cm.id,NULL)) AS 'Ungraded Resources'<br />
<br />
, COUNT(DISTINCT IF(m.name LIKE 'forum', cm.id, NULL)) AS 'Forums'<br />
<br />
, COUNT(DISTINCT IF(gi.id, cm.id, NULL)) AS 'Graded Activities'<br />
<br />
FROM prefix_course AS c<br />
JOIN prefix_course_sections AS cs ON cs.course = c.id AND cs.section <= 14 AND cs.section > 0<br />
LEFT JOIN prefix_course_modules AS cm ON cm.course = c.id AND cm.section = cs.id <br />
JOIN prefix_modules AS m ON m.id = cm.module<br />
LEFT JOIN prefix_grade_items AS gi ON gi.courseid = c.id AND gi.itemmodule = m.name AND gi.iteminstance = cm.instance<br />
<br />
WHERE <br />
cs.visible = 1<br />
AND cm.visible = 1<br />
AND c.id = %%COURSEID%%<br />
<br />
GROUP BY cs.section<br />
ORDER BY cs.section<br />
<br />
</code><br />
<br />
===Assignments and Weights===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
Returns a list of grade book categories for the current course, grade book weightings, the first type of assignment included in the category, a count of different assignment types for each category, and a count of assignments for each category.<br />
<br />
Categories with weights of 0 are not included in this report.<br />
<br />
Only visible activities are included in this report.<br />
<br />
'''Note''': This is designed to be a "Global" report in Configurable Reports.<br />
<code sql><br />
SELECT<br />
<br />
IF(gc.parent IS NOT NULL, gc.fullname, 'None') AS 'Grade Book Category'<br />
, IF(gc.parent IS NOT NULL, ROUND(gic.aggregationcoef, 2), ROUND(SUM(DISTINCT gi.aggregationcoef), 2)+ROUND(SUM(DISTINCT mgi.aggregationcoef), 2)) AS 'Category weight'<br />
<br />
, CONCAT_WS(', ',GROUP_CONCAT(DISTINCT gi.itemmodule SEPARATOR ', '), IF(mgi.id, 'manual',NULL)) AS 'Activity Types'<br />
, COUNT(DISTINCT gi.itemmodule) + IF(mgi.id,1,0) AS 'Different Activity Types'<br />
, CONCAT_WS('<br>', GROUP_CONCAT(DISTINCT gi.itemname ORDER BY gi.itemname SEPARATOR '<br>'), GROUP_CONCAT(DISTINCT mgi.itemname ORDER BY mgi.itemname SEPARATOR '<br>')) AS 'Activity Names'<br />
, COUNT(DISTINCT IF(gi.id, cm.id, NULL)) + COUNT(DISTINCT mgi.id) AS 'Activity Count'<br />
<br />
FROM prefix_course AS c<br />
<br />
#get grade categories<br />
LEFT JOIN prefix_grade_categories AS gc ON gc.courseid = c.id <br />
# back from categories to grade items to get aggregations and weights<br />
JOIN prefix_grade_items AS gic ON gic.courseid = c.id AND gic.itemtype = 'category' AND gic.aggregationcoef != 0 AND (LOCATE(gic.iteminstance, gc.path) OR (gc.parent IS NULL))<br />
<br />
# attach activities to course<br />
JOIN prefix_course_modules AS cm ON cm.course = c.id <br />
# attach grade items to activities<br />
LEFT JOIN prefix_grade_items AS gi ON gi.courseid = c.id AND gi.iteminstance = cm.instance AND gi.itemtype = 'mod' AND gi.categoryid = gc.id AND gi.hidden != 1<br />
<br />
# attach manual grade items to course-- they don't have modules<br />
LEFT JOIN prefix_grade_items AS mgi ON mgi.courseid = c.id and mgi.itemtype = 'manual' AND mgi.categoryid = gc.id<br />
<br />
WHERE <br />
cm.visible = 1<br />
AND c.id = %%COURSEID%%<br />
<br />
GROUP BY gc.id<br />
ORDER BY gc.id<br />
<br />
</code><br />
<br />
===Pre-Term Course Review===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
Provides an overview of the readiness of ONLINE, HYBRID, and BLENDED courses in the Staging category and all subcategories. Links to each course are provided. Other details:<br />
<br />
# "Required blocks" include Instructor Block (mooprofile), Activities, and the Research block.<br />
# "Instructor Details" block is not the "Instructor" block (mooprofile) automatically provided by the system. It is an optional block that can be edited by the instructor. If not edited to remove boilerplate text, it should be hidden.<br />
# All courses should be in the "Collapsed Topics" format with the "Weeks" structure.<br />
# "Weeks defined in course settings" is taken from our SIS when the course shells are created, but can be edited by faculty. "# of weeks named and visible" should usually match or exceed this value.<br />
# We recommend that each week contain at least one forum, at least one graded activity, and at least one ungraded resource.<br />
# "Syllabus updated" date is for the first attached file found with the text "syllabus" in the name. The "Days ago" calculation is included for convenience.<br />
<br />
'''Note''': At our institution, we construct categories each term, and insert a text string "staging" in the Category ID for pre-term courses during the preparation or "staging" phase of course development. We remove this text string (and change it to "production") when courses go live at the start of the new term.<br />
<br />
<code sql><br />
SELECT CONCAT('<a target="_blank" href="%%WWWROOT%%/course/view.php',CHAR(63),'id=',c.id,'">',c.shortname,'</a>') AS Course<br />
<br />
#,RIGHT(c.idnumber,2) AS Type # Specific to GSC "Instructional Method" storage<br />
<br />
#, substring_index(substr(c.shortname FROM locate('.',c.shortname)+1),'-',1) AS Section # Specific to GSC<br />
<br />
,(SELECT CONCAT('<a target="_blank" href="%%WWWROOT%%/user/view.php',CHAR(63),'id=',u.id,'">',u.lastname,', ', u.firstname,'</a>')<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS 'Instructor' <br />
<br />
,(SELECT IF((u2.description IS NULL) OR (u2.description LIKE ''),'NO', 'YES')<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u2 ON u2.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS 'Profile Has Bio'<br />
<br />
,(SELECT IF(u3.picture > 0,'YES','NO')<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u3 ON u3.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS 'Profile Has Picture'<br />
<br />
, IF(((bpi.visible IS NULL) OR (bpi.visible !=0)) AND ((bpm.visible IS NULL) OR (bpm.visible !=0)) AND ((bpa.visible IS NULL) OR (bpa.visible !=0)) AND ((bpr.visible IS NULL) OR (bpr.visible !=0)),'YES','NO') AS 'Required blocks visible'<br />
#, IF((bpm.visible IS NULL) OR (bpm.visible !=0),'YES','NO') AS 'Messages block visible'<br />
#, IF((bpa.visible IS NULL) OR (bpa.visible !=0),'YES','NO') AS 'activities block visible'<br />
#, IF((bpr.visible IS NULL) OR (bpr.visible !=0),'YES','NO') AS 'research block visible'<br />
<br />
#, IF(SUM(IF(bi.configdata LIKE 'Tzo4OiJzdGRDbGFzcyI6Mzp7czo1OiJ0aXRsZSI7czoxODoiSW5zdHJ1Y3RvciBEZXRhaWxzI%',1,0)) AND (bip.visible !=0),'YES','') AS 'Instructor Details Block visible' # This is a hack based on UUencoded string data from the title of HTML "Instructor Details" block<br />
<br />
#, IF(bi.configdata LIKE '%ZGl0IHRoaXMgYmxvY2s%','NO','') AS 'Instructor Details Block Updated' # HTML block has string 'dit this block'<br />
<br />
#, IF(COUNT(bi.id) - SUM(IF(bi.configdata LIKE 'Tzo4OiJzdGRDbGFzcyI6Mzp7czo1OiJ0aXRsZSI7czoxODoiSW5zdHJ1Y3RvciBEZXRhaWxzI%',1,0)),'YES','') AS 'possible extra instructor blocks' #looking for any HTML block with "instructor" in the title<br />
<br />
, IF(c.format='topcoll','YES', c.format) AS 'Collapsed Topics course format' # change this if you want to test for a different format<br />
, IF(cfo.value = 2, 'YES','NO') AS 'weeks structure'<br />
<br />
, cfw.value AS 'weeks defined in course settings'<br />
<br />
, COUNT(DISTINCT IF(((cs.name IS NOT NULL) AND (cs.visible = 1) AND (cs.section != '0') AND (cs.sequence IS NOT NULL)),cs.id,NULL)) AS '# of weeks named & visible (includes orphans)'<br />
<br />
, COUNT(DISTINCT IF(m.name LIKE 'forum', cm.id, NULL)) AS 'Forums'<br />
, COUNT(DISTINCT IF(m.name LIKE 'forum' ,cs.id , NULL)) AS 'Weeks with Forum'<br />
<br />
, COUNT(DISTINCT IF(gi.id, cm.id, NULL)) AS 'Activities'<br />
, COUNT(DISTINCT IF(gi.id, cs.id, NULL)) AS 'Weeks with Activities'<br />
, COUNT(DISTINCT mgi.id) AS 'Manual Grade Items'<br />
<br />
, COUNT(DISTINCT IF((gi.id IS NULL) AND (m.name NOT IN ('forum','label')),cm.id,NULL)) AS 'Resources'<br />
, COUNT(DISTINCT IF((gi.id IS NULL) AND (m.name NOT IN ('forum','label')), cs.id, NULL)) AS 'Weeks with Resources'<br />
<br />
# Here are some other things you could check for per course<br />
#,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm JOIN prefix_modules AS m ON cm.module = m.id WHERE cm.course = c.id AND m.name LIKE '%forum%') AS Forums<br />
<br />
#,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm JOIN prefix_modules AS m ON cm.module = m.id WHERE cm.course = c.id AND m.name LIKE '%quiz%') AS Quizzes<br />
<br />
#,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm JOIN prefix_modules AS m ON cm.module = m.id WHERE cm.course = c.id AND m.name LIKE '%assign%') AS Assignments<br />
<br />
#,(SELECT COUNT(prefix_resource.id) FROM prefix_resource JOIN prefix_course ON prefix_course.id = prefix_resource.course WHERE c.id = prefix_resource.course) AS Files<br />
<br />
#,(SELECT COUNT(prefix_url.id) FROM prefix_url JOIN prefix_course ON prefix_course.id = prefix_url.course WHERE c.id = prefix_url.course) AS Links<br />
<br />
,(SELECT FROM_UNIXTIME(MAX(prefix_resource.timemodified))<br />
FROM prefix_resource<br />
JOIN prefix_course ON prefix_course.id = prefix_resource.course WHERE c.id = prefix_resource.course AND prefix_resource.name LIKE '%syllabus%') AS SyllabusDate<br />
<br />
,(SELECT TO_DAYS(NOW())-TO_DAYS(FROM_UNIXTIME(MAX(prefix_resource.timemodified)))<br />
FROM prefix_resource<br />
JOIN prefix_course ON prefix_course.id = prefix_resource.course WHERE c.id = prefix_resource.course AND prefix_resource.name LIKE '%syllabus%') AS DaysAgo<br />
<br />
, IF(COUNT(DISTINCT IF(f.type LIKE 'news', f.id,NULL)),'YES','NO' ) AS 'Announcement Forum Visible'<br />
<br />
, IF(COUNT(DISTINCT IF(f.type LIKE 'news', fd.id,NULL)),'YES','NO' ) AS 'Announcement posted'<br />
<br />
FROM prefix_course AS c<br />
LEFT JOIN prefix_course_categories as cc ON c.category = cc.id<br />
LEFT JOIN prefix_context AS ctxx ON c.id = ctxx.instanceid <br />
<br />
LEFT JOIN prefix_block_positions AS bpi ON bpi.contextid = ctxx.id AND bpi.blockinstanceid = '43692' # mooprofile<br />
LEFT JOIN prefix_block_positions AS bpm ON bpm.contextid = ctxx.id AND bpm.blockinstanceid = '43962' # messages<br />
LEFT JOIN prefix_block_positions AS bpa ON bpa.contextid = ctxx.id AND bpa.blockinstanceid = '43963' # activities<br />
LEFT JOIN prefix_block_positions AS bpr ON bpr.contextid = ctxx.id AND bpr.blockinstanceid = '38368' # html research help<br />
<br />
LEFT JOIN prefix_course_sections AS cs ON cs.course = c.id AND cs.visible = 1 AND cs.sequence IS NOT NULL<br />
LEFT JOIN prefix_course_modules AS cm ON cm.course = c.id AND cm.section = cs.id <br />
LEFT JOIN prefix_modules AS m ON m.id = cm.module<br />
LEFT JOIN prefix_grade_items AS gi ON gi.courseid = c.id AND gi.itemmodule = m.name AND gi.iteminstance = cm.instance<br />
<br />
LEFT JOIN prefix_forum AS f ON f.course = c.id AND cm.instance = f.id AND cm.visible = 1<br />
LEFT JOIN prefix_forum_discussions AS fd ON fd.forum = f.id<br />
<br />
# attach manual grade items to course-- they don't have modules<br />
LEFT JOIN prefix_grade_items AS mgi ON mgi.courseid = c.id and mgi.itemtype = 'manual'<br />
<br />
LEFT JOIN prefix_course_format_options AS cfo ON cfo.courseid = c.id AND cfo.name = 'layoutstructure'<br />
LEFT JOIN prefix_course_format_options AS cfw ON cfw.courseid = c.id AND cfw.name = 'numsections'<br />
<br />
LEFT JOIN prefix_block_instances AS bi ON bi.parentcontextid = ctxx.id AND bi.blockname = 'html' AND (bi.configdata LIKE '%SW5zdHJ1Y3Rvc%' or bi.configdata LIKE '%bnN0cnVjdG9y%')<br />
LEFT JOIN prefix_block_positions AS bip ON bip.blockinstanceid = bi.id<br />
<br />
WHERE RIGHT(c.idnumber,2) IN ('OL', 'BL', 'HY') <br />
# AND substring(cc.path,2,2) IN ('26') # Staging<br />
#AND substring(cc.path,2,3) IN ('158') # UG<br />
AND cc.idnumber LIKE '%staging%'<br />
AND ctxx.contextlevel = 50<br />
<br />
GROUP BY c.shortname<br />
</code><br />
<br />
===Module instances + Module HITs by role teacher and student in course===<br />
<code sql><br />
SELECT <br />
m.name AS "Module name"<br />
, COUNT(*) AS "Module count"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_log AS l <br />
WHERE l.course = cm.course AND l.module = m.name ) AS "Hits"<br />
<br />
,(SELECT COUNT(*)<br />
FROM prefix_log AS l<br />
JOIN prefix_context AS con ON con.instanceid= l.course AND con.contextlevel=50<br />
JOIN prefix_role_assignments AS ra ON ra.contextid= con.id AND ra.userid= l.userid AND ra.roleid = 5 <br />
WHERE l.course = cm.course AND l.module = m.name) AS "Students HITs"<br />
<br />
,(SELECT COUNT(*)<br />
FROM prefix_log AS l<br />
JOIN prefix_context AS con ON con.instanceid= l.course AND con.contextlevel=50<br />
JOIN prefix_role_assignments AS ra ON ra.contextid= con.id AND ra.userid= l.userid AND ra.roleid = 3 <br />
WHERE l.course = cm.course AND l.module = m.name) AS "Teachers HITs"<br />
<br />
FROM mdl_course_modules AS cm<br />
JOIN mdl_modules AS m on m.id = cm.module<br />
WHERE cm.course = '%%COURSEID%%'<br />
GROUP BY cm.module<br />
</code><br />
<br />
===Course Syllabus===<br />
Contributed by Elizabeth Dalton, Granite State College / Moodle HQ<br />
<br />
This report requires ELIS. It runs from within a course and constructs a course syllabus based on content in the course and in the ELIS entries related to the course (Class Instance, Course Description, and Program). It is a proof-of-concept of an automated syllabus production tool. Fields such as "Course Policies" and "Teaching Philosophy" are added to the Class Instance records, and instructors enter them there. The Instructor Bio is pulled from the User Profile of all users with the Teacher role in the course.<br />
<br />
<code sql><br />
SELECT <br />
<br />
c.fullname AS 'fullname'<br />
, ec.idnumber AS 'elis-id'<br />
, DATE_FORMAT(FROM_UNIXTIME(ec.startdate), '%b %e, %Y') AS 'start'<br />
, DATE_FORMAT(FROM_UNIXTIME(ec.enddate), '%b %e, %Y') AS 'end'<br />
, ecd.name AS 'longname'<br />
, ecd.code AS 'coursecode'<br />
, ecd.credits AS 'coursecredits'<br />
, ecd.syllabus AS 'description'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'learning-outcomes'<br />
WHERE ctxecd.id = eft.contextid) AS 'outcomes'<br />
<br />
,(SELECT CONCAT('<a target="_blank" href="%%WWWROOT%%/user/view.php',CHAR(63),'id=',u.id,'">',u.firstname,' ', u.lastname,'</a> ', u.email)<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS 'Instructor' <br />
<br />
, (SELECT efc.data<br />
FROM prefix_local_eliscore_fld_data_char AS efc<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = efc.fieldid AND ef.shortname = 'term-code'<br />
WHERE ctxci.id = efc.contextid) AS 'termcode'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'prerequisites'<br />
WHERE ctxecd.id = eft.contextid) AS 'prerequisites'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'textbooks'<br />
WHERE ctxci.id = eft.contextid) AS 'textbooks'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'other-class-materials'<br />
WHERE ctxci.id = eft.contextid) AS 'other-class-materials'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'course-policies'<br />
WHERE ctxci.id = eft.contextid) AS 'course-policies'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'teaching-philosophy'<br />
WHERE ctxci.id = eft.contextid) AS 'teaching-philosophy'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'course-methods'<br />
WHERE ctxci.id = eft.contextid) AS 'course-methods'<br />
<br />
,(SELECT u2.description<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u2 ON u2.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS 'Bio'<br />
<br />
,(SELECT<br />
<br />
GROUP_CONCAT(DISTINCT CONCAT(<br />
<br />
'<tr><td style="border: solid #000 .5px">',IF(gc.parent IS NOT NULL, gc.fullname, 'None')<br />
, ' </td><td style="border: solid #000 .5px"> '<br />
,IF(gc.parent IS NOT NULL, ROUND(gic.aggregationcoef, 2), ROUND( gi.aggregationcoef, 2)+ROUND(mgi.aggregationcoef, 2))<br />
<br />
) SEPARATOR '</td></tr>')<br />
#get grade categories<br />
FROM prefix_grade_categories AS gc <br />
# back from categories to grade items to get aggregations and weights<br />
LEFT JOIN prefix_grade_items AS gic ON gic.courseid = gc.courseid AND gic.itemtype = 'category' AND gic.aggregationcoef != 0 AND (LOCATE(gic.iteminstance, gc.path) OR (gc.parent IS NULL))<br />
# attach grade items to activities<br />
LEFT JOIN prefix_grade_items AS gi ON gi.courseid = gc.courseid AND gi.itemtype = 'mod' AND gi.categoryid = gc.id AND gi.hidden != 1<br />
# attach manual grade items to course-- they don't have modules<br />
LEFT JOIN prefix_grade_items AS mgi ON mgi.courseid = gc.courseid and mgi.itemtype = 'manual' AND mgi.categoryid = gc.id<br />
WHERE gc.courseid = c.id ) AS 'grade categories'<br />
<br />
, '<table width = "50%" >' AS 'table start'<br />
, '<table width = "100%" >' AS 'table start 2'<br />
, '</table>' AS 'table end'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'activities-schedule'<br />
WHERE ctxci.id = eft.contextid) AS 'activities'<br />
<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'schedule'<br />
WHERE ctxci.id = eft.contextid) AS 'schedule'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'grading-scale'<br />
WHERE ctxepm.id = eft.contextid) AS 'gradescale'<br />
<br />
FROM<br />
prefix_course AS c <br />
<br />
# connect moodle course to ELIS class instance<br />
LEFT JOIN prefix_local_elisprogram_cls_mdl AS ecm ON ecm.moodlecourseid = c.id<br />
LEFT JOIN prefix_local_elisprogram_cls AS ec ON ec.id = ecm.classid<br />
# class instance context<br />
LEFT JOIN prefix_context AS ctxci ON ctxci.instanceid = ec.id AND ctxci.contextlevel = '14'<br />
<br />
# connect ELIS class instance to ELIS course description<br />
LEFT JOIN prefix_local_elisprogram_crs AS ecd ON ecd.id = ec.courseid<br />
# course description context<br />
LEFT JOIN prefix_context AS ctxecd ON ctxecd.instanceid = ecd.id AND ctxecd.contextlevel = '13'<br />
<br />
#connect ELIS program to ELIS Course Description<br />
LEFT JOIN prefix_local_elisprogram_pgm_crs AS epc ON epc.courseid = ecd.id<br />
LEFT JOIN prefix_local_elisprogram_pgm AS epm ON epm.id = epc.curriculumid<br />
# course program context<br />
LEFT JOIN prefix_context AS ctxepm ON ctxepm.instanceid = epm.id AND ctxepm.contextlevel = '11'<br />
<br />
WHERE<br />
<br />
c.id = %%COURSEID%%<br />
</code><br />
<br />
===Course Activities Helper===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
This report provides a list of the graded activities in a course.<br />
* '''Note''': Only graded activities are displayed.<br />
* '''Note''': This is a "Global" report. Run it within a course to see a summary of the contents of that course.<br />
* '''Note''': This report assumes that course sections each last one week.<br />
<br />
<code sql><br />
# 303 Course Activities Helper<br />
<br />
SELECT <br />
<br />
gi.itemmodule AS 'activity type'<br />
# cs.section AS 'section number'<br />
<br />
# Calculation assumes each section lasts one week<br />
, CONCAT(DATE_FORMAT(FROM_UNIXTIME(c.startdate + (7*24*60*60* (cs.section-1))), '%b %e, %Y'),' - <br>',DATE_FORMAT(FROM_UNIXTIME(c.startdate + (7*24*60*60* (cs.section))), '%b %e, %Y')) AS 'Date'<br />
<br />
, gi.itemname AS 'activity name'<br />
<br />
#, (SELECT asg.intro FROM prefix_assign AS asg WHERE asg.id = cm.instance) AS 'intro'<br />
<br />
#, (SELECT f.intro FROM prefix_forum AS f WHERE f.id = cm.instance) AS 'f intro'<br />
<br />
, CASE gi.itemmodule <br />
WHEN 'assign' THEN (SELECT asg.intro FROM prefix_assign AS asg WHERE asg.id = gi.iteminstance) <br />
WHEN 'forum' THEN (SELECT f.intro FROM prefix_forum AS f WHERE f.id = gi.iteminstance) <br />
WHEN 'quiz' THEN (SELECT q.intro FROM prefix_quiz AS q WHERE q.id = gi.iteminstance) <br />
END AS 'test case'<br />
<br />
#, (SELECT GROUP_CONCAT(CONCAT(' - ',gi.itemname) SEPARATOR '<BR>') FROM prefix_grade_items AS gi JOIN prefix_course_modules AS cm ON gi.iteminstance = cm.instance WHERE gi.gradetype = 1 AND gi.hidden != 1 AND gi.courseid = c.id AND cm.course = c.id AND cm.section = cs.id ) AS 'activities'<br />
<br />
<br />
FROM<br />
prefix_course AS c <br />
<br />
#get grade sections<br />
LEFT JOIN prefix_course_sections AS cs ON cs.course = c.id AND cs.section > 0 AND cs.section <=14<br />
LEFT JOIN prefix_course_modules AS cm ON cm.course = c.id AND cm.section = cs.id<br />
<br />
#LEFT JOIN prefix_assign AS asg ON asg.id = cm.instance<br />
<br />
JOIN prefix_grade_items AS gi ON gi.iteminstance = cm.instance AND gi.gradetype = 1 AND gi.hidden != 1 AND gi.courseid = c.id AND cm.course = c.id AND cm.section = cs.id<br />
<br />
WHERE<br />
c.id = %%COURSEID%%<br />
AND cs.visible = 1<br />
<br />
ORDER BY gi.itemmodule, cs.section<br />
</code><br />
<br />
==Grade and Course Completion Reports==<br />
===Site-Wide Grade Report with All Items===<br />
Shows grades for all course items along with course totals for each student. Works with ad-hoc reports or Configurable Reports<br />
<code sql><br />
SELECT u.firstname AS 'First' , u.lastname AS 'Last', <br />
u.firstname + ' ' + u.lastname AS 'Display Name', <br />
c.fullname AS 'Course', <br />
cc.name AS 'Category',<br />
<br />
CASE <br />
WHEN gi.itemtype = 'course' <br />
THEN c.fullname + ' Course Total'<br />
ELSE gi.itemname<br />
END AS 'Item Name',<br />
<br />
ROUND(gg.finalgrade,2) AS Grade,<br />
DATEADD(ss,gg.timemodified,'1970-01-01') AS Time<br />
<br />
FROM prefix_course AS c<br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid<br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
JOIN prefix_grade_grades AS gg ON gg.userid = u.id<br />
JOIN prefix_grade_items AS gi ON gi.id = gg.itemid<br />
JOIN prefix_course_categories as cc ON cc.id = c.category<br />
<br />
WHERE gi.courseid = c.id <br />
ORDER BY lastname<br />
</code><br />
For MySQL users, you'll need to use the MySQL DATE_ADD function instead of DATEADD. Replace the line:<br />
<code><br />
DATEADD(ss,gg.timemodified,'1970-01-01') AS Time<br />
</code><br />
with:<br />
<code><br />
FROM_UNIXTIME(gg.timemodified) AS Time<br />
</code><br />
And:<br />
<code><br />
u.firstname + ' ' + u.lastname AS 'Display Name', <br />
</code><br />
with:<br />
<code><br />
CONCAT(u.firstname,' ',u.lastname) AS 'Display Name', <br />
</code><br />
<br />
===Site-Wide Grade Report with Just Course Totals===<br />
A second site-wide grade report for all students that just shows course totals. Works with ad-hoc reports or Configurable Reports<br />
<code sql><br />
SELECT u.firstname AS 'First' , u.lastname AS 'Last', u.firstname + ' ' + u.lastname AS 'Display Name', <br />
cc.name AS 'Category',<br />
CASE <br />
WHEN gi.itemtype = 'course' <br />
THEN c.fullname + ' Course Total'<br />
ELSE gi.itemname<br />
END AS 'Item Name',<br />
<br />
ROUND(gg.finalgrade,2) AS Grade,<br />
DATEADD(ss,gg.timemodified,'1970-01-01') AS Time<br />
<br />
FROM prefix_course AS c<br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid<br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
JOIN prefix_grade_grades AS gg ON gg.userid = u.id<br />
JOIN prefix_grade_items AS gi ON gi.id = gg.itemid<br />
JOIN prefix_course_categories as cc ON cc.id = c.category<br />
<br />
WHERE gi.courseid = c.id AND gi.itemtype = 'course'<br />
<br />
ORDER BY lastname<br />
</code><br />
<br />
For MySQL users:<br />
<code sql><br />
SELECT u.firstname AS 'First' , u.lastname AS 'Last', CONCAT(u.firstname , ' ' , u.lastname) AS 'Display Name', <br />
c.fullname AS 'Course', <br />
cc.name AS 'Category',<br />
CASE <br />
WHEN gi.itemtype = 'course' <br />
THEN CONCAT(c.fullname, ' - Total')<br />
ELSE gi.itemname<br />
END AS 'Item Name',<br />
<br />
ROUND(gg.finalgrade,2) AS Grade,<br />
FROM_UNIXTIME(gg.timemodified) AS TIME<br />
<br />
FROM prefix_course AS c<br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid<br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
JOIN prefix_grade_grades AS gg ON gg.userid = u.id<br />
JOIN prefix_grade_items AS gi ON gi.id = gg.itemid<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
<br />
WHERE gi.courseid = c.id AND gi.itemtype = 'course'<br />
ORDER BY lastname<br />
</code><br />
<br />
===Learner report by Learner with grades===<br />
Which Learners in which course and what are the grades<br />
<code sql><br />
SELECT u.firstname AS 'Name' , u.lastname AS 'Surname', c.fullname AS 'Course', cc.name AS 'Category', <br />
CASE WHEN gi.itemtype = 'Course' <br />
THEN c.fullname + ' Course Total' <br />
ELSE gi.itemname <br />
END AS 'Item Name', ROUND(gg.finalgrade,2) AS Score,ROUND(gg.rawgrademax,2) AS Max, ROUND(gg.finalgrade / gg.rawgrademax * 100 ,2) as Percentage,<br />
<br />
if (ROUND(gg.finalgrade / gg.rawgrademax * 100 ,2) > 79,'Yes' , 'No') as Pass<br />
<br />
FROM prefix_course AS c <br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid <br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id <br />
JOIN prefix_user AS u ON u.id = ra.userid <br />
JOIN prefix_grade_grades AS gg ON gg.userid = u.id <br />
JOIN prefix_grade_items AS gi ON gi.id = gg.itemid <br />
JOIN prefix_course_categories AS cc ON cc.id = c.category <br />
WHERE gi.courseid = c.id and gi.itemname != 'Attendance'<br />
ORDER BY `Name` ASC<br />
</code><br />
<br />
===User Course Completion===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
A very simple report with a list of course completion status by username. Completions are noted by date, blank otherwise. <br />
<br />
<code sql><br />
SELECT <br />
u.username, <br />
c.shortname, <br />
DATE_FORMAT(FROM_UNIXTIME(p.timecompleted),'%Y-%m-%d') AS completed<br />
FROM prefix_course_completions AS p<br />
JOIN prefix_course AS c ON p.course = c.id<br />
JOIN prefix_user AS u ON p.userid = u.id<br />
WHERE c.enablecompletion = 1<br />
ORDER BY u.username<br />
</code><br />
<br />
===User Course Completion with Criteria===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
A report with course completions by username, with Aggregation method, Criteria types, and Criteria detail where available.<br />
<br />
<code sql><br />
SELECT u.username AS user, <br />
c.shortname AS course,<br />
DATE_FORMAT(FROM_UNIXTIME(t.timecompleted),'%Y-%m-%d') AS completed,<br />
CASE<br />
WHEN (SELECT a.method FROM prefix_course_completion_aggr_methd AS a WHERE (a.course = c.id AND a.criteriatype IS NULL) = 1) THEN "Any"<br />
ELSE "All"<br />
END AS aggregation,<br />
CASE <br />
WHEN p.criteriatype = 1 THEN "Self"<br />
WHEN p.criteriatype = 2 THEN "By Date"<br />
WHEN p.criteriatype = 3 THEN "Unenrol Status"<br />
WHEN p.criteriatype = 4 THEN "Activity"<br />
WHEN p.criteriatype = 5 THEN "Duration"<br />
WHEN p.criteriatype = 6 THEN "Course Grade"<br />
WHEN p.criteriatype = 7 THEN "Approve by Role"<br />
WHEN p.criteriatype = 8 THEN "Previous Course"<br />
END AS criteriatype,<br />
CASE <br />
WHEN p.criteriatype = 1 THEN "*"<br />
WHEN p.criteriatype = 2 THEN DATE_FORMAT(FROM_UNIXTIME(p.timeend),'%Y-%m-%d')<br />
WHEN p.criteriatype = 3 THEN t.unenroled<br />
WHEN p.criteriatype = 4 THEN <br />
CONCAT('<a target="_new" href="%%WWWROOT%%/mod/',p.module,'/view.php?id=',p.moduleinstance,'">',p.module,'</a>')<br />
WHEN p.criteriatype = 5 THEN p.enrolperiod<br />
WHEN p.criteriatype = 6 THEN CONCAT('Needed: ',ROUND(p.gradepass,2),' Achieved: ',ROUND(t.gradefinal,2)) <br />
WHEN p.criteriatype = 7 THEN p.role<br />
WHEN p.criteriatype = 8 THEN (SELECT pc.shortname FROM prefix_course AS pc WHERE pc.id = p.courseinstance)<br />
END AS criteriadetail <br />
FROM prefix_course_completion_crit_compl AS t<br />
JOIN prefix_user AS u ON t.userid = u.id<br />
JOIN prefix_course AS c ON t.course = c.id<br />
JOIN prefix_course_completion_criteria AS p ON t.criteriaid = p.id<br />
<br />
</code><br />
<br />
===Courses with Completion Enabled and their settings===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
List of all courses with completion enabled and their Aggregation setting, Criteria types, and Criteria details.<br />
<br />
<code sql><br />
<br />
SELECT c.shortname AS Course, <br />
CASE<br />
WHEN (SELECT a.method FROM prefix_course_completion_aggr_methd AS a WHERE (a.course = t.course AND a.criteriatype IS NULL)) = 2 THEN "All"<br />
ELSE "Any"<br />
END AS Course_Aggregation,<br />
CASE<br />
WHEN t.criteriatype = 1 THEN "Self completion"<br />
WHEN t.criteriatype = 2 THEN "Date done by" <br />
WHEN t.criteriatype = 3 THEN "Unenrolement" <br />
WHEN t.criteriatype = 4 THEN "Activity completion" <br />
WHEN t.criteriatype = 5 THEN "Duration in days" <br />
WHEN t.criteriatype = 6 THEN "Final grade" <br />
WHEN t.criteriatype = 7 THEN "Approve by role" <br />
WHEN t.criteriatype = 8 THEN "Previous course"<br />
END AS Criteria_type,<br />
CASE<br />
WHEN t.criteriatype = 1 THEN "On"<br />
WHEN t.criteriatype = 2 THEN DATE_FORMAT(FROM_UNIXTIME(t.timeend),'%Y-%m-%d')<br />
WHEN t.criteriatype = 3 THEN "On"<br />
WHEN t.criteriatype = 4 THEN<br />
CONCAT('<a target="_new" href="%%WWWROOT%%/mod/',t.module,'/view.php?id=',t.moduleinstance,'">',t.module,'</a>')<br />
WHEN t.criteriatype = 5 THEN ROUND(t.enrolperiod/86400)<br />
WHEN t.criteriatype = 6 THEN ROUND(t.gradepass,2)<br />
WHEN t.criteriatype = 7 THEN (SELECT r.shortname FROM prefix_role AS r WHERE r.id = t.role)<br />
WHEN t.criteriatype = 8 THEN (SELECT pc.shortname FROM prefix_course AS pc WHERE pc.id = t.courseinstance)<br />
END AS Criteria_detail<br />
FROM prefix_course_completion_criteria as t<br />
JOIN prefix_course AS c ON t.course = c.id<br />
WHERE c.enablecompletion = 1<br />
ORDER BY course<br />
</code><br />
<br />
===Course Completion Report with custom dates===<br />
<br />
List of users who completed multiple or single course/s from a start date to end date chosen by the user. The output gives username, name, course name, completion date and score<br />
<br />
<code sql><br />
<br />
SELECT u.username AS 'User Name',<br />
CONCAT(u.firstname , ' ' , u.lastname) AS 'Name',<br />
c.shortname AS 'Course Name', <br />
DATE_FORMAT(FROM_UNIXTIME(p.timecompleted),'%W %e %M, %Y') AS 'Completed Date',<br />
ROUND(c4.gradefinal,2) AS 'Score'<br />
FROM prefix_course_completions AS p<br />
JOIN prefix_course AS c ON p.course = c.id<br />
JOIN prefix_user AS u ON p.userid = u.id<br />
JOIN prefix_course_completion_crit_compl AS c4 ON u.id = c4.userid<br />
WHERE c.enablecompletion = 1 AND (p.timecompleted IS NOT NULL OR p.timecompleted !='') <br />
AND (p.timecompleted>= :start_date AND p.timecompleted<=:end_date)<br />
GROUP BY u.username<br />
ORDER BY c.shortname<br />
<br />
</code><br />
<br />
===Scales used in activities===<br />
<code sql><br />
SELECT scale.name<br />
,CONCAT('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS Course<br />
,CONCAT('<a target="_new" href="%%WWWROOT%%/mod/',gi.itemmodule,'/view.php?id=',cm.id,'">',gi.itemname,'</a>') AS "Module View"<br />
,CONCAT('<a target="_new" href="%%WWWROOT%%/course/modedit.php?up','date=',cm.id,'">',gi.itemname,'</a>') AS "Module Settings"<br />
<br />
FROM prefix_grade_items AS gi<br />
JOIN prefix_course AS c ON c.id = gi.courseid<br />
JOIN prefix_course_modules AS cm ON cm.course = gi.courseid AND cm.instance = gi.iteminstance<br />
JOIN prefix_scale AS scale ON scale.id = gi.scaleid<br />
WHERE gi.scaleid IS NOT NULL<br />
</code><br />
<br />
<br />
===Extra Credit Items by Name Only===<br />
Contributed by Eric Strom<br />
<br />
This query identifies grade items in visible courses with student enrollment that have "extra credit" in the name of the item but set as extra credit in the grade settings. Includes the defined course start date, count of students and instructors, and a clickable email link of instructor (first found record if more than one).<br />
<br />
<code sql><br />
SELECT DATE(FROM_UNIXTIME(c.startdate)) AS StartDate, <br />
concat('<a target="_new" href="%%WWWROOT%%/grade/edit/tree/index.php',CHAR(63),'id=',<br />
c.id,'">',c.idnumber,'</a>') AS Course_ID, gi.itemname AS Item_Name<br />
<br />
,(SELECT COUNT( ra.userid ) FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = c.id) AS Students<br />
<br />
,(SELECT COUNT( ra.userid ) FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id) AS Instructors<br />
<br />
,(SELECT DISTINCT concat('<a href="mailto:',u.email,'">',u.email,'</a>')<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_user AS u ON ra.userid = u.id<br />
JOIN prefix_context AS ctx ON ctx.id = ra.contextid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id AND ctx.contextlevel = 50 LIMIT 1) AS 'Instructor_Email'<br />
<br />
,now() AS Report_Timestamp<br />
<br />
FROM prefix_grade_items AS gi<br />
JOIN prefix_course AS c ON gi.courseid = c.id<br />
<br />
WHERE gi.itemname LIKE '%extra credit%' <br />
AND gi.gradetype = '1' <br />
AND gi.hidden = '0' <br />
AND gi.aggregationcoef = '0' <br />
AND c.visible = 1<br />
AND (SELECT COUNT( ra.userid ) FROM prefix_role_assignments AS ra JOIN prefix_context AS ctx ON ra.contextid = ctx.id WHERE ra.roleid = 5 AND ctx.instanceid = c.id) > 0<br />
<br />
GROUP BY Course_ID, gi.id<br />
ORDER BY StartDate, Course_ID<br />
<br />
%%FILTER_SEARCHTEXT:Course_ID:~%%<br />
</code><br />
<br />
===Site Wide Number of Courses Completed by User===<br />
Contributed by Ken St. John<br />
<br />
Simple report that shows the number of completed courses for all users site wide<br />
<br />
<code sql><br />
SELECT u.lastname, u.firstname,<br />
COUNT(p.timecompleted) AS TotalCompletions<br />
FROM prefix_course_completions AS p<br />
JOIN prefix_user AS u ON p.userid = u.id<br />
GROUP BY p.userid<br />
ORDER BY u.lastname<br />
</code><br />
<br />
==Activity Module Reports==<br />
<br />
=== User activity completions with dates===<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
This report shows the users completion status of activities across all courses. It is intended to be uses with Configurable Reports filters for user, start and end times, and also to be able to search the Module names. <br />
<br />
Note: The CASE statement with module numbers may differ on different systems, depending on the number give to the module when the site was created or the module added to the site. These are common default numbers, but you should check your id numbers for them in the course_modules table and adjust as required. You can also add other, third-party plugins too if you wish. <br />
<br />
<code sql><br />
SELECT<br />
u.username As 'User',<br />
c.shortname AS 'Course',<br />
m.name AS Activitytype, <br />
CASE <br />
WHEN cm.module = 1 THEN (SELECT a1.name FROM prefix_assign a1 WHERE a1.id = cm.instance)<br />
WHEN cm.module = 2 THEN (SELECT a2.name FROM prefix_assignment a2 WHERE a2.id = cm.instance)<br />
WHEN cm.module = 3 THEN (SELECT a3.name FROM prefix_book a3 WHERE a3.id = cm.instance)<br />
WHEN cm.module = 4 THEN (SELECT a4.name FROM prefix_chat a4 WHERE a4.id = cm.instance)<br />
WHEN cm.module = 5 THEN (SELECT a5.name FROM prefix_choice a5 WHERE a5.id = cm.instance)<br />
WHEN cm.module = 6 THEN (SELECT a6.name FROM prefix_data a6 WHERE a6.id = cm.instance)<br />
WHEN cm.module = 7 THEN (SELECT a7.name FROM prefix_feedback a7 WHERE a7.id = cm.instance)<br />
WHEN cm.module = 8 THEN (SELECT a8.name FROM prefix_folder a8 WHERE a8.id = cm.instance)<br />
WHEN cm.module = 9 THEN (SELECT a9.name FROM prefix_forum a9 WHERE a9.id = cm.instance)<br />
WHEN cm.module = 10 THEN (SELECT a10.name FROM prefix_glossary a10 WHERE a10.id = cm.instance)<br />
WHEN cm.module = 11 THEN (SELECT a11.name FROM prefix_imscp a11 WHERE a11.id = cm.instance)<br />
WHEN cm.module = 12 THEN (SELECT a12.name FROM prefix_label a12 WHERE a12.id = cm.instance)<br />
WHEN cm.module = 13 THEN (SELECT a13.name FROM prefix_lesson a13 WHERE a13.id = cm.instance)<br />
WHEN cm.module = 14 THEN (SELECT a14.name FROM prefix_lti a14 WHERE a14.id = cm.instance)<br />
WHEN cm.module = 15 THEN (SELECT a15.name FROM prefix_page a15 WHERE a15.id = cm.instance)<br />
WHEN cm.module = 16 THEN (SELECT a16.name FROM prefix_quiz a16 WHERE a16.id = cm.instance)<br />
WHEN cm.module = 17 THEN (SELECT a17.name FROM prefix_resource a17 WHERE a17.id = cm.instance)<br />
WHEN cm.module = 18 THEN (SELECT a18.name FROM prefix_scorm a18 WHERE a18.id = cm.instance)<br />
WHEN cm.module = 19 THEN (SELECT a19.name FROM prefix_survey a19 WHERE a19.id = cm.instance)<br />
WHEN cm.module = 20 THEN (SELECT a20.name FROM prefix_url a20 WHERE a20.id = cm.instance)<br />
WHEN cm.module = 21 THEN (SELECT a21.name FROM prefix_wiki a21 WHERE a21.id = cm.instance)<br />
WHEN cm.module = 22 THEN (SELECT a22.name FROM prefix_workshop a22 WHERE a22.id = cm.instance)<br />
END AS Actvityname,<br />
# cm.section AS Coursesection,<br />
CASE<br />
WHEN cm.completion = 0 THEN '0 None'<br />
WHEN cm.completion = 1 THEN '1 Self'<br />
WHEN cm.completion = 2 THEN '2 Auto'<br />
END AS Activtycompletiontype, <br />
CASE<br />
WHEN cmc.completionstate = 0 THEN 'In Progress'<br />
WHEN cmc.completionstate = 1 THEN 'Completed'<br />
WHEN cmc.completionstate = 2 THEN 'Completed with Pass'<br />
WHEN cmc.completionstate = 3 THEN 'Completed with Fail'<br />
ELSE 'Unknown'<br />
END AS 'Progress', <br />
DATE_FORMAT(FROM_UNIXTIME(cmc.timemodified), '%Y-%m-%d %H:%i') AS 'When'<br />
FROM prefix_course_modules_completion cmc <br />
JOIN prefix_user u ON cmc.userid = u.id<br />
JOIN prefix_course_modules cm ON cmc.coursemoduleid = cm.id<br />
JOIN prefix_course c ON cm.course = c.id<br />
JOIN prefix_modules m ON cm.module = m.id<br />
# skip the predefined admin and guest user<br />
WHERE u.id > 2<br />
# config reports filters<br />
%%FILTER_USERS:u.username%%<br />
%%FILTER_SEARCHTEXT:m.name:~%%<br />
%%FILTER_STARTTIME:cmc.timemodified:>%% %%FILTER_ENDTIME:cmc.timemodified:<%%<br />
<br />
ORDER BY u.username<br />
<br />
</code><br />
<br />
===How many SCORM activities are used in each Course===<br />
<code sql><br />
SELECT cm.course,c.fullname ,m.name <br />
,concat('<a target="_new" href="%%WWWROOT%%/mod/scorm/index.php?id=',c.id,'">',count(cm.id),'</a>') AS Counter<br />
<br />
FROM `prefix_course_modules` as cm <br />
JOIN prefix_modules as m ON cm.module=m.id <br />
JOIN prefix_course as c ON cm.course = c.id <br />
WHERE m.name LIKE '%scorm%' <br />
GROUP BY cm.course,cm.module <br />
ORDER BY count(cm.id) desc<br />
</code><br />
<br />
===SCORM Usage by Course Start Date===<br />
Contributed by Elizabeth Dalton, Granite State College <br />
<br />
Report of number of inclusions of SCORM activities in courses, filtered by course start date.<br />
<br />
<code sql><br />
SELECT <br />
<br />
CONCAT('<a target="_blank" href="%%WWWROOT%%/course/view.php',CHAR(63),'id=',c.id,'">',c.shortname,'</a>') AS 'course'<br />
<br />
, cc.name AS 'Category'<br />
, scm.name AS 'Sample Activity Name'<br />
, FROM_UNIXTIME(c.startdate) AS 'Course Start Date'<br />
, COUNT(DISTINCT cm.id) AS 'Resources Used'<br />
#, FROM_UNIXTIME(cm.added) AS 'resource added'<br />
<br />
<br />
FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id AND m.name LIKE 'SCO%'<br />
<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
JOIN prefix_scorm AS scm ON scm.id = cm.instance<br />
<br />
WHERE<br />
1<br />
<br />
%%FILTER_STARTTIME:c.startdate:>%%<br />
%%FILTER_ENDTIME:c.startdate:<%%<br />
<br />
GROUP BY c.shortname, m.name<br />
ORDER BY c.startdate, c.shortname <br />
</code><br />
<br />
=== LTI (External Tool) Usage by Course Start Date===<br />
Contributed by Elizabeth Dalton, Granite State College <br />
<br />
Report of number of inclusions of LTI (External Tool) Usage activities in courses, filtered by course start date.<br />
<br />
<code sql><br />
SELECT <br />
<br />
CONCAT('<a target="_blank" href="%%WWWROOT%%/course/view.php',CHAR(63),'id=',c.id,'">',c.shortname,'</a>') AS 'course'<br />
<br />
, cc.name AS 'Category'<br />
, lti.name AS 'Sample Activity Name'<br />
, FROM_UNIXTIME(c.startdate) AS 'Course Start Date'<br />
, COUNT(DISTINCT cm.id) AS 'Resources Used'<br />
#, FROM_UNIXTIME(cm.added) AS 'resource added'<br />
<br />
<br />
FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id AND m.name LIKE 'lti'<br />
<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
JOIN prefix_lti AS lti ON lti.id = cm.instance<br />
WHERE<br />
1<br />
<br />
%%FILTER_STARTTIME:c.startdate:>%%<br />
%%FILTER_ENDTIME:c.startdate:<%%<br />
<br />
GROUP BY c.shortname, m.name<br />
ORDER BY c.startdate, c.shortname <br />
</code><br />
<br />
===Detailed ACTIONs for each MODULE===<br />
<code sql><br />
SELECT module,action,count(id) as counter<br />
FROM prefix_log<br />
GROUP BY module,action<br />
ORDER BY module,counter desc<br />
</code><br />
<br />
===Most popular ACTIVITY===<br />
<code sql><br />
SELECT COUNT(l.id) hits, module<br />
FROM prefix_log l<br />
WHERE module != 'login' AND module != 'course' AND module != 'role'<br />
GROUP BY module<br />
ORDER BY hits DESC<br />
</code><br />
<br />
===System wide use of ACTIVITIES and RESOURCES===<br />
<code sql><br />
SELECT count( cm.id ) AS counter, m.name<br />
FROM `prefix_course_modules` AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
GROUP BY cm.module<br />
ORDER BY counter DESC<br />
</code><br />
<br />
===LOG file ACTIONS per MODULE per COURSE (IDs)===<br />
<code sql><br />
select course,module,action,count(action) as summa from prefix_log<br />
where action <> 'new'<br />
group by course,action,module<br />
order by course,module,action<br />
</code><br />
<br />
===System Wide usage count of various course Activities===<br />
(Tested and works fine in Moodle 2.x)<br />
Like: Forum, Wiki, Blog, Assignment, Database,<br />
#Within specific category<br />
#Teacher name in course<br />
<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') as Course<br />
<br />
,(SELECT CONCAT(u.firstname,' ', u.lastname) AS Teacher<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS Teacher <br />
<br />
,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%') AS Wikis<br />
,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
WHERE cm.course = c.id AND m.name LIKE '%blog%') AS Blogs<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
WHERE cm.course = c.id AND m.name LIKE '%forum%') AS Forums<br />
<br />
,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
WHERE cm.course = c.id AND m.name LIKE '%data%') AS Databses<br />
<br />
,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
WHERE cm.course = c.id AND m.name LIKE '%assignment%') AS Assignments<br />
<br />
,(SELECT Count( ra.userid ) AS Users FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = c.id) AS Students<br />
<br />
FROM prefix_course AS c<br />
WHERE c.category IN ( 18)<br />
ORDER BY Wikis DESC,Blogs DESC, Forums DESC<br />
</code><br />
<br />
===Course wiki usage/activity over the last 6 semesters===<br />
<code sql><br />
SELECT "Courses with Wikis"<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%'<br />
and c.fullname LIKE CONCAT('%','2010','%') and c.fullname LIKE '%Semester A%') AS '2010 <br/> Semester A'<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%'<br />
and c.fullname LIKE CONCAT('%','2010','%') and c.fullname LIKE '%Semester B%') AS '2010 <br/> Semester B'<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%'<br />
and c.fullname LIKE CONCAT('%','תשעא','%') and c.fullname LIKE '%סמסטר א%') AS 'תשעא <br/> סמסטר א'<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%'<br />
and c.fullname LIKE CONCAT('%','תשעא','%') and c.fullname LIKE '%סמסטר ב%') AS 'תשעא <br/> סמסטר ב'<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%'<br />
and c.fullname LIKE CONCAT('%','תשעב','%') and c.fullname LIKE '%סמסטר א%') AS 'תשעב <br/> סמסטר א'<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%'<br />
and c.fullname LIKE CONCAT('%','תשעב','%') and c.fullname LIKE '%סמסטר ב%') AS 'תשעב <br/> סמסטר ב'<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%'<br />
and c.fullname LIKE CONCAT('%','תשעג','%') and c.fullname LIKE '%סמסטר א%') AS 'תשעג <br/> סמסטר א'<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%'<br />
and c.fullname LIKE CONCAT('%','תשעג','%') and c.fullname LIKE '%סמסטר ב%') AS 'תשעג <br/> סמסטר ב'<br />
</code><br />
<br />
===Detailed WIKI activity (per wiki per course)===<br />
Including Number of Students in course (for reference)<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',cm.course,'">',c.fullname,'</a>') as CourseID <br />
,(SELECT Count( ra.userid ) AS Users<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = c.id ) AS Students<br />
,m.name<br />
, ( SELECT count(id) FROM prefix_log WHERE cmid = cm.id AND action LIKE '%updat%' ) as 'UPDAT E'<br />
, ( SELECT count(id) FROM prefix_log WHERE cmid = cm.id AND action LIKE '%annotate%' ) as ANNOTATE<br />
, ( SELECT count(id) FROM prefix_log WHERE cmid = cm.id AND action LIKE '%comment%' ) as COMMENT<br />
, ( SELECT count(id) FROM prefix_log WHERE cmid = cm.id AND action LIKE '%add%' ) as 'A DD'<br />
, ( SELECT count(id) FROM prefix_log WHERE cmid = cm.id AND action LIKE '%edit%' ) as EDIT<br />
, ( SELECT count(id) FROM prefix_log WHERE cmid = cm.id AND action NOT LIKE '%view%' ) as 'All (NO View)'<br />
FROM `prefix_course_modules` as cm <br />
JOIN prefix_modules as m ON cm.module=m.id <br />
JOIN prefix_course as c ON cm.course = c.id <br />
WHERE m.name LIKE '%wiki%'<br />
GROUP BY cm.course,cm.module<br />
ORDER BY 'All (NO View)' DESC<br />
</code><br />
<br />
===Wiki usage, system wide===<br />
(you can filter the output by selecting some specific course categories : "WHERE c.category IN ( 8,13,15)")<br />
<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') as Course<br />
<br />
,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%') AS Wikis<br />
<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.course = c.id AND l.module LIKE '%wiki%') AS 'WikiActivity<br/>ALL'<br />
<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.course = c.id AND l.module LIKE '%wiki%' and l.action LIKE '%add%' ) AS 'WikiActivity<br/>ADD'<br />
<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.course = c.id AND l.module LIKE '%wiki%' and l.action LIKE '%edit%' ) AS 'WikiActivity<br/>EDIT'<br />
<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.course = c.id AND l.module LIKE '%wiki%' and l.action LIKE '%annotate%' ) AS 'WikiActivity<br/>ANNOTATE'<br />
<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.course = c.id AND l.module LIKE '%wiki%' and l.action LIKE '%comments%' ) AS 'WikiActivity<br/>Comments'<br />
<br />
,(SELECT Count( ra.userid ) AS Users FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = c.id) AS Students<br />
<br />
,(SELECT count(*) FROM prefix_ouwiki_pages as ouwp<br />
JOIN prefix_ouwiki as ouw ON ouw.id = ouwp.subwikiid<br />
WHERE ouw.course = c.id GROUP BY ouw.course ) as OUWikiPages<br />
<br />
,(SELECT count( DISTINCT nwp.pagename ) FROM prefix_wiki_pages AS nwp<br />
JOIN prefix_wiki AS nw ON nw.id = nwp.dfwiki WHERE nw.course = c.id ) As NWikiPages<br />
<br />
FROM prefix_course AS c<br />
WHERE c.category IN ( 8,13,15)<br />
HAVING Wikis > 0<br />
ORDER BY 'WikiActivity<br/>ALL' DESC<br />
</code><br />
<br />
===Aggregated Teacher activity by "WEB2" Modules===<br />
(Tested and works fine in Moodle 2.x)<br />
The NV column shows activity without VIEW log activity<br />
<code sql><br />
SELECT ra.userid, u.firstname,u.lastname<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.userid = u.id AND l.module LIKE '%wiki%') AS Wiki<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.userid = u.id AND l.module LIKE '%wiki%' AND l.action NOT LIKE '%view%') AS Wiki_NV<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.userid = u.id AND l.module LIKE '%forum%') AS Forum<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.userid = u.id AND l.module LIKE '%forum%' AND l.action NOT LIKE '%view%') AS Forum_NV<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.userid = u.id AND l.module LIKE '%blog%') AS Blog<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.userid = u.id AND l.module LIKE '%blog%' AND l.action NOT LIKE '%view%') AS Blog_NV<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.userid = u.id AND l.module LIKE '%assignment%') AS Assignment<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.userid = u.id AND l.module LIKE '%assignment%' AND l.action NOT LIKE '%view%') AS Assignment_NV<br />
FROM prefix_role_assignments AS ra <br />
JOIN prefix_user AS u ON u.id = ra.userid <br />
WHERE ra.roleid = 3 <br />
GROUP BY ra.userid<br />
</code><br />
<br />
===List all the certificates issued, sort by variables in the custom profile fields===<br />
Note: The SQL queries look intimidating at first, but isn't really that difficult to learn. I've seen in the forums that users wanted to do 'site-wide' groups in 1.9x. This is sort of the idea. It pulls all the certificates issued to all users sorted by the custom profile fields, which in my case is the Units or Depts (i.e. my site wide groups). Why certificates? I've explored with both grades and quizzes, the course admins are not really interested in the actual grades but whether the learner received a certificate (i.e. passed the course with x, y, z activities). It also saves me from creating groups and assigning them into the right groups. Even assigning in bulk is not efficient, since I have upward of 25 groups per course and constantly new learners enrolling in courses. The limitation is something to do with the server? as it only pull 5000 rows of data. If anyone figured out how to change this, please let me know. In the meantime, the work around is to pull only a few units/depts at a time to limit the number of rows. This is fine at the moment, since each course admin are only responsible for certain units/depts.<br />
<br />
<code sql><br />
SELECT<br />
DATE_FORMAT( FROM_UNIXTIME(prefix_certificate_issues.timecreated), '%Y-%m-%d' ) AS Date,<br />
prefix_certificate_issues.classname AS Topic,<br />
prefix_certificate.name AS Certificate,<br />
prefix_certificate_issues.studentname as Name,<br />
prefix_user_info_data.data AS Units<br />
<br />
FROM<br />
prefix_certificate_issues<br />
<br />
INNER JOIN prefix_user_info_data<br />
on prefix_certificate_issues.userid = prefix_user_info_data.userid<br />
<br />
INNER JOIN prefix_certificate<br />
on prefix_certificate_issues.certificateid = prefix_certificate.id<br />
<br />
WHERE prefix_user_info_data.data='Unit 1'<br />
OR prefix_user_info_data.data='Unit 2'<br />
OR prefix_user_info_data.data='Unit 3'<br />
<br />
ORDER BY Units, Name, Topic ASC<br />
</code><br />
<br />
<br />
=== All Simple Certificates Earned in the Site===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
Basic report of all certificates earned with the Simple Certificate plugin module in the whole site, sorted by most recent first. (Note: this uses the MySQL [http://www.mysqltutorial.org/mysql-date_format/ DATE_FORMAT] function.)<br />
<br />
<code sql><br />
SELECT<br />
CONCAT (u.firstname, ' ',u.lastname) As 'User',<br />
c.fullname AS 'Course',<br />
sc.name AS 'Certificate',<br />
DATE_FORMAT( FROM_UNIXTIME(sci.timecreated), '%Y-%m-%d' ) As 'Date Awarded'<br />
# sci.code 'CertificateId'<br />
FROM prefix_simplecertificate_issues sci<br />
JOIN prefix_user u ON sci.userid = u.id<br />
JOIN prefix_simplecertificate sc ON sci.certificateid = sc.id<br />
JOIN prefix_course AS c ON sc.course = c.id<br />
ORDER BY sci.timecreated DESC<br />
</code><br />
<br />
If you want to limit this to the most recent ones, you can add a condition to limit it to a certain number of days past. For example, adding this WHERE clause (above the ORDER BY) will show only those earned in the last 30 days:<br />
<code sql><br />
WHERE DATEDIFF(NOW(),FROM_UNIXTIME(sci.timecreated) ) < 30<br />
</code><br />
<br />
===Counter Blog usage in Courses,system wide===<br />
What teachers in what courses, uses blogs and how many + student count in that course.<br />
<code sql><br />
<br />
SELECT ( @counter := @counter+1) as counter, <br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') as Course<br />
<br />
,( SELECT DISTINCT CONCAT(u.firstname,' ',u.lastname)<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_user AS u ON ra.userid = u.id<br />
JOIN prefix_context AS ctx ON ctx.id = ra.contextid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id AND ctx.contextlevel = 50 LIMIT 1) AS Teacher<br />
<br />
,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
WHERE cm.course = c.id AND m.name LIKE '%blog%') AS Blogs<br />
<br />
,(SELECT Count( ra.userid ) AS Users FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = c.id) AS Students<br />
<br />
FROM prefix_course AS c, (SELECT @counter := 0) as s_init<br />
WHERE c.category IN ( 8,13,15)<br />
HAVING Blogs > 0<br />
ORDER BY Blogs DESC<br />
</code><br />
<br />
=== Elluminate (Blackboard Collaborate) - system wide usage===<br />
<code sql><br />
SELECT e.name As Session ,er.recordingsize<br />
,c.fullname As Course<br />
,u.firstname,u.lastname <br />
,DATE_FORMAT(FROM_UNIXTIME(e.timestart),'%d-%m-%Y') AS dTimeStart<br />
,concat('<a target="_new" href="%%WWWROOT%%/moodle/mod/elluminate/loadrecording.php?id=',er.id,'">Show</a>') AS RecordedSession<br />
<br />
FROM prefix_elluminate_recordings AS er<br />
JOIN prefix_elluminate AS e ON e.meetingid = er.meetingid<br />
JOIN prefix_course as c ON c.id = e.course<br />
JOIN prefix_user AS u ON u.id = e.creator <br />
ORDER BY er.recordingsize DESC<br />
</code><br />
<br />
<br />
=== Choice ===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
Results of the Choice activity. For all courses, shows course shortname, username, the Choice text, and the answer chosen by the user.<br />
<br />
<code sql><br />
SELECT c.shortname AS course, u.username, h.name as question, o.text AS answer<br />
FROM prefix_choice AS h<br />
JOIN prefix_course AS c ON h.course = c.id<br />
JOIN prefix_choice_answers AS a ON h.id = a.choiceid<br />
JOIN prefix_user AS u ON a.userid = u.id<br />
JOIN prefix_choice_options AS o ON a.optionid = o.id<br />
</code><br />
<br />
=== Assignment type usage in courses ===<br />
<code sql><br />
SELECT <br />
<br />
CONCAT('<a target="_new" href="%%WWWROOT%%/mod/assign/index.php?id=',c.id,'">',c.fullname,'</a>') AS "List assignments"<br />
<br />
,(SELECT COUNT(*) FROM prefix_assign WHERE c.id = course) AS Assignments<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_assign_plugin_config AS apc<br />
JOIN prefix_assign AS iassign ON iassign.id = apc.assignment <br />
WHERE iassign.course = c.id AND apc.plugin = 'file' AND apc.subtype = 'assignsubmission' AND apc.name = 'enabled' AND apc.value = '1'<br />
#GROUP BY apc.plugin<br />
) AS "File Assignments"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_assign_plugin_config AS apc<br />
JOIN prefix_assign AS iassign ON iassign.id = apc.assignment <br />
WHERE iassign.course = c.id AND apc.plugin = 'onlinetext' AND apc.subtype = 'assignsubmission' AND apc.name = 'enabled' AND apc.value = '1'<br />
) AS "Online Assignments"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_assign_plugin_config AS apc<br />
JOIN prefix_assign AS iassign ON iassign.id = apc.assignment <br />
WHERE iassign.course = c.id AND apc.plugin = 'pdf' AND apc.subtype = 'assignsubmission' AND apc.name = 'enabled' AND apc.value = '1'<br />
) AS "PDF Assignments"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_assign_plugin_config AS apc<br />
JOIN prefix_assign AS iassign ON iassign.id = apc.assignment <br />
WHERE iassign.course = c.id AND apc.plugin = 'offline' AND apc.subtype = 'assignsubmission' AND apc.name = 'enabled' AND apc.value = '1'<br />
) AS "Offline Assignments"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_assign_plugin_config AS apc<br />
JOIN prefix_assign AS iassign ON iassign.id = apc.assignment <br />
WHERE iassign.course = c.id AND apc.plugin = 'comments' AND apc.subtype = 'assignsubmission' AND apc.name = 'enabled' AND apc.value = '1'<br />
) AS "Assignments Comments"<br />
<br />
FROM prefix_assign AS assign<br />
JOIN prefix_course AS c ON c.id = assign.course<br />
GROUP BY c.id <br />
</code><br />
<br />
==Moodle Learning Analytics Reports==<br />
<br />
===Average Cognitive Depth and Social Breadth===<br />
<br />
Here is a simple SQL snippet to calculate average cognitive depth and social breadth indicators for all students in the system. This one ignores indicator values of 0, as they are nulls as defined in this model.<br />
Contributed by Elizabeth Dalton, Moodle HQ<br />
<br />
<code sql><br />
SELECT<br />
<br />
i.contextid,<br />
i.sampleid,<br />
<br />
TRUNC(AVG(CASE<br />
WHEN i.indicator LIKE '%cognitive%' THEN i.value <br />
ELSE '0'<br />
END),2) AS "Average Cognitive Depth",<br />
<br />
TRUNC(AVG(CASE<br />
WHEN i.indicator LIKE '%social%' THEN i.value <br />
ELSE '0'<br />
END),2) AS "Average Social Breadth"<br />
<br />
FROM prefix_analytics_indicator_calc as i<br />
WHERE<br />
i.value != 0<br />
GROUP BY i.contextid, i.sampleid<br />
</code><br />
<br />
==Assignment Module Reports==<br />
===All Ungraded Assignments===<br />
<br />
'''NOTE: This query is for the deprecated old Assignment module from Moodle 2.2, not the new Assignments module. Please update this query if you are the author or it will be removed as the 2.2 Assignment module is no longer supported since release 2.7.<br />
''' See: [https://docs.moodle.org/dev/Moodle_2.7_release_notes#Assignment]<br />
<br />
Returns all the submitted assignments that still need grading<br />
<code sql><br />
select <br />
u.firstname AS "First",<br />
u.lastname AS "Last",<br />
c.fullname AS "Course",<br />
a.name AS "Assignment"<br />
<br />
from prefix_assignment_submissions as asb<br />
join prefix_assignment as a ON a.id = asb.assignment<br />
join prefix_user as u ON u.id = asb.userid<br />
join prefix_course as c ON c.id = a.course<br />
join prefix_course_modules as cm ON c.id = cm.course<br />
<br />
where asb.grade < 0 and cm.instance = a.id<br />
and cm.module = 1<br />
<br />
order by c.fullname, a.name, u.lastname<br />
</code><br />
<br />
===All Ungraded Assignments w/ Link===<br />
<br />
'''NOTE: This query is for the deprecated old Assignment module from Moodle 2.2, not the new Assignments module. Please update this query if you are the author or it will be removed as the 2.2 Assignment module is no longer supported since release 2.7.<br />
''' See: [https://docs.moodle.org/dev/Moodle_2.7_release_notes#Assignment]<br />
<br />
<br />
Returns all the submitted assignments that still need grading, along with a link that goes directly to the submission to grade it. The links work if you view the report within Moodle.<br />
<code sql><br />
select <br />
u.firstname AS "First",<br />
u.lastname AS "Last",<br />
c.fullname AS "Course",<br />
a.name AS "Assignment",<br />
<br />
'<a href="http://education.varonis.com/mod/assignment/submissions.php' + char(63) +<br />
+ 'id=' + cast(cm.id as varchar) + '&userid=' + cast(u.id as varchar) <br />
+ '&mode=single&filter=0&offset=2">' + a.name + '</a>'<br />
AS "Assignmentlink"<br />
<br />
<br />
from prefix_assignment_submissions as asb<br />
join prefix_assignment as a ON a.id = asb.assignment<br />
join prefix_user as u ON u.id = asb.userid<br />
join prefix_course as c ON c.id = a.course<br />
join prefix_course_modules as cm ON c.id = cm.course<br />
<br />
where asb.grade < 0 and cm.instance = a.id and cm.module = 1<br />
<br />
order by c.fullname, a.name, u.lastname<br />
</code><br />
<br />
===Assignments (and Quizzes) waiting to be graded===<br />
<br />
'''NOTE: This query is for the deprecated old Assignment module from Moodle 2.2, not the new Assignments module. Please update this query if you are the author or it will be removed as the 2.2 Assignment module is no longer supported since release 2.7.<br />
''' See: [https://docs.moodle.org/dev/Moodle_2.7_release_notes#Assignment]<br />
<br />
<br />
This report requires a YEAR filter to be added (Available when using the latest block/configurable_reports)<br />
<br />
Which you can always remove, to make this query work on earlier versions.<br />
<br />
The report includes: <br />
*number of quizzes<br />
*unFinished Quiz attempts<br />
*Finished Quiz attempts<br />
*number of students<br />
*number of Assignments<br />
*number of submitted answers by students <br />
*number of unchecked assignments (waiting for the Teacher) in a Course.<br />
<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS Course<br />
<br />
,(SELECT CONCAT(u.firstname,' ', u.lastname) AS Teacher<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS Teacher <br />
<br />
,concat('<a target="_new" href="%%WWWROOT%%/mod/assignment/index.php?id=',c.id,'">מטלות</a>') AS Assignments<br />
<br />
,concat('<a target="_new" href="%%WWWROOT%%/mod/quiz/index.php?id=',c.id,'">בחנים</a>') AS 'Quizzes'<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_course_modules cm <br />
JOIN prefix_modules as m ON m.id = cm.module <br />
WHERE m.name LIKE 'quiz' AND cm.course = c.id <br />
GROUP BY cm.course <br />
) AS 'nQuizzes'<br />
<br />
,(SELECT COUNT(*)<br />
FROM prefix_quiz_attempts AS qa<br />
JOIN prefix_quiz AS q ON q.id = qa.quiz<br />
WHERE q.course = c.id<br />
AND qa.timefinish = 0<br />
GROUP BY q.course) AS 'unFinished Quiz attempts'<br />
<br />
,(SELECT COUNT(*)<br />
FROM prefix_quiz_attempts AS qa<br />
JOIN prefix_quiz AS q ON q.id = qa.quiz<br />
WHERE q.course = c.id<br />
AND qa.timefinish > 0<br />
GROUP BY q.course) AS 'finished quiz attempts'<br />
<br />
,(SELECT Count( ra.userid ) AS Users<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5<br />
AND ctx.instanceid = c.id<br />
) AS nStudents<br />
<br />
<br />
,(<br />
SELECT count(a.id)<br />
FROM prefix_assignment AS a <br />
JOIN prefix_course_modules AS cm ON a.course = cm.course <br />
WHERE cm.instance = a.id AND cm.module = 1 AND a.course = c.id<br />
) nAssignments<br />
<br />
,(<br />
SELECT count(*)<br />
FROM prefix_assignment AS a <br />
WHERE a.course = c.id AND FROM_UNIXTIME(a.timedue) > NOW()<br />
GROUP BY a.course<br />
) 'Open <br/>Assignments'<br />
<br />
, CONCAT(ROUND( (100 / iAssignments ) * iOpenAssignments ) ,'%') 'unFinished <br/>Assignments <br/>(percent)'<br />
<br />
,(<br />
SELECT count(asb.id)<br />
FROM prefix_assignment_submissions AS asb<br />
JOIN prefix_assignment AS a ON a.id = asb.assignment<br />
JOIN prefix_course_modules AS cm ON a.course = cm.course <br />
WHERE asb.grade < 0 AND cm.instance = a.id AND cm.module = 1 AND a.course = c.id<br />
) 'unChecked <br/>Submissions' <br />
<br />
,(<br />
SELECT count(asb.id)<br />
FROM prefix_assignment_submissions AS asb<br />
JOIN prefix_assignment AS a ON a.id = asb.assignment<br />
JOIN prefix_course_modules AS cm ON a.course = cm.course <br />
WHERE cm.instance = a.id AND cm.module = 1 AND a.course = c.id<br />
) 'Submitted <br/>Assignments'<br />
<br />
FROM prefix_course AS c<br />
LEFT JOIN (<br />
SELECT course, count(*) AS iAssignments<br />
FROM prefix_assignment AS a <br />
GROUP BY a.course <br />
) AS tblAssignmentsCount ON tblAssignmentsCount.course = c.id<br />
<br />
LEFT JOIN (<br />
SELECT course, count(*) AS iOpenAssignments<br />
FROM prefix_assignment AS a <br />
WHERE FROM_UNIXTIME(a.timedue) > NOW()<br />
GROUP BY a.course <br />
) AS tblOpenAssignmentsCount ON tblOpenAssignmentsCount.course = c.id<br />
<br />
WHERE 1=1 <br />
#AND c.fullname LIKE '%תשעג%'<br />
%%FILTER_YEARS:c.fullname%%<br />
## You can enable the SEMESTER filter as well, <br />
## by uncommenting the following line:<br />
## %%FILTER_SEMESTERS:c.fullname%%<br />
ORDER BY 'Open <br/>Assignments' DESC<br />
</code><br />
<br />
===Rubrics without zero values in criteria===<br />
Contributed by Eric Strom<br />
<br />
Rubric calculations in Moodle can fail to align with instructors expectations if they lack a zero value for each criterion used in the assessment. From documentation at https://docs.moodle.org/32/en/Rubrics#Grade_calculation:<br />
<br />
"For example, when the teacher in the previous example chose both levels with 1 point, the plain sum would be 2 points. But that is actually the lowest possible score so it maps to the grade 0 in Moodle.<br />
TIP: To avoid confusion from this sort of thing, we recommend including a level with 0 points in every rubric criterion."<br />
<br />
This report identifies rubrics having criteria without a zero value level and the courses they live in. This also refines to only assignments with active rubrics that are visible to students in the course. Links to the each rubric id is the direct link to edit the rubric. Fix by adding a zero level for each criteria that is missing it. In general, the grading changes that result will be in the students' favor.<br />
<br />
Includes search filter of course idnumber.<br />
<br />
<code sql><br />
SELECT cat.name AS Department, concat('<a target="_new" href="%%WWWROOT%%/course/view.php',CHAR(63),'id=',<br />
c.id,'">',c.idnumber,'</a>') AS Course_ID, <br />
c.fullname AS Course_Name, <br />
concat('<a target="_new" href="%%WWWROOT%%/grade/grading/form/rubric/edit.php',CHAR(63),'areaid=',gd.areaid,'">',gd.areaid,'</a>') AS Rubric<br />
FROM prefix_course AS c<br />
JOIN prefix_course_categories AS cat <br />
ON cat.id = c.category<br />
JOIN prefix_course_modules AS cm <br />
ON c.id=cm.course<br />
JOIN prefix_context AS ctx <br />
ON cm.id = ctx.instanceid<br />
JOIN prefix_grading_areas AS garea <br />
ON ctx.id = garea.contextid<br />
JOIN prefix_grading_definitions AS gd <br />
ON garea.id = gd.areaid<br />
JOIN prefix_gradingform_rubric_criteria AS crit <br />
ON gd.id = crit.definitionid<br />
JOIN prefix_gradingform_rubric_levels AS levels <br />
ON levels.criterionid = crit.id<br />
WHERE cm.visible='1' AND garea.activemethod = 'rubric' AND (crit.id NOT IN<br />
(SELECT crit.id<br />
FROM prefix_gradingform_rubric_criteria AS crit<br />
JOIN prefix_gradingform_rubric_levels AS levels <br />
ON levels.criterionid = crit.id WHERE levels.score = '0'))<br />
<br />
GROUP BY Rubric<br />
ORDER BY Course_ID, Rubric<br />
<br />
%%FILTER_SEARCHTEXT:c.idnumber:~%%<br />
</code><br />
<br />
===Who is using "Single File Upload" assignment===<br />
<code sql><br />
SELECT <br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS Course<br />
<br />
,(SELECT CONCAT(u.firstname,' ', u.lastname) AS Teacher<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS Teacher <br />
<br />
,ass.name as "Assignment Name"<br />
<br />
FROM <br />
prefix_assignment as ass<br />
<br />
JOIN <br />
prefix_course as c ON c.id = ass.course<br />
<br />
WHERE `assignmenttype` LIKE 'uploadsingle'<br />
</code><br />
<br />
==Feedback Module Reports==<br />
===List the answers to all the Feedback activities within the current course, submitted by the current user===<br />
<code sql><br />
SELECT /* crs.fullname as "Course name", f.name AS "Journal name", CONCAT(u.firstname,' ',UPPER(u.lastname)) as "Participant", */ /* include these fields if you want to check the composition of the recordset */<br />
DATE_FORMAT(FROM_UNIXTIME(c.timemodified),'%W %e %M, %Y') as "Answer Date",<br />
CASE i.typ WHEN 'label' THEN i.presentation ELSE i.name END as "Topic", /* usually labels are used as section titles, so you'd want them present in the recordset */<br />
v.value as "My Answer"<br />
<br />
FROM prefix_feedback AS f<br />
INNER JOIN prefix_course as crs on crs.id=f.course %%FILTER_COURSES:f.course%% <br />
INNER JOIN prefix_feedback_item AS i ON f.id=i.feedback<br />
INNER JOIN prefix_feedback_completed AS c on f.id=c.feedback %%FILTER_COURSEUSER:c.userid%% <br />
LEFT JOIN prefix_feedback_value AS v on v.completed=c.id AND v.item=i.id<br />
INNER JOIN prefix_user AS u on c.userid=u.id<br />
<br />
WHERE c.id = %%COURSEID%% AND u.id = %%USERID%% AND c.anonymous_response = 1 /* This clause limits the recordset to the current course and the current user and includes/ excludes the anonymous responses as needed */<br />
<br />
ORDER BY f.id, c.timemodified, i.id<br />
</code><br />
<br />
===Show all Feedbacks from all courses for all users including showing names of anonymous users===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
Shows all Feedbacks in all Courses with all multi-choice questions and answers of all users including showing the username of anonymous users. Also shows tryly anonymous users on the front page as 'Not-logged-in' users. This is a rough report, not a pretty report, and is limited to multiple-choice type questions, but is shows the answer number and the list of possible answers in raw form. I post it here as a basis for further reports, and also as away to get the identities of anonymous users if needed.<br />
<br />
<code sql><br />
SELECT <br />
c.shortname AS Course, <br />
f.name AS Feedback,<br />
# i.id AS Itemid,<br />
i.name AS Itemname,<br />
i.label AS Itemlabel,<br />
CASE <br />
WHEN f.anonymous = 1 AND u.id != 0 THEN CONCAT(u.username, ' :ANON')<br />
WHEN fc.userid = 0 THEN 'Not-logged-in'<br />
ELSE u.username<br />
END AS 'User',<br />
DATE_FORMAT(FROM_UNIXTIME(fc.timemodified),'%Y-%m-%d %H:%i') AS "Completed",<br />
v.value AS "Choice",<br />
CASE <br />
WHEN i.typ = 'multichoice' THEN<br />
IF ( SUBSTRING(i.presentation,1,6)='d>>>>>',<br />
SUBSTRING(i.presentation,7),<br />
i.presentation)<br />
ELSE i.presentation<br />
END AS "Answers",<br />
i.typ,<br />
i.dependitem,<br />
i.dependvalue<br />
<br />
FROM prefix_feedback f<br />
JOIN prefix_course c ON c.id=f.course <br />
JOIN prefix_feedback_item AS i ON f.id=i.feedback<br />
JOIN prefix_feedback_completed fc ON f.id=fc.feedback<br />
LEFT JOIN prefix_feedback_value v ON v.completed=fc.id AND v.item=i.id<br />
LEFT JOIN prefix_user AS u ON fc.userid=u.id<br />
WHERE i.typ != 'pagebreak'<br />
</code><br />
<br />
==Resource Module Reports==<br />
===List "Recently uploaded files"===<br />
see what users are uploading<br />
<code sql><br />
SELECT FROM_UNIXTIME(time,'%Y %M %D %h:%i:%s') as time ,ip,userid,url,info <br />
FROM `prefix_log` <br />
WHERE `action` LIKE 'upload' <br />
ORDER BY `prefix_log`.`time` DESC<br />
</code><br />
<br />
===List Courses that loaded a specific file: "X"===<br />
Did the Teacher (probably) uploaded course's Syllabus ?<br />
<code sql><br />
SELECT c.id, c.fullname FROM `prefix_log` as l <br />
JOIN prefix_course as c ON c.id = l.course <br />
WHERE `action` LIKE '%upload%' AND ( info LIKE '%Syllabus%' OR info LIKE '%Sylabus%' ) GROUP BY c.id<br />
</code><br />
<br />
===All resources that link to some specific external website===<br />
+ link to course<br />
+ who's the teacher<br />
+ link to external resource<br />
<code sql><br />
SELECT<br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS Course<br />
,c.shortname,r.name<br />
,(SELECT CONCAT(u.firstname,' ', u.lastname) AS Teacher<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS Teacher<br />
,concat('<a target="_new" href="%%WWWROOT%%/mod/resource/view.php?id=',r.id,'">',r.name,'</a>') AS Resource<br />
FROM prefix_resource AS r <br />
JOIN prefix_course AS c ON r.course = c.id<br />
WHERE r.reference LIKE 'http://info.oranim.ac.il/home%' <br />
</code><br />
<br />
==="Compose Web Page" RESOURCE count===<br />
<code sql><br />
SELECT course,prefix_course.fullname, COUNT(*) AS Total<br />
FROM `prefix_resource`<br />
JOIN `prefix_course` ON prefix_course.id = prefix_resource.course<br />
WHERE type='html'<br />
GROUP BY course<br />
</code><br />
<br />
===Resource count in courses===<br />
+ (First)Teacher name<br />
+ Where course is inside some specific Categories<br />
<code sql><br />
SELECT <br />
COUNT(*) AS count<br />
,r.course <br />
,c.shortname shortname<br />
,c.fullname coursename<br />
,( SELECT DISTINCT CONCAT(u.firstname,' ',u.lastname)<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_user as u ON ra.userid = u.id<br />
JOIN prefix_context AS ctx ON ctx.id = ra.contextid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = r.course AND ctx.contextlevel = 50 LIMIT 1) AS Teacher<br />
FROM prefix_resource r <br />
JOIN prefix_course c ON r.course = c.id<br />
WHERE c.category IN (10,13,28,18,26)<br />
GROUP BY r.course<br />
ORDER BY COUNT(*) DESC<br />
</code><br />
<br />
===Delete all the automated backup files===<br />
Prepare bash cli script to delete all the automated backup files on the file system. (clean up some disk space)<br />
<code sql><br />
SELECT CONCAT( 'rm -f /var/moodledatanew/filedir/', SUBSTRING( contenthash, 1, 2 ) , '/', SUBSTRING( contenthash, 3, 2 ) , '/', contenthash ) <br />
FROM `mdl_files` <br />
WHERE `filename` LIKE '%mbz%'<br />
AND filearea = 'automated'<br />
</code><br />
<br />
Find out how much disk space is used by all automated backup files:<br />
<code sql><br />
SELECT SUM(filesize)/(1024*1024*1024) FROM `mdl_files` WHERE `filename` LIKE '%mbz%' AND filearea = 'automated'<br />
</code><br />
<br />
==Forum Module Reports==<br />
===print all User's post in course Forums===<br />
%%COURSEID%% is a variable the is replace by the current CourseID you are running the sql report from. if you are using the latest block/configurable_reports ! (You can always change it to a fixed course or remove it to display all courses.)<br />
<code sql><br />
SELECT <br />
concat('<a target="_new" href="%%WWWROOT%%/mod/forum/user.php?course=',c.id,'&id=',u.id,'&mode=posts">',CONCAT(u.firstname,' ', u.lastname),'</a>') As Fullname<br />
,concat('<a target="_new" href="%%WWWROOT%%/mod/forum/view.php?f=',fd.forum,'">',f.name,'</a>') AS Forum<br />
,count(*) as Posts<br />
,(SELECT count(*) FROM prefix_forum_discussions AS ifd JOIN prefix_forum as iforum ON iforum.id = ifd.forum WHERE ifd.userid = fp.userid AND iforum.id = f.id) AS cAllDiscussion<br />
<br />
FROM prefix_forum_posts AS fp <br />
JOIN prefix_user as u ON u.id = fp.userid <br />
JOIN prefix_forum_discussions AS fd ON fp.discussion = fd.id <br />
JOIN prefix_forum AS f ON f.id = fd.forum <br />
JOIN prefix_course as c ON c.id = fd.course <br />
WHERE fd.course = %%COURSEID%% <br />
GROUP BY f.id,u.id<br />
ORDER BY u.id<br />
</code><br />
<br />
===FORUM use Count per COURSE -- not including NEWS Forum!===<br />
<code sql><br />
SELECT prefix_course.fullname, prefix_forum.course, count(*) as total FROM prefix_forum<br />
INNER JOIN prefix_course<br />
ON prefix_course.id = prefix_forum.course<br />
WHERE NOT(prefix_forum.type = 'news')<br />
GROUP BY prefix_forum.course<br />
ORDER BY total desc<br />
</code><br />
<br />
===FORUM use Count per COURSE by type -- not including NEWS Forum!===<br />
<code sql><br />
SELECT prefix_course.fullname, prefix_forum.course, prefix_forum.type, count(*) as total FROM prefix_forum<br />
INNER JOIN prefix_course<br />
ON prefix_course.id = prefix_forum.course<br />
WHERE NOT(prefix_forum.type = 'news')<br />
GROUP BY prefix_forum.course,prefix_forum.type<br />
ORDER BY total desc<br />
</code><br />
<br />
===Forum activity - system wide===<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.id,'</a>') AS CourseID<br />
,( SELECT DISTINCT CONCAT(u.firstname,' ',u.lastname)<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_user AS u ON ra.userid = u.id<br />
JOIN prefix_context AS ctx ON ctx.id = ra.contextid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id AND ctx.contextlevel = 50 LIMIT 1) AS Teacher<br />
,c.fullname as Course<br />
,f.type<br />
,(SELECT Count( ra.userid ) AS Users FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = c.id) AS Students<br />
, fd.forum, f.name,count(*) AS cPostAndDisc<br />
,(SELECT count(*) FROM prefix_forum_discussions AS ifd WHERE ifd.forum = f.id) AS cDiscussion<br />
FROM prefix_forum_posts AS fp<br />
JOIN prefix_forum_discussions AS fd ON fd.id = fp.discussion<br />
JOIN prefix_forum AS f ON f.id = fd.forum<br />
JOIN prefix_course AS c ON c.id = f.course<br />
WHERE f.type != 'news' AND c.fullname LIKE '%2013%'<br />
## WHERE 1=1 <br />
## %%FILTER_YEARS:c.fullname%%<br />
## You can enable the SEMESTER filter as well, <br />
## by uncommenting the following line:<br />
## %%FILTER_SEMESTERS:c.fullname%%<br />
<br />
GROUP BY fd.forum<br />
ORDER BY count( * ) DESC<br />
</code><br />
<br />
===Activity In Forums===<br />
Trying to figure out how much real activity we have in Forums by aggregating:<br />
Users in Course, Number of Posts, Number of Discussions, Unique student post, Unique student discussions, Number of Teachers , Number of Students, ratio between unique Student posts and the number of students in the Course...<br />
<code sql><br />
SELECT c.fullname,f.name,f.type <br />
,(SELECT count(id) FROM prefix_forum_discussions as fd WHERE f.id = fd.forum) as Discussions<br />
,(SELECT count(distinct fd.userid) FROM prefix_forum_discussions as fd WHERE fd.forum = f.id) as UniqueUsersDiscussions<br />
,(SELECT count(fp.id) FROM prefix_forum_discussions fd JOIN prefix_forum_posts as fp ON fd.id = fp.discussion WHERE f.id = fd.forum) as Posts<br />
,(SELECT count(distinct fp.userid) FROM prefix_forum_discussions fd JOIN prefix_forum_posts as fp ON fd.id = fp.discussion WHERE f.id = fd.forum) as UniqueUsersPosts<br />
,(SELECT Count( ra.userid ) AS Students<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid =5<br />
AND ctx.instanceid = c.id<br />
) AS StudentsCount<br />
,(SELECT Count( ra.userid ) AS Teachers<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid =3<br />
AND ctx.instanceid = c.id<br />
) AS 'Teacher<br/>Count'<br />
,(SELECT Count( ra.userid ) AS Users<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid IN (3,5)<br />
AND ctx.instanceid = c.id<br />
) AS UserCount<br />
, (SELECT (UniqueUsersDiscussions / StudentsCount )) as StudentDissUsage<br />
, (SELECT (UniqueUsersPosts /StudentsCount)) as StudentPostUsage<br />
FROM prefix_forum as f <br />
JOIN prefix_course as c ON f.course = c.id<br />
WHERE `type` != 'news'<br />
ORDER BY StudentPostUsage DESC<br />
</code><br />
<br />
===All Forum type:NEWS===<br />
<code sql><br />
SELECT f.id, f.name<br />
FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_forum AS f ON cm.instance = f.id<br />
WHERE m.name = 'forum'<br />
AND f.type = 'news'<br />
</code><br />
<br />
===All new forum NEWS items (discussions) from all my Courses===<br />
change "userid = 26" and "id = 26" to a new user id<br />
<code sql><br />
SELECT c.shortname,f.name,fd.name,FROM_UNIXTIME(fd.timemodified ,"%d %M %Y ") as Date<br />
FROM prefix_forum_discussions as fd <br />
JOIN prefix_forum as f ON f.id = fd.forum <br />
JOIN prefix_course as c ON c.id = f.course <br />
JOIN prefix_user_lastaccess as ul ON (c.id = ul.courseid AND ul.userid = 26)<br />
WHERE fd.timemodified > ul.timeaccess <br />
AND fd.forum IN (SELECT f.id<br />
FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_forum AS f ON cm.instance = f.id<br />
WHERE m.name = 'forum'<br />
AND f.type = 'news')<br />
AND c.id IN (SELECT c.id<br />
FROM prefix_course AS c<br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid<br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE u.id = 26) ORDER BY `fd`.`timemodified` DESC<br />
</code><br />
<br />
<br />
===News Forum - Discussions COUNT===<br />
Which is actually... How much instructions students get from their teachers<br />
<code sql><br />
SELECT c.shortname ,<br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS Course<br />
,( SELECT DISTINCT CONCAT(u.firstname,' ',u.lastname)<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_user AS u ON ra.userid = u.id<br />
JOIN prefix_context AS ctx ON ctx.id = ra.contextid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id AND ctx.contextlevel = 50 LIMIT 1) AS Teacher<br />
,concat('<a target="_new" href="%%WWWROOT%%/mod/forum/view.php?f=',fd.forum,'">',count(fd.id),'</a>') AS DiscussionsSum<br />
FROM prefix_forum_discussions AS fd<br />
INNER JOIN prefix_forum AS f ON f.id = fd.forum<br />
INNER JOIN prefix_course AS c ON c.id = f.course<br />
WHERE f.type = 'news' AND c.category IN (10,13,28,18,26)<br />
GROUP BY fd.forum<br />
ORDER BY count(fd.id) DESC<br />
</code><br />
<br />
===Cantidad de foros que han sido posteados por profesor===<br />
<br />
(Number of forums that have been posted by teacher/Google translator)<br />
<br />
Queriamos saber cuales son las acciones del profesor dentro de los foros de cada curso, por ello se hizo este informe.<br />
<br />
(We wanted to know what the teacher's actions are in the forums of each course, so this report was made. /Google translator)<br />
<code sql><br />
SELECT <br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.shortname,'</a>') AS curso,<br />
CONCAT(u.firstname ,' ',u.lastname) AS Facilitador,<br />
<br />
(SELECT COUNT( m.name ) AS COUNT FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
WHERE cm.course = c.id AND m.name LIKE '%forum%') AS foros,<br />
<br />
COUNT(*) AS Posts<br />
<br />
FROM prefix_forum_posts AS fp <br />
JOIN prefix_forum_discussions AS fd ON fp.discussion = fd.id <br />
JOIN prefix_forum AS f ON f.id = fd.forum <br />
JOIN prefix_course AS c ON c.id = fd.course<br />
JOIN prefix_user AS u ON u.id = fp.userid <br />
<br />
WHERE fp.userid =<br />
(<br />
select distinct prefix_user.id<br />
from prefix_user <br />
join prefix_role_assignments as ra on ra.userid = prefix_user.id <br />
where ra.roleid = 3 <br />
and userid = fp.userid<br />
limit 1<br />
)<br />
<br />
and c.shortname like '%2014-2-1%'<br />
GROUP BY c.id, u.id<br />
</code><br />
<br />
<br />
===List all the Posts in all the Forums that got high rating===<br />
We setup a scale that let teachers and students Rate forum post with "Important, interesting, valuable, not rated" scale<br />
And then add a link to the following report at the begining of the course "Link to all interesting posts"<br />
<code sql><br />
SELECT <br />
CONCAT('<a target="_new" href="%%WWWROOT%%/mod/forum/view.php?f=',f.id,'">',f.name,'</a>') AS 'Forum name,<br />
CONCAT('<a target="_new" href="%%WWWROOT%%/mod/forum/discuss.php?d=',fd.id,'#p',fp.id,'">',fp.subject,'</a>') AS 'Post link',<br />
SUM(r.rating) AS 'Rating'<br />
FROM mdl_rating AS r<br />
JOIN mdl_forum_posts AS fp ON fp.id = r.itemid<br />
JOIN mdl_forum_discussions AS fd ON fd.id = fp.discussion<br />
JOIN mdl_forum AS f ON f.id = fd.forum<br />
WHERE r.component = 'mod_forum' AND r.ratingarea = 'post' AND f.course = %%COURSEID%%<br />
GROUP BY r.itemid<br />
ORDER BY SUM(r.rating) DESC<br />
</code><br />
<br />
===List all the Posts in all Discussions of a single Forum===<br />
This report is used to help export all the student's posts and discussions of a single forum, by passing the context module id as a parameter to the report using "&filter_var=cmid"<br />
<code sql><br />
SELECT <br />
CONCAT('<a target="_new" href="%%WWWROOT%%/mod/forum/view.php?f=', f.id, '">', f.name, '</a>') AS 'Forum name',<br />
fd.name AS 'Discussion', <br />
CONCAT('<a target="_new" href="%%WWWROOT%%/mod/forum/discuss.php?d=', fd.id, '#p', fp.id, '">', fp.subject, '</a>') AS 'Post (link)',<br />
fp.message<br />
<br />
FROM mdl_forum_posts AS fp <br />
JOIN mdl_forum_discussions AS fd ON fd.id = fp.discussion<br />
JOIN mdl_forum AS f ON f.id = fd.forum<br />
JOIN mdl_course_modules AS cm ON cm.module = 9 AND cm.instance = f.id<br />
WHERE cm.id = %%FILTER_VAR%%<br />
ORDER BY f.id, fd.id<br />
</code><br />
<br />
==Quiz Module Reports==<br />
===Generate a list of instructors and their email addresses for those courses that has "essay questions" in their quizzes===<br />
<code sql><br />
SELECT qu.id AS quiz_id, qu.course AS course_id, qu.questions,<br />
co.fullname AS course_fullname, co.shortname AS course_shortname,<br />
qu.name AS quiz_name, FROM_UNIXTIME(qu.timeopen) AS quiz_timeopen, FROM_UNIXTIME(qu.timeclose) AS quiz_timeclose,<br />
u.firstname, u.lastname, u.email,<br />
FROM prefix_quiz qu, prefix_course co, prefix_role re, prefix_context ct, prefix_role_assignments ra, prefix_user u<br />
WHERE FROM_UNIXTIME(timeopen) > '2008-05-14' AND<br />
qu.course = co.id AND<br />
co.id = ct.instanceid AND<br />
ra.roleid = re.id AND<br />
re.name = 'Teacher' AND<br />
ra.contextid = ct.id AND<br />
ra.userid = u.id<br />
<br />
SELECT Count('x') As NumOfStudents<br />
FROM prefix_role_assignments a<br />
JOIN prefix_user u ON userid = u.id<br />
WHERE roleid = 5 AND contextid = (SELECT id FROM prefix_context WHERE instanceid = 668 AND contextlevel = 50)<br />
</code><br />
<br />
===Number of Quizes per Course===<br />
<code sql><br />
SELECT count(*)<br />
,concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS Course<br />
,concat('<a target="_new" href="%%WWWROOT%%/mod/quiz/index.php?id=',c.id,'">Link</a>') AS Quizes<br />
<br />
FROM prefix_course_modules cm<br />
JOIN prefix_course c ON c.id = cm.course<br />
JOIN prefix_modules as m ON m.id = cm.module<br />
WHERE m.name LIKE 'quiz'<br />
GROUP BY c.id<br />
</code><br />
<br />
===List all MultiAnswer (Cloze) Questions===<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/mod/quiz/attempt.php?q=', quiz.id, '">', quiz.name, '</a>') AS Quiz<br />
,question.id question_id, question.questiontext <br />
FROM prefix_question question<br />
JOIN prefix_quiz_question_instances qqi ON question.id = qqi.question<br />
JOIN prefix_quiz quiz ON qqi.quiz = quiz.id<br />
WHERE `qtype` LIKE 'multianswer'<br />
</code><br />
<br />
===List courses with MANUAL grades===<br />
Which is basically and indication to teachers using Moodle to hold offline grades inside Moodle's Gradebook,<br />
So grades could be uploaded into an administrative SIS. Use with Configurable Reports.<br />
<code sql><br />
SELECT COUNT( * )<br />
,concat('<a target="_new" href="%%WWWROOT%%/grade/edit/tree/index.php?showadvanced=1&id=',c.id,'">',c.fullname,'</a>') AS Course<br />
FROM prefix_grade_items AS gi<br />
JOIN prefix_course as c ON c.id = gi.courseid<br />
WHERE `itemtype` = 'manual'<br />
GROUP BY courseid<br />
</code><br />
===List the users that did not took the Quiz===<br />
Do not forget to change "c.id = 14" and q.name LIKE '%quiz name goes here%'<br />
<code sql><br />
SELECT<br />
user2.id AS ID,<br />
ul.timeaccess,<br />
user2.firstname AS Firstname,<br />
user2.lastname AS Lastname,<br />
user2.email AS Email,<br />
user2.username AS IDNumber,<br />
user2.institution AS Institution,<br />
<br />
IF (user2.lastaccess = 0,'never',<br />
DATE_FORMAT(FROM_UNIXTIME(user2.lastaccess),'%Y-%m-%d')) AS dLastAccess<br />
<br />
,(SELECT DATE_FORMAT(FROM_UNIXTIME(timeaccess),'%Y-%m-%d') FROM prefix_user_lastaccess WHERE userid=user2.id AND courseid=c.id) AS CourseLastAccess<br />
<br />
,(SELECT r.name<br />
FROM prefix_user_enrolments AS uenrol<br />
JOIN prefix_enrol AS e ON e.id = uenrol.enrolid<br />
JOIN prefix_role AS r ON e.id = r.id<br />
WHERE uenrol.userid=user2.id AND e.courseid = c.id) AS RoleName<br />
<br />
FROM prefix_user_enrolments AS ue<br />
JOIN prefix_enrol AS e ON e.id = ue.enrolid<br />
JOIN prefix_course AS c ON c.id = e.courseid<br />
JOIN prefix_user AS user2 ON user2 .id = ue.userid<br />
LEFT JOIN prefix_user_lastaccess AS ul ON ul.userid = user2.id<br />
WHERE c.id=14 and ue.userid NOT IN (SELECT qa.userid FROM prefix_quiz_attempts AS qa<br />
JOIN prefix_quiz AS q ON qa.quiz = q.id<br />
JOIN prefix_course AS c ON q.course = c.id<br />
WHERE c.id = 14 AND q.name LIKE '%quiz name goes here%')<br />
</code><br />
<br />
<br />
===List Questions in each Quiz===<br />
<br />
<code sql><br />
SELECT quiz.id,quiz.name, q.id, q.name<br />
FROM mdl_quiz AS quiz<br />
JOIN mdl_question AS q ON FIND_IN_SET(q.id, quiz.questions)<br />
WHERE quiz.course = %%COURSEID%%<br />
ORDER BY quiz.id ASC<br />
</code><br />
<br />
Note: this query does not work in Moodle 2.8. There is no mdl_quiz.questions field. It will need to be rewritten to use the usage/contextid organization.<br />
<br />
===Quiz activity research===<br />
This report was made to extract student full activity in quizzes for an academic research about adapting instructional design teaching methods in online learning. The students do not use the Quiz module as a standard quiz but more as Study booklets or mini courses with embedded questions and hints to assist students evaluate their progress (Similar to what you expect to find in a SCORM activity)<br />
<br />
<code sql><br />
SELECT <br />
cm.course "course_id", cm.id "moduel_id", q.id "quiz_id", q.name "quiz_name",<br />
<br />
CASE q.grademethod<br />
WHEN 1 THEN "GRADEHIGHEST"<br />
WHEN 2 THEN "GRADEAVERAGE"<br />
WHEN 3 THEN "ATTEMPTFIRST"<br />
WHEN 4 THEN "ATTEMPTLAST"<br />
END "grade method"<br />
<br />
, q.attempts "quiz_attempts_allowed", cm.groupmode "group_mode"<br />
, qa.id "attempt_id", qa.state "attempt_state", qa.sumgrades "attempt_grade", qg.grade "user_final_grade", q.grade "quiz_max_grade"<br />
,(SELECT GROUP_CONCAT(g.name) FROM mdl_groups AS g<br />
JOIN mdl_groups_members AS m ON g.id = m.groupid WHERE g.courseid = q.course AND m.userid = u.id) "user_groups",<br />
DATE_FORMAT(FROM_UNIXTIME(qa.timestart), '%d-%m-%Y %h:%k') "attempt_start",<br />
DATE_FORMAT(FROM_UNIXTIME(qa.timefinish), '%d-%m-%Y %h:%k') "attempt_finish",<br />
u.id "user_id", u.firstname, u.lastname,<br />
question.id "question_id", question.name "question_name",<br />
qas.state "question_step_state",qas.fraction "question_grade", qh.hint, question.qtype "question_type"<br />
<br />
FROM mdl_quiz as q<br />
JOIN mdl_course_modules as cm ON cm.instance = q.id and cm.module = 14 <br />
JOIN mdl_quiz_attempts qa ON q.id = qa.quiz<br />
LEFT JOIN mdl_quiz_grades as qg ON qg.quiz = q.id and qg.userid = qa.userid<br />
JOIN mdl_user as u ON u.id = qa.userid<br />
JOIN mdl_question_usages as qu ON qu.id = qa.uniqueid<br />
JOIN mdl_question_attempts as qatt ON qatt.questionusageid = qu.id<br />
JOIN mdl_question as question ON question.id = qatt.questionid<br />
JOIN mdl_question_attempt_steps as qas ON qas.questionattemptid = qatt.id<br />
LEFT JOIN mdl_question_hints as qh ON qh.questionid = q.id<br />
#WHERE q.id = "SOME QUIZ ID"<br />
WHERE cm.course = "SOME COURSE ID"<br />
</code><br />
<br />
===Quiz Usage in Courses by Date===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
This report lists the courses containing quizzes with the course start date between the two values, and provides a summary of the types of questions in the quizzes in each course and whether question randomization and answer randomization functions were used.<br />
<br />
"Multiple Choice" questions include true/false and matching question types.<br />
<br />
"Short Answer" are questions that accept a single phrase.<br />
<br />
"Other" questions include fixed numerical, calculated, essay, and various drag and drop types.<br />
<br />
"Min Quiz Age" and "Max Quiz Age" provide data about the last modified date for the quizzes in the course, compared to the course start date. The values are expressed in units of days. A negative value indicates that a quiz was edited after the start of the course. A value greater than 90 days indicates that the quiz may have been used in an earlier term (cohort) without modification.<br />
<br />
'''Note''': In Configurable Reports, the Date Filter is not applied until the "Apply" button is clicked.<br />
<br />
<code sql><br />
SELECT <br />
<br />
c.shortname AS 'Course'<br />
#, u.lastname AS 'Instructor'<br />
, COUNT(DISTINCT q.id) AS 'Quizzes'<br />
, COUNT(DISTINCT qu.id) AS 'Questions'<br />
, SUM(IF (qu.qtype = 'multichoice', 1, 0 )) + SUM(IF (qu.qtype = 'truefalse', 1, 0 )) + SUM(IF (qu.qtype = 'match', 1, 0 )) AS 'multichoice'<br />
<br />
, SUM(IF (qu.qtype = 'shortanswer', 1, 0 )) AS 'shortanswer'<br />
<br />
, COUNT( qu.id) - SUM(IF (qu.qtype = 'multichoice', 1, 0 )) - SUM(IF (qu.qtype = 'truefalse', 1, 0 )) - SUM(IF (qu.qtype = 'match', 1, 0 )) - SUM(IF (qu.qtype = 'shortanswer', 1, 0 )) AS 'Other'<br />
<br />
, (SUM(IF (qu.qtype = 'multichoice', 1, 0 )) + SUM(IF (qu.qtype = 'truefalse', 1, 0 )) + SUM(IF (qu.qtype = 'match', 1, 0 )))/COUNT( qu.id) AS 'Percent MC'<br />
<br />
#, SUM(IF (qu.qtype = 'numerical', 1, 0 )) AS 'numerical'<br />
#, SUM(IF (qu.qtype LIKE 'calc%', 1, 0 )) AS 'calculated'<br />
#, SUM(IF (qu.qtype = 'random', 1, 0 )) AS 'random'<br />
#, SUM(IF (qu.qtype = 'shortanswer', 1, 0 )) AS 'shortanswer'<br />
#, SUM(IF (qu.qtype = 'essay', 1, 0 )) AS 'essay'<br />
<br />
<br />
, IF(q.shufflequestions > 0,'Yes','No') AS 'Randomized Questions'<br />
, IF(q.shuffleanswers > 0,'Yes','No') AS 'Randomized Answers'<br />
<br />
#, FROM_UNIXTIME(c.startdate) AS 'Course Start Date'<br />
#, FROM_UNIXTIME(MIN(q.timemodified)) AS 'Last Modified'<br />
<br />
#, DATEDIFF(FROM_UNIXTIME(c.startdate),FROM_UNIXTIME(MIN(q.timemodified))) AS 'Quiz age'<br />
<br />
, MIN(DATEDIFF(FROM_UNIXTIME(c.startdate),FROM_UNIXTIME(q.timemodified))) AS 'Min Quiz Age' <br />
, MAX(DATEDIFF(FROM_UNIXTIME(c.startdate),FROM_UNIXTIME(q.timemodified))) AS 'Max Quiz Age' <br />
<br />
#, SUM(IF (DATEDIFF(FROM_UNIXTIME(c.startdate),FROM_UNIXTIME(q.timemodified)) < 90, 1,0)) AS 'new quizzes'<br />
<br />
FROM prefix_quiz AS q<br />
JOIN prefix_course AS c on c.id = q.course<br />
JOIN prefix_quiz_question_instances AS qqi ON qqi.quiz = q.id<br />
LEFT JOIN prefix_question AS qu ON qu.id = qqi.question<br />
<br />
WHERE<br />
1<br />
%%FILTER_STARTTIME:c.startdate:>%% %%FILTER_ENDTIME:c.startdate:<%%<br />
<br />
GROUP BY c.id<br />
<br />
ORDER BY c.shortname<br />
</code><br />
<br />
===Student responses (answers) to quiz questions===<br />
(Contributed by Juan F with help from Tim hunt and fellow Moodlers on the forums)<br />
A report that targets a specific quiz for all of our Biology courses, a summary of all questions and how many students get them right/wrong.<br />
<code sql><br />
SELECT<br />
concat( u.firstname, " ", u.lastname ) AS "Student Name",<br />
u.id,<br />
quiza.userid,<br />
q.course,<br />
q.name,<br />
quiza.attempt,<br />
qa.slot,<br />
que.questiontext AS 'Question',<br />
qa.rightanswer AS 'Correct Answer',<br />
qa.responsesummary AS 'Student Answer'<br />
<br />
FROM mdl_quiz_attempts quiza<br />
JOIN mdl_quiz q ON q.id=quiza.quiz<br />
JOIN mdl_question_usages qu ON qu.id = quiza.uniqueid<br />
JOIN mdl_question_attempts qa ON qa.questionusageid = qu.id<br />
JOIN mdl_question que ON que.id = qa.questionid<br />
JOIN mdl_user u ON u.id = quiza.userid<br />
<br />
WHERE q.name = "BIO 208 Post Test Assessment"<br />
AND q.course = "17926"<br />
<br />
ORDER BY quiza.userid, quiza.attempt, qa.slot<br />
</code><br />
<br />
==SCORM Activity Reports==<br />
<br />
===Lists All completed SCORM activites by Course name===<br />
This report will list all completed attempts for all SCORM activities. It is ordered first by Course name, then student's last name, then student's first name, then attempt number. Please note: the FROM_UNIXTIME command is for MySQL.<br />
<code sql><br />
SELECT u.firstname First,u.lastname Last,c.fullname Course, st.attempt Attempt,st.value Status,FROM_UNIXTIME(st.timemodified,"%m-%d-%Y") Date <br />
FROM prefix_scorm_scoes_track AS st <br />
JOIN prefix_user AS u ON st.userid=u.id<br />
JOIN prefix_scorm AS sc ON sc.id=st.scormid<br />
JOIN prefix_course AS c ON c.id=sc.course<br />
WHERE st.value='completed' <br />
ORDER BY c.fullname, u.lastname,u.firstname, st.attempt<br />
</code><br />
<br />
===Lists SCORM status for all enrolled users by Course name===<br />
This report will list the SCORM status for all users enrolled in the course. It is ordered first by Course name, then student's last name, then student's first name, then attempt number. This can be limited to individual courses by adding to the where clause the course id to report on. <br />
<code sql><br />
SELECT<br />
u.firstname AS First,<br />
u.lastname AS Last, <br />
u.idnumber AS Employee_ID, <br />
u.city AS City,<br />
uid.data AS State,<br />
u.country AS Country,<br />
g.name AS Group_name,<br />
c.fullname AS Course, <br />
st.attempt AS Attempt,<br />
st.value AS Status,<br />
FROM_UNIXTIME(st.timemodified,"%m-%d-%Y") AS Date <br />
<br />
FROM prefix_scorm_scoes_track AS st <br />
JOIN prefix_user AS u ON st.userid=u.id<br />
JOIN prefix_user_info_data AS uid ON uid.userid = u.id <br />
JOIN prefix_scorm AS sc ON sc.id=st.scormid<br />
JOIN prefix_course AS c ON c.id=sc.course<br />
JOIN prefix_groups AS g ON g.courseid = c.id<br />
JOIN prefix_groups_members AS m ON g.id = m.groupid<br />
<br />
WHERE st.element='cmi.core.lesson_status' AND m.userid=u.id<br />
<br />
UNION<br />
<br />
SELECT<br />
user2.firstname AS First,<br />
user2.lastname AS Last,<br />
user2. idnumber AS Employee_ID,<br />
user2.city AS City,<br />
uid.data AS State,<br />
user2.country AS Country,<br />
g.name AS Group_name,<br />
c.fullname AS Course,<br />
"-" AS Attempt,<br />
"not_started" AS Status,<br />
"-" AS Date<br />
<br />
FROM prefix_user_enrolments AS ue<br />
JOIN prefix_enrol AS e ON e.id = ue.enrolid<br />
JOIN prefix_course AS c ON c.id = e.courseid<br />
JOIN prefix_user AS user2 ON user2 .id = ue.userid<br />
JOIN prefix_user_info_data AS uid ON uid.userid = user2.id <br />
JOIN prefix_groups AS g ON g.courseid = c.id<br />
JOIN prefix_groups_members AS m ON g.id = m.groupid<br />
JOIN prefix_scorm AS sc ON sc.course=c.id<br />
Left Join prefix_scorm_scoes_track AS st on st.scormid=sc.id AND st.userid=user2.id<br />
<br />
WHERE st.timemodified IS NULL AND m.userid=user2.id<br />
<br />
ORDER BY Course, Last, First, Attempt<br />
<br />
</code><br />
<br />
== Badges==<br />
<br />
=== All badges issued, by User ===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
This report will show you all the badges on a site that have been issued, both site and all courses, by the username of each user issued a badge. Includes the type of criteria passed (activity, course completion, manual), date issued, date expires, and a direct link to that issued badge page so you can see all the other details for that badge.<br />
<br />
<code sql><br />
SELECT u.username, b.name AS badgename, <br />
CASE<br />
WHEN b.courseid IS NOT NULL THEN<br />
(SELECT c.shortname<br />
FROM prefix_course AS c<br />
WHERE c.id = b.courseid)<br />
WHEN b.courseid IS NULL THEN "*"<br />
END AS Context,<br />
CASE <br />
WHEN t.criteriatype = 1 AND t.method = 1 THEN "Activity Completion (All)"<br />
WHEN t.criteriatype = 1 AND t.method = 2 THEN "Activity Completion (Any)"<br />
WHEN t.criteriatype = 2 AND t.method = 2 THEN "Manual Award"<br />
WHEN t.criteriatype = 4 AND t.method = 1 THEN "Course Completion (All)"<br />
WHEN t.criteriatype = 4 AND t.method = 2 THEN "Course Completion (Any)"<br />
ELSE CONCAT ('Other: ', t.criteriatype)<br />
END AS Criteriatype,<br />
DATE_FORMAT( FROM_UNIXTIME( d.dateissued ) , '%Y-%m-%d' ) AS dateissued,<br />
DATE_FORMAT( FROM_UNIXTIME( d.dateexpire ), '%Y-%m-%d' ) AS dateexpires,<br />
CONCAT ('<a target="_new" href="%%WWWROOT%%/badges/badge.php?hash=',d.uniquehash,'">link</a>') AS Details<br />
FROM prefix_badge_issued AS d <br />
JOIN prefix_badge AS b ON d.badgeid = b.id<br />
JOIN prefix_user AS u ON d.userid = u.id<br />
JOIN prefix_badge_criteria AS t on b.id = t.badgeid <br />
WHERE t.criteriatype <> 0<br />
ORDER BY u.username<br />
</code><br />
<br />
Please note: the FROM_UNIXTIME command is for MySQL.<br />
<br />
=== All badges available in the system, with Earned count ===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
Report of all badges in the system, with badge name and description, context, course shortname if a course badge, whether it is active and available, and a count of how many users have been issued that badge.<br />
<br />
<code sql><br />
SELECT b.id, b.name, b.description,<br />
CASE<br />
WHEN b.type = 1 THEN "System"<br />
WHEN b.type = 2 THEN "Course"<br />
END AS Context, <br />
CASE<br />
WHEN b.courseid IS NOT NULL THEN <br />
(SELECT c.shortname <br />
FROM prefix_course AS c <br />
WHERE c.id = b.courseid)<br />
WHEN b.courseid IS NULL THEN "*"<br />
END AS Course, <br />
CASE<br />
WHEN b.status = 0 OR b.status = 2 THEN "No"<br />
WHEN b.status = 1 OR b.status = 3 THEN "Yes"<br />
WHEN b.status = 4 THEN "x"<br />
END AS Available,<br />
CASE<br />
WHEN b.status = 0 OR b.status = 1 THEN "0"<br />
WHEN b.status = 2 OR b.status = 3 OR b.status = 4 THEN <br />
(SELECT COUNT(*) <br />
FROM prefix_badge_issued AS d<br />
WHERE d.badgeid = b.id<br />
)<br />
END AS Earned<br />
FROM prefix_badge AS b<br />
<br />
</code><br />
<br />
=== Badges Leaderboard ===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
A simple list of usernames and how many badges they have earned overall.<br />
<br />
<code sql><br />
SELECT u.username, (SELECT COUNT(*) FROM prefix_badge_issued AS d WHERE d.userid = u.id) AS earned<br />
FROM prefix_user AS u<br />
ORDER BY earned DESC, u.username ASC<br />
</code><br />
<br />
=== Manage badges (System & Course) ===<br />
<br />
List system wide badges, course and system level badges + a link to relevant "manage badges" page.<br />
<br />
<code sql><br />
SELECT b.id, b.name, b.description <br />
,CASE <br />
WHEN b.type = 1 THEN 'System'<br />
WHEN b.type = 2 THEN 'Course'<br />
END AS Level<br />
,CONCAT('<a target="_new" href="%%WWWROOT%%/badges/index.php?type=', b.type, '&id=',<br />
c.id, '">Manage badges in: ', c.fullname, '</a>') AS Manage <br />
FROM prefix_badge AS b<br />
JOIN prefix_course AS c ON c.id = b.courseid<br />
</code><br />
<br />
==Administrator Reports==<br />
<br />
===Config changes in Export friendly form===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
The Administrative report Config changes is very useful but it would be nice to have it in a format that could be easily exported in one listing. Here is code to do that.<br />
<br />
<code sql><br />
SELECT <br />
DATE_FORMAT( FROM_UNIXTIME( g.timemodified ) , '%Y-%m-%d' ) AS date, <br />
u.username AS user, <br />
g.name AS setting, <br />
CASE <br />
WHEN g.plugin IS NULL THEN "core"<br />
ELSE g.plugin<br />
END AS plugin, <br />
g.value AS new_value, <br />
g.oldvalue AS original_value<br />
FROM prefix_config_log AS g<br />
JOIN prefix_user AS u ON g.userid = u.id<br />
ORDER BY date DESC<br />
</code><br />
<br />
===Cohorts by user===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
How to get a list of all users and which cohorts they belong to.<br />
<br />
<code sql><br />
SELECT u.firstname, u.lastname, h.idnumber, h.name<br />
FROM prefix_cohort AS h<br />
JOIN prefix_cohort_members AS hm ON h.id = hm.cohortid<br />
JOIN prefix_user AS u ON hm.userid = u.id<br />
ORDER BY u.firstname<br />
</code><br />
<br />
===Cohorts with Courses===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
List of all cohorts with name, id, visibility, and which courses they are enrolled in.<br />
<br />
<code sql><br />
SELECT<br />
# h.id,<br />
# e.customint1,<br />
h.name AS Cohort,<br />
h.idnumber AS Cohortid,<br />
CASE <br />
WHEN h.visible = 1 THEN 'Yes'<br />
ELSE '-'<br />
END AS Cohortvisible,<br />
CONCAT('<a target="_new" href="%%WWWROOT%%/course/view.php', CHAR(63),'id=',c.id,'">',c.fullname,'</a>') AS Course<br />
FROM prefix_cohort h<br />
JOIN prefix_enrol e ON h.id = e.customint1<br />
JOIN prefix_course c ON c.id = e.courseid %%FILTER_COURSES:e.courseid%% <br />
WHERE e.enrol = 'cohort' AND e.roleid = 5<br />
</code><br />
<br />
===Courses created And Active courses by Year===<br />
Active courses is counting course that have at least one Hit, And "Active_MoreThan100Hits" counts courses that have at least 100 Hits<br />
<code sql><br />
SELECT <br />
<br />
YEAR( FROM_UNIXTIME( `timecreated` ) ) AS YEAR, COUNT( * ) AS Counter<br />
<br />
, (SELECT COUNT( DISTINCT course ) <br />
FROM prefix_log AS l<br />
WHERE YEAR( FROM_UNIXTIME( l.`time` ) ) = YEAR( FROM_UNIXTIME( `timecreated` ) )<br />
) AS "Active"<br />
<br />
,(SELECT COUNT(*) FROM ( <br />
SELECT COUNT( * ),time <br />
FROM prefix_log AS l <br />
GROUP BY course <br />
HAVING COUNT(*) > 100) AS courses_log<br />
WHERE YEAR( FROM_UNIXTIME( courses_log.`time` ) ) = YEAR( FROM_UNIXTIME( `timecreated` ) )<br />
) AS "Active_MoreThan100Hits"<br />
<br />
FROM `prefix_course` <br />
GROUP BY YEAR( FROM_UNIXTIME( `timecreated` ) ) <br />
</code><br />
<br />
===Users created And Active users by Year===<br />
Active users is counting users that have at least one Hit, And "Active_MoreThan500Hits" counts users that have at least 500 Hits<br />
<code sql><br />
SELECT <br />
<br />
YEAR( FROM_UNIXTIME( `firstaccess` ) ) AS YEAR, COUNT( * ) AS Counter<br />
<br />
, (SELECT COUNT( DISTINCT userid ) <br />
FROM prefix_log AS l<br />
WHERE YEAR( FROM_UNIXTIME( l.`time` ) ) = YEAR( FROM_UNIXTIME( `firstaccess` ) )<br />
) AS "Active"<br />
<br />
,(SELECT COUNT(*) FROM ( <br />
SELECT COUNT( * ),time <br />
FROM prefix_log AS l <br />
GROUP BY userid <br />
HAVING COUNT(*) > 500) AS users_log<br />
WHERE YEAR( FROM_UNIXTIME( users_log.`time` ) ) = YEAR( FROM_UNIXTIME( `firstaccess` ) )<br />
) AS "Active_MoreThan500Hits"<br />
<br />
FROM `prefix_user` <br />
GROUP BY YEAR( FROM_UNIXTIME( `timecreated` ) ) <br />
</code><br />
<br />
===Course Aggregation Report===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
If you are considering upgrading from Moodle 2.6 to 2.8 or later, your grades may be changed. This report can help quantify and identify the courses at risk of changes.<br />
<br />
In particular, be on the lookout for any courses with the following combinations of parameters, which are known to cause changes in calculations:<br />
<br />
# mean of grades set with aggregate with subcategory.<br />
# Simple weighted mean of grades with aggregate with sub category and drop the lowest<br />
# Sum of grades drop the lowest<br />
<br />
Also review:<br />
https://tracker.moodle.org/browse/MDL-48618<br />
https://tracker.moodle.org/browse/MDL-48634<br />
https://tracker.moodle.org/browse/MDL-49257<br />
https://tracker.moodle.org/browse/MDL-50089<br />
https://tracker.moodle.org/browse/MDL-50062<br />
<br />
<code sql><br />
SELECT<br />
<br />
COUNT(c.shortname) AS 'Count of Courses'<br />
<br />
# If you want to display all the courses for each aggregation type, uncomment the next line and change GROUP BY settings<br />
#, c.shortname AS 'course name'<br />
<br />
# If you need to display grade categories for each aggregation type, uncomment the next line and change GROUP BY settings<br />
#, gc.fullname AS 'grade category name'<br />
<br />
, gc.aggregation AS 'aggregation method'<br />
<br />
#These aggregation text strings appear to be hard-coded. I couldn't find a table for them. If you have aggregation types I haven't included here, they'll be blank in your report results.<br />
, CASE gc.aggregation<br />
WHEN 0 THEN 'Mean of Grades'<br />
WHEN 2 THEN 'Median of Grades'<br />
WHEN 6 THEN 'Highest Grade'<br />
WHEN 8 THEN 'Mode of Grades'<br />
WHEN 10 THEN 'Weighted Mean of Grades'<br />
WHEN 11 THEN 'Simple Weighted Mean of Grades'<br />
WHEN 12 THEN 'Mean of Grades (with extra credits)'<br />
WHEN 13 THEN 'Sum of Grades'<br />
END AS 'aggregation name'<br />
<br />
# Note that gc.aggregatesubcats column is eliminated in 2.8 and later per MDL-47503, so comment that line on updated systems or you'll get an error<br />
, gc.keephigh AS 'keep high'<br />
, gc.droplow AS 'dr0p low'<br />
, gc.aggregateonlygraded AS 'Aggregate only graded'<br />
, gc.aggregateoutcomes AS 'aggregate outcomes'<br />
, gc.aggregatesubcats AS 'aggregate subcategories'<br />
<br />
# If you are displaying data about individual courses, you may want to know how old they are<br />
#, FROM_UNIXTIME(c.startdate) AS 'course start date'<br />
<br />
# If you are trying to use this report to check to see if final grades have changed after an upgrade, you might want these data items, but calculations can still change later when the courses are actually viewed. Also, you'll need to uncomment the necessary JOINs below<br />
#, gi.itemname AS 'grade item'<br />
#, gg.finalgrade AS 'final grade'<br />
<br />
FROM<br />
<br />
prefix_course AS c<br />
JOIN prefix_grade_categories AS gc ON gc.courseid = c.id<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
<br />
#LEFT JOIN prefix_grade_items AS gi ON gi.courseid = c.id #AND gi.categoryid=gc.id<br />
#LEFT JOIN prefix_grade_grades AS gg ON gg.itemid = gi.id AND gg.userid = u.id<br />
<br />
WHERE<br />
1<br />
#AND gc.aggregation = 13 #only the dreaded Sum of Grades aggregations<br />
#AND gc.depth = 1 # if for some reason you only want course aggregations, not subcategories<br />
<br />
<br />
GROUP BY gc.aggregation, gc.keephigh, gc.droplow, gc.aggregateonlygraded, gc.aggregateoutcomes, gc.aggregatesubcats<br />
<br />
</code><br />
<br />
=== Running Cron jobs (task_scheduled) ===<br />
<code sql><br />
SELECT classname<br />
,DATE_FORMAT(FROM_UNIXTIME(lastruntime), '%H:%i [%d]') AS 'last'<br />
,DATE_FORMAT(now(), '%H:%i') AS 'now'<br />
,DATE_FORMAT(FROM_UNIXTIME(nextruntime), '%H:%i [%d]') AS 'next'<br />
,DATE_FORMAT(FROM_UNIXTIME(UNIX_TIMESTAMP()-nextruntime), '%i') AS 'next in min'<br />
FROM mdl_task_scheduled<br />
WHERE now() > FROM_UNIXTIME(nextruntime)<br />
</code><br />
<br />
=== All Meta courses with Parent and Child course relationships ===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
This shows the list of courses with Meta course link enrollments in them ('Parent course'), and the courses which are connected to them to provide enrollments ('Child courses').<br />
<br />
<code sql><br />
SELECT <br />
c.fullname AS 'Parent course name',<br />
c.shortname AS 'Parent course shortname',<br />
en.courseid AS 'Parent course id',<br />
(SELECT fullname FROM prefix_course WHERE prefix_course.id = en.customint1) As 'Child course name',<br />
(SELECT shortname FROM prefix_course WHERE prefix_course.id = en.customint1) As 'Child course shortname',<br />
en.customint1 AS 'Child course id'<br />
FROM prefix_enrol en<br />
JOIN prefix_course c ON c.id = en.courseid<br />
WHERE en.enrol = 'meta'<br />
ORDER BY c.fullname<br />
</code><br />
<br />
== Useful sub queries ==<br />
<br />
IN this section please put any short one purpose sub queries that show how common procedures often useful as part of larger queries.<br />
<br />
=== All teachers in the course ===<br />
<br />
<br />
This snippet shows how to get teachers from a course. The contextevel for course objects is 50. And the default Teacher role is role id 3.<br />
<br />
<code sql><br />
,(SELECT GROUP_CONCAT( CONCAT( u.firstname, " ", u.lastname ) ) <br />
FROM prefix_course ic<br />
JOIN prefix_context con ON con.instanceid = ic.id<br />
JOIN prefix_role_assignments ra ON con.id = ra.contextid AND con.contextlevel = 50<br />
JOIN prefix_role r ON ra.roleid = r.id<br />
JOIN prefix_user u ON u.id = ra.userid<br />
WHERE r.id = 3 AND ic.id = c.id<br />
GROUP BY ic.id<br />
) AS TeacherNames<br />
</code><br />
<br />
=== Get custom User profile fields for a user ===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
This snippet of code shows how to connect a user with their custom profile field data. This will list all users with all custom profile fields and data. Custom profile fields have two tables, one for the definition of the profile field (user_info_field) and its settings, and a separate table to hold the data entered by users (user_info_data). <br />
<br />
<code sql><br />
SELECT u.username, uif.name, uid.data<br />
FROM prefix_user AS u<br />
JOIN prefix_user_info_data AS uid ON uid.userid = u.id<br />
JOIN prefix_user_info_field AS uif ON uid.fieldid = uif.id <br />
</code><br />
<br />
If you want to limit it to one of those fields, you can restrict it by shortname of the custom profile field, so:<br />
<br />
<code sql><br />
SELECT u.username, uif.name, uid.data<br />
FROM prefix_user AS u<br />
JOIN prefix_user_info_data AS uid ON uid.userid = u.id<br />
JOIN prefix_user_info_field AS uif ON (uid.fieldid = uif.id AND uif.shortname = 'shortname1')<br />
</code><br />
<br />
will show you only the data from the custom profile field with the shortname 'shortname1'.<br />
<br />
If you want to do this with two or more custom profile fields, you will need to have a JOIN and table alias for each with a restriction for each profile field shortname. Example:<br />
<br />
<code sql><br />
SELECT u.username, d1.data AS 'Profile One', d2.data As 'Profile Two'<br />
FROM prefix_user u<br />
JOIN prefix_user_info_data d1 ON d1.userid = u.id<br />
JOIN prefix_user_info_field f1 ON d1.fieldid = f1.id AND f1.shortname = 'shortname1'<br />
JOIN prefix_user_info_data d2 ON d2.userid = u.id<br />
JOIN prefix_user_info_field f2 ON d2.fieldid = f2.id AND f2.shortname = 'shortname2'<br />
</code><br />
<br />
==== NOTE: Alternate Method ====<br />
<br />
If you have more than a couple of fields you need to use, then this query may time out or not return data due to too many joins. The limit seems to be around 10 custom profile fields. <br />
<br />
Instead you should use an alternate method which uses Subselects for each of the profile fields. Details and sample code are in this forum discussion: https://moodle.org/mod/forum/discuss.php?d=355502#p1434854. A sample of the style is:<br />
<br />
<code sql><br />
SELECT u.username<br />
<br />
,(SELECT d1.data FROM prefix_user_info_data d1<br />
JOIN prefix_user_info_field f1 ON d1.fieldid = f1.id AND f1.shortname = 'shortname1'<br />
WHERE d1.userid = u.id<br />
) AS thefirstfield<br />
<br />
,(SELECT d1.data FROM prefix_user_info_data d1<br />
JOIN prefix_user_info_field f1 ON d1.fieldid = f1.id AND f1.shortname = 'shortname2'<br />
WHERE d1.userid = u.id<br />
) AS thesecondfield<br />
<br />
FROM prefix_user u<br />
</code><br />
<br />
=== How to use Configurable Reports Date Time Filters===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
In the Configurable Reports block, you can set the Time and Date filter to allow you to pick your report Start date/time and End date/time interactively. This will work on any column in a table that is a timestamp.<br />
<br />
Here is a simple example:<br />
<br />
<code sql><br />
SELECT u.username, <br />
DATE_FORMAT(FROM_UNIXTIME(u.firstaccess),'%Y-%m-%d %H:%i') AS 'FirstAccess',<br />
DATE_FORMAT(FROM_UNIXTIME(u.lastaccess),'%Y-%m-%d %H:%i') AS 'LastAccess' <br />
FROM prefix_user u<br />
<br />
WHERE 1=1<br />
%%FILTER_STARTTIME:u.firstaccess:>%% <br />
%%FILTER_ENDTIME:u.lastaccess:<%% <br />
</code><br />
<br />
1) You will need to replace name of the table and column for the filter to use the time and date column you need for your query. In the example above, it filters on the firstaccess and lastaccess columns in the user table. If you were doing a report on course completion, you might put the timecompleted column, and so forth.<br />
<br />
2) You MUST then add the Start / End date filter on the Filters tab of the Report. If you don't, the report will still run, probably, but the filter will be ignored.<br />
<br />
Note: the WHERE 1=1 statement is a peculiarity of the filters in Config reports: if you don't have a WHERE statement in your query already, then you must add this dummy WHERE to keep the statement valid. If you already have a WHERE statement in your code, simply add the %%FILTER%% placeholders after it (and before any GROUP or ORDER BY statements.)<br />
<br />
==See also==<br />
* [https://github.com/jleyva/moodle-configurable_reports_repository Configurable Reports Repository on GitHub]<br />
* [https://moodleschema.zoola.io/index.html Moodle DB schema explorer] - searching and filtering tables, fields and external key connections between tables.<br />
<br />
[[Category:Contributed code]]<br />
<br />
[[es:Reportes específicos hechos por usuarios]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=ad-hoc_contributed_reports&diff=133235ad-hoc contributed reports2019-03-07T09:02:54Z<p>Fox: /* Module activity (Instances and Hits) for each academic year */ Updated for new (since Moodle 2.7) log table</p>
<hr />
<div>{{Sitewide reports}}<br />
==User and Role Report==<br />
<br />
===Count number of distinct learners and teachers enrolled per category (including all its sub categories)===<br />
<code sql>SELECT COUNT(DISTINCT lra.userid) AS learners, COUNT(DISTINCT tra.userid) as teachers<br />
FROM prefix_course AS c #, mdl_course_categories AS cats<br />
LEFT JOIN prefix_context AS ctx ON c.id = ctx.instanceid<br />
JOIN prefix_role_assignments AS lra ON lra.contextid = ctx.id<br />
JOIN prefix_role_assignments AS tra ON tra.contextid = ctx.id<br />
JOIN prefix_course_categories AS cats ON c.category = cats.id<br />
WHERE c.category = cats.id<br />
AND (<br />
cats.path LIKE '%/CATEGORYID/%' #Replace CATEGORYID with the category id you want to count (eg: 80)<br />
OR cats.path LIKE '%/CATEGORYID'<br />
)<br />
AND lra.roleid=5<br />
AND tra.roleid=3</code><br />
<br />
===Detailed ACTIONs for each ROLE (TEACHER, NON-EDITING TEACHER and STUDENT)===<br />
<code sql><br />
SELECT r.name, l.action, COUNT( l.userid ) AS counter<br />
FROM prefix_log AS l<br />
JOIN prefix_context AS context ON context.instanceid = l.course AND context.contextlevel = 50<br />
JOIN prefix_role_assignments AS ra ON l.userid = ra.userid AND ra.contextid = context.id<br />
JOIN prefix_role AS r ON ra.roleid = r.id<br />
WHERE ra.roleid IN ( 3, 4, 5 ) <br />
GROUP BY roleid, l.action<br />
</code><br />
<br />
===Student (user) COUNT in each Course===<br />
Including (optional) filter by: year (if included in course fullname).<br />
<code sql><br />
SELECT CONCAT('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',course.id,'">',course.fullname,'</a>') AS Course<br />
,CONCAT('<a target="_new" href="%%WWWROOT%%/user/index.php?contextid=',context.id,'">Show users</a>') AS Users<br />
, COUNT(course.id) AS Students<br />
FROM prefix_role_assignments AS asg<br />
JOIN prefix_context AS context ON asg.contextid = context.id AND context.contextlevel = 50<br />
JOIN prefix_user AS user ON user.id = asg.userid<br />
JOIN prefix_course AS course ON context.instanceid = course.id<br />
WHERE asg.roleid = 5 <br />
# AND course.fullname LIKE '%2013%'<br />
GROUP BY course.id<br />
ORDER BY COUNT(course.id) DESC<br />
</code><br />
<br />
=== Enrolment count in each Course ===<br />
<br />
Shows the total number of enroled users of all roles in each course. Sorted by course name.<br />
<br />
<code sql><br />
SELECT c.fullname, COUNT(ue.id) AS Enroled<br />
FROM prefix_course AS c <br />
JOIN prefix_enrol AS en ON en.courseid = c.id<br />
JOIN prefix_user_enrolments AS ue ON ue.enrolid = en.id<br />
GROUP BY c.id<br />
ORDER BY c.fullname<br />
</code><br />
<br />
===LIST of all site USERS by COURSE enrollment (Moodle 2.x)===<br />
<br />
<code sql><br />
SELECT<br />
user2.firstname AS Firstname,<br />
user2.lastname AS Lastname,<br />
user2.email AS Email,<br />
user2.city AS City,<br />
course.fullname AS Course<br />
,(SELECT shortname FROM prefix_role WHERE id=en.roleid) as Role<br />
,(SELECT name FROM prefix_role WHERE id=en.roleid) as RoleName<br />
<br />
FROM prefix_course as course <br />
JOIN prefix_enrol AS en ON en.courseid = course.id<br />
JOIN prefix_user_enrolments AS ue ON ue.enrolid = en.id<br />
JOIN prefix_user AS user2 ON ue.userid = user2.id<br />
</code><br />
<br />
===Enrolled users,which did not login into the Course, even once (Moodle 2)===<br />
Designed forMoodle 2 table structure and uses special plugin filter : %%FILTER_SEARCHTEXT:table.field%%<br />
<br />
<code sql><br />
SELECT<br />
user2.id as ID,<br />
ul.timeaccess,<br />
user2.firstname AS Firstname,<br />
user2.lastname AS Lastname,<br />
user2.email AS Email,<br />
user2.city AS City,<br />
user2.idnumber AS IDNumber,<br />
user2.phone1 AS Phone,<br />
user2.institution AS Institution,<br />
<br />
IF (user2.lastaccess = 0,'never',<br />
DATE_FORMAT(FROM_UNIXTIME(user2.lastaccess),'%Y-%m-%d')) AS dLastAccess<br />
<br />
,(SELECT DATE_FORMAT(FROM_UNIXTIME(timeaccess),'%Y-%m-%d') FROM prefix_user_lastaccess WHERE userid=user2.id and courseid=c.id) as CourseLastAccess<br />
<br />
,(SELECT r.name<br />
FROM prefix_user_enrolments AS uenrol<br />
JOIN prefix_enrol AS e ON e.id = uenrol.enrolid<br />
JOIN prefix_role AS r ON e.id = r.id<br />
WHERE uenrol.userid=user2.id and e.courseid = c.id) AS RoleName<br />
<br />
FROM prefix_user_enrolments as ue<br />
JOIN prefix_enrol as e on e.id = ue.enrolid<br />
JOIN prefix_course as c ON c.id = e.courseid<br />
JOIN prefix_user as user2 ON user2 .id = ue.userid<br />
LEFT JOIN prefix_user_lastaccess as ul on ul.userid = user2.id<br />
WHERE c.id=16 AND ul.timeaccess IS NULL<br />
%%FILTER_SEARCHTEXT:user2.firstname%%<br />
</code><br />
<br />
===Role assignments on categories===<br />
<code sql><br />
SELECT <br />
concat('<a target="_new" href="%%WWWROOT%%/course/category.php?id=',cc.id,'">',cc.id,'</a>') AS id,<br />
concat('<a target="_new" href="%%WWWROOT%%/course/category.php?id=',cc.id,'">',cc.name,'</a>') AS category,<br />
cc.depth, cc.path, r.name AS role,<br />
concat('<a target="_new" href="%%WWWROOT%%/user/view.php?id=',usr.id,'">',usr.lastname,'</a>') AS name,<br />
usr.firstname, usr.username, usr.email<br />
FROM prefix_course_categories cc<br />
INNER JOIN prefix_context cx ON cc.id = cx.instanceid<br />
AND cx.contextlevel = '40'<br />
INNER JOIN prefix_role_assignments ra ON cx.id = ra.contextid<br />
INNER JOIN prefix_role r ON ra.roleid = r.id<br />
INNER JOIN prefix_user usr ON ra.userid = usr.id<br />
ORDER BY cc.depth, cc.path, usr.lastname, usr.firstname, r.name, cc.name<br />
</code><br />
<br />
===Permissions Overides on Categories===<br />
(By: [http://moodle.org/mod/forum/discuss.php?d=153059#p712834 Séverin Terrier] )<br />
<code sql><br />
SELECT rc.id, ct.instanceid, ccat.name, rc.roleid, rc.capability, rc.permission, <br />
DATE_FORMAT( FROM_UNIXTIME( rc.timemodified ) , '%Y-%m-%d' ) AS timemodified, rc.modifierid, ct.instanceid, ct.path, ct.depth<br />
FROM `prefix_role_capabilities` AS rc<br />
INNER JOIN `prefix_context` AS ct ON rc.contextid = ct.id<br />
INNER JOIN `prefix_course_categories` AS ccat ON ccat.id = ct.instanceid<br />
AND `contextlevel` =40<br />
</code><br />
<br />
===Lists "Totally Opened Courses" (visible, opened to guests, with no password)===<br />
(By: [http://moodle.org/mod/forum/discuss.php?d=153059#p712837 Séverin Terrier] )<br />
<code sql><br />
SELECT<br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.id,'</a>') AS id,<br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.shortname,'</a>') AS 'Course',<br />
concat('<a target="_new" href="%%WWWROOT%%/enrol/instances.php?id=',c.id,'">Méthodes inscription</a>') AS 'Enrollment plugins',<br />
e.sortorder<br />
FROM prefix_enrol AS e, prefix_course AS c<br />
WHERE e.enrol='guest' AND e.status=0 AND e.password='' AND c.id=e.courseid AND c.visible=1<br />
</code><br />
<br />
===Lists "loggedin users" from the last 120 days===<br />
<code sql><br />
SELECT id,username,FROM_UNIXTIME(`lastlogin`) as days <br />
FROM `prefix_user` <br />
WHERE DATEDIFF( NOW(),FROM_UNIXTIME(`lastlogin`) ) < 120<br />
</code><br />
<br />
''and user count for that same population:''<br />
<code sql><br />
SELECT COUNT(id) as Users FROM `prefix_user` <br />
WHERE DATEDIFF( NOW(),FROM_UNIXTIME(`lastlogin`) ) < 120<br />
</code><br />
<br />
==== Users loggedin within the last 7 days ====<br />
<code sql><br />
SELECT<br />
l.* FROM mdl_logstore_standard_log l<br />
WHERE<br />
l.eventname = '\\core\\event\\user_loggedin'<br />
AND FROM_UNIXTIME(l.timecreated, '%Y-%m-%d') >= DATE_SUB(NOW(), INTERVAL 7 DAY)<br />
<br />
SELECT l.eventname FROM mdl_logstore_standard_log l<br />
GROUP BY l.eventname<br />
</code><br />
<br />
===Lists the users who have only logged into the site once===<br />
<code sql><br />
SELECT id, username, firstname, lastname, idnumber<br />
FROM prefix_user<br />
WHERE prefix_user.deleted = 0<br />
AND prefix_user.lastlogin = 0 <br />
AND prefix_user.lastaccess > 0<br />
</code><br />
<br />
===Students in all courses of some institute===<br />
What is the status (deleted or not) of all Students (roleid = 5) in all courses of some Institute<br />
<code sql><br />
SELECT c.id, c.fullname, u.firstname, u.lastname, u.deleted<br />
FROM prefix_course AS c<br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid<br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE ra.roleid =5<br />
AND ctx.instanceid = c.id<br />
AND u.institution = 'please enter school name here'<br />
</code><br />
<br />
===Full User info (for deleted users)===<br />
Including extra custom profile fields (from prefix_user_info_data)<br />
<code sql><br />
SELECT * <br />
FROM prefix_user as u <br />
JOIN prefix_user_info_data as uid ON uid.userid = u.id <br />
JOIN prefix_user_info_field as uif ON (uid.fieldid = uif.id AND uif.shortname = 'class')<br />
WHERE `deleted` = "1" and `institution`="your school name" and `department` = "your department" and `data` = "class level and number"<br />
</code><br />
<br />
===User's courses===<br />
change "u.id = 2" with a new user id<br />
<code sql><br />
SELECT u.firstname, u.lastname, c.id, c.fullname<br />
FROM prefix_course AS c<br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid<br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE u.id = 2<br />
</code><br />
<br />
===List Users with extra info (email) in current course===<br />
blocks/configurable_reports replaces %%COURSEID%% with course id.<br />
<code sql><br />
SELECT u.firstname, u.lastname, u.email<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS context ON context.id = ra.contextid AND context.contextlevel = 50<br />
JOIN prefix_course AS c ON c.id = context.instanceid AND c.id = %%COURSEID%%<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
</code><br />
<br />
===List Students with enrollment and completion dates in current course===<br />
This is meant to be a "global" report in Configurable Reports containing the following:<br />
firstname, lastname, idnumber, institution, department, email, student enrolment date, student completion date<br />
Note: for PGSQL, use to_timestamp() instead of FROM_UNIXTIME()<br />
Contributed by Elizabeth Dalton, Moodle HQ<br />
<br />
<code sql><br />
SELECT <br />
u.firstname<br />
, u.lastname<br />
, u.idnumber<br />
, u.institution<br />
, u.department<br />
, u.email<br />
, FROM_UNIXTIME(cc.timeenrolled)<br />
, FROM_UNIXTIME(cc.timecompleted)<br />
<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS context ON context.id = ra.contextid AND context.contextlevel = 50<br />
JOIN prefix_course AS c ON c.id = context.instanceid AND c.id = %%COURSEID%%<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
JOIN prefix_course_completions AS cc ON cc.course = c.id AND cc.userid = u.id<br />
</code><br />
<br />
===Special Roles===<br />
<code sql><br />
SELECT ra.roleid,r.name<br />
,concat('<a target="_new" href="%%WWWROOT%%/course/user.php?id=1&user=',ra.userid,'">',u.firstname ,' ',u.lastname,'</a>') AS Username<br />
,concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS Course<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_role AS r ON r.id = ra.roleid<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
JOIN prefix_context AS ctx ON (ctx.id = ra.contextid AND ctx.contextlevel = 50)<br />
JOIN prefix_course AS c ON ctx.instanceid = c.id<br />
WHERE ra.roleid > 6<br />
</code><br />
<br />
===Courses without Teachers===<br />
Actually, shows the number of Teachers in a course.<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') as Course<br />
,(SELECT Count( ra.userid ) AS Users FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id) AS Teachers<br />
FROM prefix_course AS c<br />
ORDER BY Teachers ASC<br />
</code><br />
<br />
===List of users who have been enrolled for more than 4 weeks===<br />
For Moodle 2.2 , by Isuru Madushanka Weerarathna <br />
<code sql><br />
SELECT uenr.userid As User, IF(enr.courseid=uenr.courseid ,'Y','N') As Enrolled, <br />
IF(DATEDIFF(NOW(), FROM_UNIXTIME(uenr.timecreated))>=28,'Y','N') As EnrolledMoreThan4Weeks<br />
FROM prefix_enrol As enr, prefix_user_enrolments AS uenr<br />
WHERE enr.id = uenr.enrolid AND enr.status = uenr.status<br />
</code><br />
<br />
=== List of users with language===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
An issue with systems that do not have their default language set up properly is the need to do a mass change for all users to a localization. A common case is changing default English to American English. <br />
<br />
This will show you the language setting for all users:<br />
<code sql><br />
SELECT username, lang from prefix_user <br />
</code><br />
<br />
NOTE: UPDATE commands require the ability to alter the database directly via tools like Adminer or PHPMyAdmin or other db tools.<br />
<br />
This code will change the setting from 'en' to 'en_us' for all users:<br />
<br />
<code sql><br />
UPDATE prefix_user SET lang = 'en_us' WHERE lang = 'en'<br />
</code><br />
<br />
To do this for only users who have a particular country set, use this as an example:<br />
<code sql><br />
UPDATE prefix_user SET lang = 'en_us' WHERE country = 'US' AND lang = 'en'<br />
</code><br />
<br />
=== List of users with Authentication ===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
Sometimes you need to do mass changes of authentication methods. A common case is changing default manual to LDAP. <br />
<br />
This will show you the Authentication setting for all users:<br />
<code sql><br />
SELECT username, auth from prefix_user <br />
</code><br />
<br />
NOTE: UPDATE commands require the ability to alter the database directly via tools like Adminer or PHPMyAdmin or other db tools. <br />
<br />
This code will change the setting from 'manual' to 'ldap' for all users except for the first two accounts which are Guest and Admin. (WARNING: it is bad practice to change your admin account from manual to an external method as failure of that external method will lock you out of Moodle as admin.)<br />
<br />
<code sql><br />
UPDATE prefix_user SET auth = 'ldap' WHERE auth = 'manual' AND id > 2<br />
</code><br />
<br />
=== Compare role capability and permissions ===<br />
<code sql><br />
SELECT DISTINCT mrc.capability <br />
,(SELECT rc.permission FROM `mdl_role_capabilities` AS rc WHERE rc.capability = mrc.capability <br />
AND rc.roleid = '1' AND rc.contextid = '1') AS Manager<br />
,(SELECT rc.permission FROM `mdl_role_capabilities` AS rc WHERE rc.capability = mrc.capability <br />
AND rc.roleid = '2' AND rc.contextid = '1') AS CourseCreator<br />
,(SELECT rc.permission FROM `mdl_role_capabilities` AS rc WHERE rc.capability = mrc.capability <br />
AND rc.roleid = '3' AND rc.contextid = '1') AS Teacher<br />
,(SELECT rc.permission FROM `mdl_role_capabilities` AS rc WHERE rc.capability = mrc.capability <br />
AND rc.roleid = '4' AND rc.contextid = '1') AS AssistantTeacher<br />
,(SELECT rc.permission FROM `mdl_role_capabilities` AS rc WHERE rc.capability = mrc.capability <br />
AND rc.roleid = '5' AND rc.contextid = '1') AS Student<br />
,(SELECT rc.permission FROM `mdl_role_capabilities` AS rc WHERE rc.capability = mrc.capability <br />
AND rc.roleid = '6' AND rc.contextid = '1') AS Guest<br />
<br />
FROM `mdl_role_capabilities` AS mrc<br />
</code><br />
<br />
=== User's accumulative time spent in course ===<br />
A sum up of the time delta between logstore_standard_log user's records, considering the a 2 hour session limit.<br />
<br />
Uses: current user's id %%USERID%% and current course's id %%COURSEID%% <br />
<br />
And also using a date filter (which can be ignored) <br />
<br />
The extra "User" field is used as a dummy field for the Line chart Series field, in which I use X=id, Series=Type, Y=delta.<br />
<br />
<code sql><br />
SELECT <br />
l.id, <br />
l.timecreated, <br />
DATE_FORMAT(FROM_UNIXTIME(l.timecreated),'%d-%m-%Y') AS dTime,<br />
@prevtime := (SELECT max(timecreated) FROM mdl_logstore_standard_log <br />
WHERE userid = %%USERID%% and id < l.id ORDER BY id ASC LIMIT 1) AS prev_time,<br />
IF (l.timecreated - @prevtime < 7200, @delta := @delta + (l.timecreated-@prevtime),0) AS sumtime,<br />
l.timecreated-@prevtime AS delta,<br />
"User" as type<br />
<br />
FROM prefix_logstore_standard_log as l, <br />
(SELECT @delta := 0) AS s_init <br />
# Change UserID<br />
WHERE l.userid = %%USERID%% AND l.courseid = %%COURSEID%%<br />
%%FILTER_STARTTIME:l.timecreated:>%% %%FILTER_ENDTIME:l.timecreated:<%% <br />
</code><br />
<br />
=== Low-Participation Student Report ===<br />
Contributed by Elizabeth Dalton, Granite State College / Moodle HQ<br />
<br />
This report returns a list of students who are enrolled in courses filtered by a short-name text marker (in this case "OL-") in the specified category, but have very low participation in the course during the specified time period (fewer than 2 "Edits" to Activity Modules, indicating few active contributions to the course). The number of "Edits" is provided for each student for the time period specified.<br />
<br />
An "Edit" is defined as course activity other than viewing content. Click the "Logs" link to review the student activity. The Logs offer the option to review "View" activity as well as "Edit" activity.<br />
<br />
Only "visible" courses are included in this report. The report may be downloaded as an Excel spreadsheet.<br />
<br />
Don't forget to set up Filters: "Start / End date filter" and "Filter categories" on the Filters tab in Configurable reports.<br />
<br />
<code sql><br />
SELECT u.lastname AS Last, u.firstname AS First, u.idnumber AS IDnumber, u.email AS email, c.shortname AS CourseID, count(l.id) AS Edits, CONCAT('<a target="_new" href="https://learn.granite.edu/report/log/index.php',CHAR(63),'chooselog=1&showusers=1&showcourses=0&id=',c.id,'&user=',u.id,'&date=0&modid=&modaction=-view&logformat=showashtml','">','Logs','</a>') AS Link<br />
<br />
FROM prefix_user AS u<br />
JOIN prefix_role_assignments AS ra ON u.id = ra.userid<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
<br />
LEFT JOIN prefix_log AS l ON l.userid = u.id AND l.course = c.id AND l.action NOT LIKE "view%" %%FILTER_STARTTIME:l.TIME:>%% %%FILTER_ENDTIME:l.TIME:<%%<br />
<br />
WHERE ra.roleid =5<br />
AND ctx.instanceid = c.id<br />
AND c.visible=1<br />
# This prefix filter allows the exclusion of non-online courses at the original institution. Alter this to fit your institution, or remove it.<br />
AND c.shortname LIKE '%OL-%'<br />
%%FILTER_CATEGORIES:c.category%%<br />
<br />
GROUP BY u.idnumber<br />
<br />
HAVING Edits < 2<br />
</code><br />
<br />
=== Messages of All Users in a Specific Course ===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
NOTE: This query will probably not work at all in 3.5 now due to the changes in the structure of the Messages database. - RT<br />
<br />
This query shows the personal messages between users in a specific course, given the course id number. Properly speaking, personal messages pertain only to users and are not part of courses, but by filtering enrollments for roles in a course, you can show this. <br />
<br />
This report as is shows only the messages between Teachers and Students, as the WHERE statement contains and AND ((...))) section that restrict this report to ONLY messages between Teachers (role id = 3) and Students (role id =5). Remove that part of the statement if you wish to see _all_ messages between all users, e.g. teachers to teachers, student to student. <br />
<br />
Also, if you have created custom roles, you can replace the default id numbers with custom ones to further enhance the report.<br />
<br />
<code sql><br />
SELECT <br />
u.username AS 'From',<br />
CONCAT(u.firstname ,' ',u.lastname) AS 'From Name',<br />
u2.username AS 'To',<br />
CONCAT(u2.firstname ,' ',u2.lastname) AS 'To Name',<br />
DATE_FORMAT(FROM_UNIXTIME(me.timecreated), '%Y-%m-%d %H:%i') AS 'When',<br />
me.subject AS 'Subject', <br />
me.smallmessage AS 'Message'<br />
FROM prefix_message me<br />
JOIN prefix_role_assignments AS ra ON ra.userid = me.useridfrom AND ra.roleid IN (3,4,5) <br />
JOIN prefix_role_assignments AS ra2 ON ra2.userid = me.useridto AND ra2.roleid IN (3,4,5) <br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id AND ra2.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
JOIN prefix_user u ON u.id = me.useridfrom<br />
JOIN prefix_user u2 ON u2.id = me.useridto<br />
WHERE c.id=## <br />
AND ((ra.roleid = 3 AND ra2.roleid = 5) OR (ra.roleid = 5 AND ra2.roleid = 3)) <br />
ORDER BY me.useridfrom, me.useridto, me.timecreated<br />
</code><br />
<br />
==Log Activity Reports==<br />
===Count all Active Users by ROLE in a course category (including all of its sub-categories)===<br />
<code sql><br />
SELECT COUNT(DISTINCT l.userid) as active<br />
FROM mdl_course as c<br />
JOIN mdl_context AS ctx ON ctx.instanceid=c.id<br />
JOIN mdl_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN mdl_user_lastaccess as l ON ra.userid = l.userid<br />
JOIN mdl_course_categories AS cats ON c.category = cats.id<br />
WHERE c.category=cats.id AND (<br />
cats.path LIKE '%/80/%'<br />
OR cats.path LIKE '%/80'<br />
) <br />
AND ra.roleid=3 AND ctx.contextlevel=50 #ra.roleid= TEACHER 3, NON-EDITING TEACHER 4, STUDENT 5<br />
AND l.timeaccess > (unix_timestamp() - ((60*60*24)*NO_OF_DAYS)) #NO_OF_DAYS change to number<br />
</code><br />
===Detailed "VIEW" ACTION for each ROLE (TEACHER,NONE-EDITING TEACHER and STUDENT)===<br />
<code sql><br />
SELECT l.action, count( l.userid ) as counter , r.name<br />
FROM `prefix_log` as l<br />
JOIN `prefix_role_assignments` AS ra on l.userid = ra.userid<br />
JOIN `prefix_role` AS r ON ra.roleid = r.id<br />
WHERE (ra.roleid IN (3,4,5)) AND (l.action LIKE '%view%' )<br />
GROUP BY roleid,l.action<br />
order by r.name,counter desc<br />
</code><br />
<br />
===Total Activity of Roles:"Teacher" and "None-Editing Teacher" by Dates and by Hours===<br />
The output columns of this report table can be used as base for a Pivot-Table<br />
which will show the amount of '''activity''' per '''hour''' per '''days''' in 3D graph view.<br />
<br />
<code sql><br />
SELECT DATE_FORMAT( FROM_UNIXTIME( l.time ) , '%Y-%m-%d' ) AS grptimed ,<br />
DATE_FORMAT( FROM_UNIXTIME( l.time ) , '%k' ) AS grptimeh , count( l.userid ) AS counter <br />
FROM `prefix_log` AS l<br />
JOIN prefix_user AS u ON u.id = l.userid<br />
JOIN prefix_role_assignments AS ra ON l.userid = ra.userid<br />
JOIN prefix_role AS r ON r.id = ra.roleid<br />
WHERE ra.roleid IN (3,4)<br />
GROUP BY grptimed,grptimeh<br />
ORDER BY grptimed,grptimeh<br />
</code><br />
<br />
===How many LOGINs per user and user's Activity===<br />
+ link username to a user activity graph report<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/user.php?id=1&user=',u.id,'&mode=alllogs">',u.firstname ,' ',u.lastname,'</a>') as Username<br />
,count(*) as logins<br />
,(SELECT count(*) FROM prefix_log WHERE userid = l.userid GROUP BY userid) as Activity <br />
FROM prefix_log as l JOIN prefix_user as u ON l.userid = u.id <br />
WHERE `action` LIKE '%login%' group by userid<br />
ORDER BY Activity DESC<br />
</code><br />
===Distinct user logins per month===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
The following will show you the months of the current calendar year with the total number of distinct, unique user logins per month. Change the year in the WHERE clause to the year you need.<br />
<br />
<code sql><br />
SELECT <br />
COUNT(DISTINCT l.userid) AS 'DistinctUserLogins', <br />
DATE_FORMAT(FROM_UNIXTIME(l.timecreated), '%M') AS 'Month'<br />
FROM prefix_logstore_standard_log l<br />
WHERE l.action = 'loggedin' AND YEAR(FROM_UNIXTIME(l.timecreated)) = '2017' <br />
GROUP BY MONTH(FROM_UNIXTIME(l.timecreated))<br />
</code><br />
<br />
===Total activity per course, per unique user on the last 24h===<br />
<code sql><br />
SELECT<br />
COUNT(DISTINCT userid) AS countUsers<br />
, COUNT(l.courseid) AS countVisits<br />
, CONCAT('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">', c.fullname, '</a>') AS Course<br />
<br />
FROM mdl_logstore_standard_log AS l<br />
JOIN mdl_course AS c ON c.id = l.courseid<br />
WHERE l.courseid > 0<br />
AND FROM_UNIXTIME(l.timecreated) >= DATE_SUB(NOW(), INTERVAL 1 DAY)<br />
AND c.fullname LIKE '%תשעו%'<br />
GROUP BY l.courseid<br />
ORDER BY countVisits DESC<br />
</code><br />
<br />
===Weekly Instructor Online Participation===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
Displays participation of instructors in all courses per week of a term, including pre-term and post-term edits. An edit is defined as a change to the course, such as a discussion post, the grading of an assignment, or the uploading of file attachments, as well as alterations to course content.<br />
<br />
* To specify a subject and/or course number, use % as a wildcard, e.g. ARTS% or ARTS501%<br />
* To match part of a last name, use %, e.g. Smi% will match "Smith", "Smile", etc.<br />
<br />
At our institution, we include filters on the course name or category to constrain by terms. These are very specific to how course names and categories are constructed at our institution, so I've removed those elements from this code. Also, our terms are 12 weeks long. You would want to insert additional "SUM" lines for longer terms, or remove lines for shorter terms.<br />
<br />
'''Note''': This report can take a long time to run. While it can be run in Configurable Reports on demand, it may be more appropriate to implement it in the Ad Hoc Queries plugin as a scheduled report.<br />
<br />
'''Note''': This version uses legacy (pre-2.7) logs. See below for post-2.7 Standard Logs version.<br />
<br />
<code sql><br />
SELECT <br />
c.shortname AS CourseID<br />
, cc.name AS Category<br />
, CONCAT(u.firstname ,' ',u.lastname) AS Instructor<br />
<br />
, (SELECT COUNT( ra2.userid ) AS Users2 FROM prefix_role_assignments AS ra2<br />
JOIN prefix_context AS ctx2 ON ra2.contextid = ctx2.id<br />
WHERE ra2.roleid = 5 AND ctx2.instanceid = c.id) AS Students<br />
<br />
, c.startdate AS Course_Start_Date<br />
<br />
, c.visible AS Visible<br />
<br />
, COUNT(l.id) AS Edits<br />
<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time)) - WEEK(FROM_UNIXTIME(c.startdate))<0,1,0)) AS BeforeTerm<br />
<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=0,1,0)) AS Week1<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=1,1,0)) AS Week2<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=2,1,0)) AS Week3<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=3,1,0)) AS Week4<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=4,1,0)) AS Week5<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=5,1,0)) AS Week6<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=6,1,0)) AS Week7<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=7,1,0)) AS Week8<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=8,1,0)) AS Week9<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=9,1,0)) AS Week10<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=10,1,0)) AS Week11<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=11,1,0)) AS Week12<br />
<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))>=12,1,0)) AS AfterTerm<br />
<br />
, CONCAT('<a target="_new" href="%%WWWROOT%%/report/log/index.php',CHAR(63),'chooselog=1&showusers=1&showcourses=0&id=',c.id,'&user=',u.id,'&date=0&modid=&modaction=&logformat=showashtml','">','Logs','</a>') AS Link<br />
<br />
FROM prefix_user AS u<br />
JOIN prefix_role_assignments AS ra ON u.id = ra.userid<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
JOIN prefix_course_categories as cc ON c.category = cc.id<br />
<br />
LEFT JOIN prefix_log AS l ON l.userid = u.id AND l.course = c.id AND l.action NOT LIKE "view%"<br />
<br />
WHERE ra.roleid =3<br />
AND ctx.instanceid = c.id<br />
AND c.shortname LIKE :course<br />
AND u.lastname LIKE :last_name<br />
<br />
GROUP BY u.idnumber, c.id<br />
HAVING students > 0<br />
ORDER BY c.shortname<br />
</code><br />
<br />
'''Note''': Post-2.7 log version:<br />
<br />
<code sql><br />
SELECT <br />
c.shortname AS CourseID<br />
, cc.name AS Category<br />
, CONCAT(u.firstname ,' ',u.lastname) AS Instructor<br />
<br />
, (SELECT COUNT( ra2.userid ) AS Users2 FROM prefix_role_assignments AS ra2<br />
JOIN prefix_context AS ctx2 ON ra2.contextid = ctx2.id<br />
WHERE ra2.roleid = 5 AND ctx2.instanceid = c.id) AS Students<br />
<br />
, FROM_UNIXTIME(c.startdate) AS Course_Start_Date<br />
<br />
, c.visible AS Visible<br />
<br />
, COUNT(DISTINCT l.id) AS Edits<br />
<br />
, COUNT(DISTINCT IF((l.timecreated-c.startdate)<0,l.id,NULL)) AS 'Before Term'<br />
<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=0,l.id,NULL)) AS 'Week 1'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=1,l.id,NULL)) AS 'Week 2'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=2,l.id,NULL)) AS 'Week 3'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=3,l.id,NULL)) AS 'Week 4'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=4,l.id,NULL)) AS 'Week 5'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=5,l.id,NULL)) AS 'Week 6'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=6,l.id,NULL)) AS 'Week 7'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=7,l.id,NULL)) AS 'Week 8'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=8,l.id,NULL)) AS 'Week 9'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=9,l.id,NULL)) AS 'Week 10'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=10,l.id,NULL)) AS 'Week 11'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=11,l.id,NULL)) AS 'Week 12'<br />
<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))>=12,l.id,NULL)) AS 'After Term'<br />
<br />
, CONCAT('<a target="_new" href="%%WWWROOT%%/report/log/index.php',CHAR(63),'chooselog=1&showusers=1&showcourses=0&id=',c.id,'&user=',u.id,'&date=0&modid=&modaction=&logformat=showashtml','">','Logs','</a>') AS Link<br />
<br />
FROM prefix_user AS u<br />
LEFT JOIN prefix_role_assignments AS ra ON u.id = ra.userid<br />
LEFT JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
LEFT JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
LEFT JOIN prefix_course_categories as cc ON c.category = cc.id<br />
<br />
LEFT JOIN prefix_logstore_standard_log AS l ON l.userid = u.id AND l.courseid = c.id AND l.crud IN ('c','u')<br />
<br />
WHERE ra.roleid =3<br />
AND ctx.instanceid = c.id<br />
AND c.shortname LIKE '%OL-%'<br />
AND cc.idnumber LIKE '%current%'<br />
<br />
GROUP BY u.idnumber, c.id<br />
#HAVING students > 0<br />
ORDER BY RIGHT(c.shortname,2), c.shortname<br />
</code><br />
<br />
===Weekly Student Online Participation===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
Displays participation of students in the current course by week, including pre-term and post-term edits. An edit is defined as a change to the course, such as a discussion post, the submission of an assignment, or the completion of a quiz, as well as alterations to course content such as database entries (if permitted).<br />
<br />
Links to three other reports are also provided:<br />
<br />
* Logs: complete log entries for the student in the course, organized by date<br />
* Activity Outline: the "Outline Report" from the User Activity Reports, summarizing the student's activity in the course, organized by course content<br />
* Consolidated Activity Report: the "Complete Report" from the User Activity Reports, detailing the student's activity in the course, organized by course content (includes text of forum posts)<br />
<br />
'''Note''': This should be defined as a "Global" report (visible from within all courses). At our institution, our terms are 12 weeks long. You would want to insert additional "SUM" lines for longer terms, or remove lines for shorter terms. We pull advisor names into student user profiles as part of our configuration. These lines are present in the code below, but are commented out, as they are very specific to your Moodle configuration.<br />
<br />
'''Note''': This version of the report uses legacy (pre-2.7) logs. See below for a post-2.7 Standard Logs version.<br />
<br />
<code sql><br />
SELECT <br />
u.lastname AS 'Last Name'<br />
, u.firstname AS 'First Name'<br />
, COUNT(l.id) AS 'Edits'<br />
<br />
, SUM(IF((l.time-c.startdate)/7<0,1,0)) AS 'Before Term'<br />
<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=0,1,0)) AS 'Week 1'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=1,1,0)) AS 'Week 2'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=2,1,0)) AS 'Week 3'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=3,1,0)) AS 'Week 4'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=4,1,0)) AS 'Week 5'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=5,1,0)) AS 'Week 6'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=6,1,0)) AS 'Week 7'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=7,1,0)) AS 'Week 8'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=8,1,0)) AS 'Week 9'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=9,1,0)) AS 'Week 10'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=10,1,0)) AS 'Week 11'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=11,1,0)) AS 'Week 12'<br />
<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))>=15,1,0)) AS 'After Term'<br />
<br />
, CONCAT('<a target="_blank" href="%%WWWROOT%%/report/log/index.php',CHAR(63),'chooselog=1&showusers=1&showcourses=0&id=',c.id,'&user=',u.id,'&date=0&modid=&modaction=&logformat=showashtml','">','Logs','</a>') AS 'Logs'<br />
<br />
, CONCAT('<a target="_blank" href="%%WWWROOT%%/report/outline/user.php',CHAR(63),'id=',u.id,'&course=',c.id,'&mode=outline">','Outline','</a>') AS 'Activity Outline'<br />
<br />
, CONCAT('<a target="_blank" href="%%WWWROOT%%/report/outline/user.php',CHAR(63),'id=',u.id,'&course=',c.id,'&mode=complete">','Activity','</a>') AS 'Consolidated Activity'<br />
<br />
FROM prefix_user AS u<br />
JOIN prefix_role_assignments AS ra ON u.id = ra.userid<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
JOIN prefix_course_categories as cc ON c.category = cc.id<br />
<br />
LEFT JOIN prefix_log AS l ON l.userid = u.id AND l.course = c.id AND l.action NOT LIKE "view%"<br />
<br />
WHERE ra.roleid =5<br />
AND ctx.instanceid = c.id<br />
<br />
AND c.id = %%COURSEID%%<br />
<br />
GROUP BY u.idnumber<br />
<br />
ORDER BY u.lastname, u.firstname<br />
</code><br />
<br />
'''Note''': Post-2.7 (Standard Logs) version<br />
<br />
<code sql><br />
SELECT <br />
u.lastname AS 'Last Name'<br />
, u.firstname AS 'First Name'<br />
, COUNT(l.id) AS 'Edits'<br />
<br />
, COUNT(DISTINCT IF((l.timecreated-c.startdate)<0,l.id,NULL)) AS 'Before Term'<br />
<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=0,l.id,NULL)) AS 'Week 1'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=1,l.id,NULL)) AS 'Week 2'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=2,l.id,NULL)) AS 'Week 3'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=3,l.id,NULL)) AS 'Week 4'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=4,l.id,NULL)) AS 'Week 5'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=5,l.id,NULL)) AS 'Week 6'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=6,l.id,NULL)) AS 'Week 7'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=7,l.id,NULL)) AS 'Week 8'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=8,l.id,NULL)) AS 'Week 9'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=9,l.id,NULL)) AS 'Week 10'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=10,l.id,NULL)) AS 'Week 11'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=11,l.id,NULL)) AS 'Week 12'<br />
<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))>=12,l.id,NULL)) AS 'After Term'<br />
<br />
# Our institution stores academic advisor names and emails in custom profile fields<br />
#, CONCAT('<a href="mailto:',uce.data,'">',uid.data, '</a>') AS 'Academic Advisor'<br />
<br />
, CONCAT('<a target="_blank" href="%%WWWROOT%%/report/log/index.php',CHAR(63),'chooselog=1&showusers=1&showcourses=0&id=',c.id,'&user=',u.id,'&date=0&modid=&modaction=&logformat=showashtml','">','Logs','</a>') AS 'Logs'<br />
<br />
, CONCAT('<a target="_blank" href="%%WWWROOT%%/report/outline/user.php',CHAR(63),'id=',u.id,'&course=',c.id,'&mode=outline">','Outline','</a>') AS 'Activity Outline'<br />
<br />
, CONCAT('<a target="_blank" href="%%WWWROOT%%/report/outline/user.php',CHAR(63),'id=',u.id,'&course=',c.id,'&mode=complete">','Activity','</a>') AS 'Consolidated Activity'<br />
<br />
, CONCAT('<a target="_blank" href="%%WWWROOT%%/mod/forum/user.php',CHAR(63),'id=',u.id,'&course=',c.id,'">','Posts','</a>') AS 'Posts'<br />
<br />
FROM prefix_user AS u<br />
JOIN prefix_role_assignments AS ra ON u.id = ra.userid<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
JOIN prefix_course_categories as cc ON c.category = cc.id<br />
<br />
# student academic coach - you can include custom profile field data with these methods<br />
# LEFT JOIN prefix_user_info_data as uid ON u.id = uid.userid AND uid.fieldid = '2'<br />
# student academic coach email<br />
# LEFT JOIN prefix_user_info_data as uce on u.id = uce.userid AND uce.fieldid = '6'<br />
<br />
LEFT JOIN prefix_logstore_standard_log AS l ON l.userid = u.id AND l.courseid = c.id AND l.crud IN ('c','u')<br />
<br />
WHERE ra.roleid =5<br />
AND ctx.instanceid = c.id<br />
<br />
AND c.id = %%COURSEID%%<br />
<br />
GROUP BY u.idnumber<br />
<br />
ORDER BY u.lastname, u.firstname<br />
</code><br />
<br />
===My Weekly Online Participation===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
Displays participation of the '''current user''' in the '''current course''' by week, including pre-term and post-term submissions/edits. A submission/edit is defined as a change to the course, such as a discussion post, the submission of an assignment, or the completion of a quiz, as well as alterations to course content such as database entries or new course activities or resources (if permitted).<br />
<br />
This report uses Standard Logs (post 2.7).<br />
<br />
<code sql><br />
SELECT <br />
<br />
l.component AS 'activity'<br />
<br />
, COUNT(DISTINCT IF((l.timecreated-c.startdate)<0,l.id,NULL)) AS 'Before Term'<br />
<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=0,l.id,NULL)) AS 'Week 1'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=1,l.id,NULL)) AS 'Week 2'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=2,l.id,NULL)) AS 'Week 3'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=3,l.id,NULL)) AS 'Week 4'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=4,l.id,NULL)) AS 'Week 5'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=5,l.id,NULL)) AS 'Week 6'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=6,l.id,NULL)) AS 'Week 7'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=7,l.id,NULL)) AS 'Week 8'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=8,l.id,NULL)) AS 'Week 9'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=9,l.id,NULL)) AS 'Week 10'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=10,l.id,NULL)) AS 'Week 11'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=11,l.id,NULL)) AS 'Week 12'<br />
<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))>=12,l.id,NULL)) AS 'After Term'<br />
<br />
, COUNT(l.id) AS 'Total'<br />
<br />
FROM prefix_user AS u<br />
JOIN prefix_role_assignments AS ra ON u.id = ra.userid<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
JOIN prefix_course_categories as cc ON c.category = cc.id<br />
<br />
LEFT JOIN prefix_logstore_standard_log AS l ON l.userid = u.id AND l.courseid = c.id AND l.crud IN ('c','u')<br />
<br />
WHERE 1<br />
AND ctx.instanceid = c.id<br />
<br />
AND c.id = %%COURSEID%%<br />
AND u.id = %%USERID%%<br />
<br />
GROUP BY l.component<br />
<br />
ORDER BY l.component<br />
</code><br />
<br />
===Faculty/Student Interactions===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
Returns a count of instructor and other-student responses to student activity for the specified time period. This report can help indicate whether students' comments are being responded to, as well as summarizing post activity by students during the specified time.<br />
<br />
'''Note''': This version of the report uses legacy (pre-2.7) logs. See below for the post-2.7 Standard Logs version.<br />
<br />
'''Note''': This should be defined as a "Global" report (visible from within all courses). <br />
<br />
'''Note''': This report can take a long time to run. <br />
<br />
<br />
<code sql><br />
SELECT <br />
<br />
# Identify student<br />
CONCAT('<a target="_blank" href="%%WWWROOT%%/message/index.php?id=' , allstu.id , '">' , allstu.firstname , ' ' , allstu.lastname , '</a>' ) AS 'Student - click to send message'<br />
<br />
, IF((COUNT(DISTINCT IF(fps.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fps.id,NULL) )>0) OR (COUNT(DISTINCT IF(asb.timemodified > (UNIX_TIMESTAMP() - (7*24*60*60)),asb.id,NULL))>0) OR (SELECT COUNT(DISTINCT mfs.id) FROM prefix_message AS mfs WHERE mfs.useridfrom = allstu.id AND mfs.useridto = instr.id AND mfs.timecreated > (UNIX_TIMESTAMP() - (7*24*60*60))),'YES','NO') AS 'Student Participated This week'<br />
<br />
, IF((COUNT(DISTINCT IF(fpi.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpi.id,NULL) )>0) OR (COUNT(DISTINCT IF(asg.timemodified > (UNIX_TIMESTAMP() - (7*24*60*60)),asg.id,NULL))>0) OR (SELECT COUNT(DISTINCT mts.id) FROM prefix_message AS mts WHERE mts.useridfrom = instr.id AND mts.useridto = allstu.id AND mts.timecreated > (UNIX_TIMESTAMP() - (7*24*60*60))),'YES','NO') AS 'Student Contacted This week'<br />
<br />
## Only posts within last 7 days<br />
<br />
# Count posts by student<br />
, COUNT(DISTINCT IF(fps.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fps.id,NULL)) AS 'Forum Stu Posts - 7 days'<br />
<br />
# Count replies to student posts by instructors<br />
, COUNT(DISTINCT IF(fpi.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpi.id,NULL) ) AS 'Forum Instr Replies - 7 days'<br />
<br />
# using link back to student posts on replies, get unique student IDs responded<br />
, COUNT(DISTINCT IF(fpsr.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpsr.id,NULL)) - COUNT(DISTINCT IF(fpi.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpi.id,NULL) ) AS 'Forum Stu Replies - 7 days'<br />
<br />
# all replies<br />
, COUNT(DISTINCT IF(fpsr.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpsr.id,NULL)) AS 'Forum All Replies - 7 days'<br />
<br />
# add in count of graded assignments - 7 days<br />
, COUNT(DISTINCT IF(asb.timemodified > (UNIX_TIMESTAMP() - (7*24*60*60)),asb.id,NULL)) AS 'Assign Submit - 7 days'<br />
, COUNT(DISTINCT IF(asg.timemodified > (UNIX_TIMESTAMP() - (7*24*60*60)),asg.id,NULL)) AS 'Assign Grades - 7 days'<br />
<br />
# Messages between students and instructors - 7 days<br />
, (SELECT COUNT(DISTINCT mfs.id) FROM prefix_message AS mfs WHERE mfs.useridfrom = allstu.id AND mfs.useridto = instr.id AND mfs.timecreated > (UNIX_TIMESTAMP() - (7*24*60*60))) AS 'Msg Stu to Instr - 7 days'<br />
, (SELECT COUNT(DISTINCT mts.id) FROM prefix_message AS mts WHERE mts.useridfrom = instr.id AND mts.useridto = allstu.id AND mts.timecreated > (UNIX_TIMESTAMP() - (7*24*60*60))) AS 'Msg Instr to Stu - 7 days'<br />
<br />
## All posts in course so far<br />
# Count posts by student<br />
, COUNT(DISTINCT fps.id) AS 'Forum Stu Posts - to date'<br />
<br />
# Count replies to student posts by instructors<br />
, COUNT(DISTINCT fpi.id) AS 'Forum Instr Replies - to date'<br />
<br />
# using link back to student posts on replies, get unique student IDs responded<br />
, COUNT(DISTINCT fpsr.id) - COUNT(DISTINCT fpi.id) AS 'Forum Stu Replies - to date'<br />
<br />
# all replies<br />
, COUNT(DISTINCT fpsr.id) AS 'Forum All Replies - to date'<br />
<br />
# add in count of graded assignments - whole course<br />
, COUNT(DISTINCT asb.id) AS 'Assign Submit - to date'<br />
, COUNT(DISTINCT asg.id) AS 'Assign Grades - to date'<br />
<br />
# Messages between students and instructors - to date<br />
, (SELECT COUNT(DISTINCT mfs.id) FROM prefix_message AS mfs WHERE mfs.useridfrom = allstu.id AND mfs.useridto = instr.id ) AS 'Msg Stu to Instr - to date'<br />
, (SELECT COUNT(DISTINCT mts.id) FROM prefix_message AS mts WHERE mts.useridfrom = instr.id AND mts.useridto = allstu.id) AS 'Msg Instr to Stu - to date'<br />
<br />
## JOINS<br />
<br />
# Start by getting all the students in the course<br />
FROM prefix_user AS allstu <br />
JOIN prefix_role_assignments AS ras ON allstu.id = ras.userid AND ras.roleid = 5<br />
JOIN prefix_context AS ctx ON ras.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
JOIN prefix_course_categories as cc ON c.category = cc.id<br />
<br />
# Now we get the forums and forum discussions from this course only<br />
LEFT JOIN prefix_forum AS frm ON frm.course = c.id AND c.id = %%COURSEID%%<br />
LEFT JOIN prefix_forum_discussions AS fd ON fd.course = %%COURSEID%% AND fd.forum = frm.id<br />
<br />
# These are forum discussion posts just by students within specified time<br />
LEFT JOIN prefix_forum_posts AS fps ON fps.userid = allstu.id AND fps.discussion = fd.id<br />
<br />
# Separately, we connect the instructors of the courses<br />
# We can use the context we have already gotten for the students<br />
LEFT JOIN prefix_role_assignments AS rai ON rai.contextid = ctx.id<br />
LEFT JOIN prefix_user AS instr ON instr.id = rai.userid AND rai.roleid =3<br />
<br />
# Now we will connect to posts by instructors that are replies to student posts<br />
# This is a left join, because we don't want to eliminate any students from the list<br />
LEFT JOIN prefix_forum_posts AS fpi ON fpi.discussion = fd.id AND fpi.userid = instr.id AND fpi.parent = fps.id<br />
<br />
# To get identities of only those students who were replied to:<br />
# Connect from instr replies back up to parent posts by students again<br />
# This has to be a LEFT JOIN, we know these posts exist but don't eliminate non-responded students<br />
LEFT JOIN prefix_forum_posts AS fpir ON fpir.id = fpi.parent<br />
<br />
# We also want to know if students are replying to one another<br />
# These are posts that are replies to student posts<br />
# Again, a left join<br />
LEFT JOIN prefix_forum_posts AS fpsr ON fpsr.discussion = fd.id AND fpsr.parent = fps.id<br />
<br />
# get the activity modules<br />
LEFT JOIN prefix_course_modules AS cm ON c.id = cm.course<br />
<br />
# get the assignments<br />
LEFT JOIN prefix_assign AS a ON cm.instance = a.id<br />
LEFT JOIN prefix_assign_submission AS asb ON a.id = asb.assignment AND asb.userid=allstu.id <br />
LEFT JOIN prefix_assign_grades AS asg ON asg.assignment = a.id AND asg.userid = allstu.id AND asg.assignment = asb.assignment <br />
<br />
# We care about messages that involve both the instructor and students of this course<br />
# messages from instructor to students:<br />
# LEFT JOIN prefix_message AS mts ON mts.useridfrom = instr.id AND mts.useridto = allstu.id<br />
# LEFT JOIN prefix_message AS mfs ON mfs.useridfrom = instr.id AND mfs.useridto = allstu.id<br />
<br />
WHERE <br />
c.id = %%COURSEID%% <br />
<br />
# GROUP BY c.shortname , allstu.id<br />
GROUP BY allstu.id<br />
<br />
ORDER BY allstu.lastname<br />
</code><br />
<br />
'''Note''': Post-2.7 Standard Logs version<br />
<br />
<code sql><br />
SELECT <br />
<br />
# Identify student<br />
CONCAT('<a target="_blank" href="%%WWWROOT%%/message/index.php?id=' , allstu.id , '">' , allstu.firstname , ' ' , allstu.lastname , '</a>' ) AS 'Student - click to send message'<br />
<br />
, IF((COUNT(DISTINCT IF(fps.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fps.id,NULL) )>0) OR (COUNT(DISTINCT IF(asb.timemodified > (UNIX_TIMESTAMP() - (7*24*60*60)),asb.id,NULL))>0) OR (SELECT COUNT(DISTINCT mfs.id) FROM prefix_message AS mfs WHERE mfs.useridfrom = allstu.id AND mfs.useridto = instr.id AND mfs.timecreated > (UNIX_TIMESTAMP() - (7*24*60*60))),'YES','NO') AS 'Student Participated This week'<br />
<br />
, IF((COUNT(DISTINCT IF(fpi.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpi.id,NULL) )>0) OR (COUNT(DISTINCT IF(asg.timemodified > (UNIX_TIMESTAMP() - (7*24*60*60)),asg.id,NULL))>0) OR (SELECT COUNT(DISTINCT mts.id) FROM prefix_message AS mts WHERE mts.useridfrom = instr.id AND mts.useridto = allstu.id AND mts.timecreated > (UNIX_TIMESTAMP() - (7*24*60*60))),'YES','NO') AS 'Student Contacted This week'<br />
<br />
## Only posts within last 7 days<br />
<br />
# Count posts by student<br />
, COUNT(DISTINCT IF(fps.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fps.id,NULL)) AS 'Forum Stu Posts - 7 days'<br />
<br />
# Count replies to student posts by instructors<br />
, COUNT(DISTINCT IF(fpi.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpi.id,NULL) ) AS 'Forum Instr Replies - 7 days'<br />
<br />
# using link back to student posts on replies, get unique student IDs responded<br />
, COUNT(DISTINCT IF(fpsr.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpsr.id,NULL)) - COUNT(DISTINCT IF(fpi.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpi.id,NULL) ) AS 'Forum Stu Replies - 7 days'<br />
<br />
# all replies<br />
, COUNT(DISTINCT IF(fpsr.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpsr.id,NULL)) AS 'Forum All Replies - 7 days'<br />
<br />
# add in count of graded assignments - 7 days<br />
, COUNT(DISTINCT IF(asb.timemodified > (UNIX_TIMESTAMP() - (7*24*60*60)),asb.id,NULL)) AS 'Assign Submit - 7 days'<br />
, COUNT(DISTINCT IF(asg.timemodified > (UNIX_TIMESTAMP() - (7*24*60*60)),asg.id,NULL)) AS 'Assign Grades - 7 days'<br />
<br />
# Messages between students and instructors - 7 days<br />
, (SELECT COUNT(DISTINCT mfs.id) FROM prefix_message AS mfs WHERE mfs.useridfrom = allstu.id AND mfs.useridto = instr.id AND mfs.timecreated > (UNIX_TIMESTAMP() - (7*24*60*60))) AS 'Msg Stu to Instr - 7 days'<br />
, (SELECT COUNT(DISTINCT mts.id) FROM prefix_message AS mts WHERE mts.useridfrom = instr.id AND mts.useridto = allstu.id AND mts.timecreated > (UNIX_TIMESTAMP() - (7*24*60*60))) AS 'Msg Instr to Stu - 7 days'<br />
<br />
## All posts in course so far<br />
# Count posts by student<br />
, COUNT(DISTINCT fps.id) AS 'Forum Stu Posts - to date'<br />
<br />
# Count replies to student posts by instructors<br />
, COUNT(DISTINCT fpi.id) AS 'Forum Instr Replies - to date'<br />
<br />
# using link back to student posts on replies, get unique student IDs responded<br />
, COUNT(DISTINCT fpsr.id) - COUNT(DISTINCT fpi.id) AS 'Forum Stu Replies - to date'<br />
<br />
# all replies<br />
, COUNT(DISTINCT fpsr.id) AS 'Forum All Replies - to date'<br />
<br />
# add in count of graded assignments - whole course<br />
, COUNT(DISTINCT asb.id) AS 'Assign Submit - to date'<br />
, COUNT(DISTINCT asg.id) AS 'Assign Grades - to date'<br />
<br />
# Messages between students and instructors - to date<br />
, (SELECT COUNT(DISTINCT mfs.id) FROM prefix_message AS mfs WHERE mfs.useridfrom = allstu.id AND mfs.useridto = instr.id ) AS 'Msg Stu to Instr - to date'<br />
, (SELECT COUNT(DISTINCT mts.id) FROM prefix_message AS mts WHERE mts.useridfrom = instr.id AND mts.useridto = allstu.id) AS 'Msg Instr to Stu - to date'<br />
<br />
## JOINS<br />
<br />
# Start by getting all the students in the course<br />
FROM prefix_user AS allstu <br />
JOIN prefix_role_assignments AS ras ON allstu.id = ras.userid AND ras.roleid = 5<br />
JOIN prefix_context AS ctx ON ras.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
JOIN prefix_course_categories as cc ON c.category = cc.id<br />
<br />
# Now we get the forums and forum discussions from this course only<br />
JOIN prefix_forum AS frm ON frm.course = c.id AND c.id = %%COURSEID%%<br />
JOIN prefix_forum_discussions AS fd ON fd.course = %%COURSEID%% AND fd.forum = frm.id<br />
<br />
# These are forum discussion posts just by students within specified time<br />
LEFT JOIN prefix_forum_posts AS fps ON fps.userid = allstu.id AND fps.discussion = fd.id<br />
<br />
# Separately, we connect the instructors of the courses<br />
# We can use the context we have already gotten for the students<br />
JOIN prefix_role_assignments AS rai ON rai.contextid = ctx.id<br />
JOIN prefix_user AS instr ON instr.id = rai.userid AND rai.roleid =3<br />
<br />
# Now we will connect to posts by instructors that are replies to student posts<br />
# This is a left join, because we don't want to eliminate any students from the list<br />
LEFT JOIN prefix_forum_posts AS fpi ON fpi.discussion = fd.id AND fpi.userid = instr.id AND fpi.parent = fps.id<br />
<br />
# To get identities of only those students who were replied to:<br />
# Connect from instr replies back up to parent posts by students again<br />
# This has to be a LEFT JOIN, we know these posts exist but don't eliminate non-responded students<br />
LEFT JOIN prefix_forum_posts AS fpir ON fpir.id = fpi.parent<br />
<br />
# We also want to know if students are replying to one another<br />
# These are posts that are replies to student posts<br />
# Again, a left join<br />
LEFT JOIN prefix_forum_posts AS fpsr ON fpsr.discussion = fd.id AND fpsr.parent = fps.id<br />
<br />
# get the activity modules<br />
JOIN prefix_course_modules AS cm ON c.id = cm.course<br />
<br />
# get the assignments<br />
JOIN prefix_assign AS a ON cm.instance = a.id<br />
LEFT JOIN prefix_assign_submission AS asb ON a.id = asb.assignment AND asb.userid=allstu.id <br />
LEFT JOIN prefix_assign_grades AS asg ON asg.assignment = a.id AND asg.userid = allstu.id AND asg.assignment = asb.assignment <br />
<br />
WHERE <br />
c.id = %%COURSEID%% <br />
<br />
# GROUP BY c.shortname , allstu.id<br />
GROUP BY allstu.id<br />
<br />
ORDER BY allstu.lastname<br />
</code><br />
<br />
===Student Resource Usage===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
Displays usage by students of all activities and resources in the current course by activity. Only activities and sections which are visible in the course are included. This version requires the new "Standard Logs" from Moodle 2.7+.<br />
<br />
'''Note''': This should be defined as a "Global" report (visible from within all courses). <br />
<br />
<code sql><br />
SELECT <br />
cs.section AS 'Week'<br />
, cs.name AS 'Section Name'<br />
, m.name AS 'item type'<br />
<br />
, CONCAT(<br />
COALESCE(a.name, ''), <br />
COALESCE(b.name,''), <br />
COALESCE(cert.name,''), <br />
COALESCE(chat.name,''), <br />
COALESCE(choice.name,''), <br />
COALESCE(data.name,''), <br />
COALESCE(feedback.name,''), <br />
COALESCE(folder.name,''), <br />
COALESCE(forum.name,''), <br />
COALESCE(glossary.name,''), <br />
COALESCE(imscp.name,''), <br />
COALESCE(lesson.name,''), <br />
COALESCE(p.name,''),<br />
COALESCE(questionnaire.name,''), <br />
COALESCE(quiz.name,''), <br />
COALESCE(cr.name,''), <br />
COALESCE(scorm.name,''), <br />
COALESCE(survey.name,''), <br />
COALESCE(url.name,''), <br />
COALESCE(wiki.name,''), <br />
COALESCE(workshop.name,''), <br />
COALESCE(kalvidassign.name,''), <br />
COALESCE(attendance.name,''), <br />
COALESCE(checklist.name,''), <br />
COALESCE(flashcard.name,''), <br />
COALESCE(lti.name,''), <br />
COALESCE(oublog.name,''), <br />
COALESCE(ouwiki.name,''), <br />
COALESCE(subpage.name,''), <br />
COALESCE(journal.name,''), <br />
COALESCE(lightboxgallery.name,''), <br />
COALESCE(elluminate.name,''), <br />
COALESCE(adaptivequiz.name,''), <br />
COALESCE(hotpot.name,''), <br />
COALESCE(wiziq.name,''), <br />
COALESCE(turnitintooltwo.name,''), <br />
COALESCE(kvr.name,'')<br />
) AS 'item name'<br />
<br />
<br />
, SUM(IF(l.crud IN ('r'),1,0)) AS 'total views'<br />
, SUM(IF(l.crud IN ('c','u'),1,0)) AS 'total submissions'<br />
, COUNT(DISTINCT IF(l.crud IN ('r'),u.id,NULL)) AS 'count of students who viewed'<br />
, COUNT(DISTINCT IF(l.crud IN ('c','u'),u.id,NULL)) AS 'count of students who submitted'<br />
<br />
FROM prefix_user AS u<br />
JOIN prefix_role_assignments AS ra ON u.id = ra.userid<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
JOIN prefix_course_categories as cc ON c.category = cc.id<br />
<br />
JOIN prefix_course_sections AS cs ON cs.course = c.id AND cs.section <= 14 #AND cs.section > 0<br />
LEFT JOIN prefix_course_modules AS cm ON cm.course = c.id AND cm.section = cs.id<br />
JOIN prefix_modules AS m ON m.id = cm.module AND m.name NOT LIKE 'label'<br />
<br />
LEFT JOIN prefix_assign AS a ON a.id = cm.instance AND m.name = 'assign'<br />
LEFT JOIN prefix_book AS b ON b.id = cm.instance AND m.name = 'book'<br />
LEFT JOIN prefix_certificate AS cert ON cert.id = cm.instance AND m.name = 'certificate'<br />
LEFT JOIN prefix_chat AS chat ON chat.id = cm.instance AND m.name = 'chat'<br />
LEFT JOIN prefix_choice AS choice ON choice.id = cm.instance AND m.name = 'choice'<br />
LEFT JOIN prefix_data AS data ON data.id = cm.instance AND m.name = 'data'<br />
LEFT JOIN prefix_feedback AS feedback ON feedback.id = cm.instance AND m.name = 'feedback'<br />
LEFT JOIN prefix_folder AS folder ON folder.id = cm.instance AND m.name = 'folder'<br />
LEFT JOIN prefix_forum AS forum ON forum.id = cm.instance AND m.name = 'forum'<br />
LEFT JOIN prefix_glossary AS glossary ON glossary.id = cm.instance AND m.name = 'glossary'<br />
LEFT JOIN prefix_imscp AS imscp ON imscp.id = cm.instance AND m.name = 'imscp'<br />
LEFT JOIN prefix_lesson AS lesson ON lesson.id = cm.instance AND m.name = 'lesson'<br />
LEFT JOIN prefix_page AS p ON p.id = cm.instance AND m.name = 'page'<br />
LEFT JOIN prefix_questionnaire AS questionnaire ON questionnaire.id = cm.instance AND m.name = 'questionnaire'<br />
LEFT JOIN prefix_quiz AS quiz ON quiz.id = cm.instance AND m.name = 'quiz'<br />
LEFT JOIN prefix_resource AS cr ON cr.id = cm.instance AND m.name = 'resource'<br />
LEFT JOIN prefix_scorm AS scorm ON scorm.id = cm.instance AND m.name = 'scorm'<br />
LEFT JOIN prefix_survey AS survey ON survey.id = cm.instance AND m.name = 'survey'<br />
LEFT JOIN prefix_url AS url ON url.id = cm.instance AND m.name = 'url'<br />
LEFT JOIN prefix_wiki AS wiki ON wiki.id = cm.instance AND m.name = 'wiki'<br />
LEFT JOIN prefix_workshop AS workshop ON workshop.id = cm.instance AND m.name = 'workshop'<br />
LEFT JOIN prefix_kalvidassign AS kalvidassign ON kalvidassign.id = cm.instance AND m.name = 'kalvidassign'<br />
LEFT JOIN prefix_kalvidres AS kvr ON kvr.id = cm.instance AND m.name = 'kalvidres'<br />
LEFT JOIN prefix_attendance AS attendance ON attendance.id = cm.instance AND m.name = 'attendance'<br />
LEFT JOIN prefix_checklist AS checklist ON checklist.id = cm.instance AND m.name = 'checklist'<br />
LEFT JOIN prefix_flashcard AS flashcard ON flashcard.id = cm.instance AND m.name = 'flashcard'<br />
LEFT JOIN prefix_lti AS lti ON lti.id = cm.instance AND m.name = 'lti'<br />
LEFT JOIN prefix_oublog AS oublog ON oublog.id = cm.instance AND m.name = 'oublog'<br />
LEFT JOIN prefix_ouwiki AS ouwiki ON ouwiki.id = cm.instance AND m.name = 'ouwiki'<br />
LEFT JOIN prefix_subpage AS subpage ON subpage.id = cm.instance AND m.name = 'subpage'<br />
LEFT JOIN prefix_journal AS journal ON journal.id = cm.instance AND m.name = 'journal'<br />
LEFT JOIN prefix_lightboxgallery AS lightboxgallery ON lightboxgallery.id = cm.instance AND m.name = 'lightboxgallery'<br />
LEFT JOIN prefix_elluminate AS elluminate ON elluminate.id = cm.instance AND m.name = 'elluminate'<br />
LEFT JOIN prefix_adaptivequiz AS adaptivequiz ON adaptivequiz.id = cm.instance AND m.name = 'adaptivequiz'<br />
LEFT JOIN prefix_hotpot AS hotpot ON hotpot.id = cm.instance AND m.name = 'hotpot'<br />
LEFT JOIN prefix_wiziq AS wiziq ON wiziq.id = cm.instance AND m.name = 'wiziq'<br />
LEFT JOIN prefix_turnitintooltwo AS turnitintooltwo ON turnitintooltwo.id = cm.instance AND m.name = 'turnitintooltwo'<br />
<br />
LEFT JOIN prefix_logstore_standard_log AS l ON l.userid = u.id AND l.courseid = c.id<br />
<br />
<br />
WHERE ra.roleid =5<br />
AND ctx.instanceid = c.id<br />
AND cs.visible = 1<br />
AND cm.visible = 1<br />
<br />
AND c.id = %%COURSEID%%<br />
<br />
GROUP BY cm.id<br />
<br />
ORDER BY cs.section<br />
</code><br />
<br />
===Module activity (Hits) between dates===<br />
<code sql><br />
SELECT module, COUNT( * ) <br />
FROM prefix_logstore_standard_log AS l<br />
WHERE (FROM_UNIXTIME( l.`timecreated` ) BETWEEN '2018-10-01 00:00:00' AND '2019-09-31 00:00:00')<br />
GROUP BY module<br />
</code><br />
<br />
===Module activity (Instances and Hits) for each academic year===<br />
<code sql><br />
SELECT name<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_logstore_standard_log AS l<br />
WHERE (FROM_UNIXTIME(l.`timecreated`) BETWEEN '2017-10-01 00:00:00' AND '2018-09-31 00:00:00')<br />
AND l.module = m.name AND l.action = 'add'<br />
) AS "Added 2017"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_logstore_standard_log AS l<br />
WHERE (FROM_UNIXTIME(l.`timecreated`) BETWEEN '2017-10-01 00:00:00' AND '2018-09-31 00:00:00')<br />
AND l.module = m.name<br />
) AS "Used 2017"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_logstore_standard_log AS l<br />
WHERE (FROM_UNIXTIME(l.`timecreated`) BETWEEN '2018-10-01 00:00:00' AND '2019-09-31 00:00:00')<br />
AND l.module = m.name AND l.action = 'add'<br />
) AS "Added 2018"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_logstore_standard_log AS l<br />
WHERE (FROM_UNIXTIME(l.`timecreated`) BETWEEN '2018-10-01 00:00:00' AND '2019-09-31 00:00:00')<br />
AND l.module = m.name<br />
) AS "Used 2018"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_logstore_standard_log AS l<br />
WHERE (FROM_UNIXTIME(l.`timecreated`) BETWEEN '2019-10-01 00:00:00' AND '2020-09-31 00:00:00')<br />
AND l.module = m.name AND l.action = 'add'<br />
) AS "Added 2019"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_logstore_standard_log AS l<br />
WHERE (FROM_UNIXTIME(l.`timecreated`) BETWEEN '2019-10-01 00:00:00' AND '2020-09-31 00:00:00')<br />
AND l.module = m.name<br />
) AS "Used 2019"<br />
<br />
FROM mdl_modules AS m<br />
</code><br />
<br />
===Unique user sessions per day and month + graph===<br />
The "graph" column is used when displaying a graph (which needs at least three columns to pick from)<br />
<code sql><br />
SELECT COUNT(DISTINCT userid) AS "Unique User Logins"<br />
,DATE_FORMAT(FROM_UNIXTIME(timecreated), "%y /%m / %d") AS "Year / Month / Day", "Graph" <br />
FROM `mdl_logstore_standard_log` <br />
WHERE action LIKE 'loggedin'<br />
#AND timecreated > UNIX_TIMESTAMP('2015-01-01 00:00:00') # optional start date<br />
#AND timecreated <= UNIX_TIMESTAMP('2015-01-31 23:59:00') # optional end date<br />
GROUP BY MONTH(FROM_UNIXTIME(timecreated)), DAY(FROM_UNIXTIME(timecreated))<br />
ORDER BY MONTH(FROM_UNIXTIME(timecreated)), DAY(FROM_UNIXTIME(timecreated))<br />
</code><br />
<br />
And...<br />
<br />
Counting user's global and unique hits per day + counting individual usage of specific activities and resources (on that day),<br />
<br />
And since I am using phpMyAdmin's "Display Graph" feature (at the bottom of the query's output page), I have scaled down the "User Hits" by 10 to fit the graph. that's it.<br />
<code sql><br />
SELECT DATE_FORMAT(FROM_UNIXTIME(timecreated), "%y-%m-%d") AS "Datez"<br />
,COUNT(DISTINCT userid) AS "Unique Users"<br />
,ROUND(COUNT(*)/10) "User Hits (K)"<br />
,SUM(IF(component='mod_quiz',1,0)) "Quizzes"<br />
,SUM(IF(component='mod_forum' or component='mod_forumng',1,0)) "Forums"<br />
,SUM(IF(component='mod_assign',1,0)) "Assignments"<br />
,SUM(IF(component='mod_oublog',1,0)) "Blogs"<br />
,SUM(IF(component='mod_resource',1,0)) "Files (Resource)"<br />
,SUM(IF(component='mod_url',1,0)) "Links (Resource)"<br />
,SUM(IF(component='mod_page',1,0)) "Pages (Resource)"<br />
<br />
FROM `mdl_logstore_standard_log` <br />
WHERE 1=1<br />
AND timecreated > UNIX_TIMESTAMP('2015-03-01 00:00:00') # optional START DATE<br />
AND timecreated <= UNIX_TIMESTAMP('2015-05-31 23:59:00') # optional END DATE<br />
GROUP BY MONTH(FROM_UNIXTIME(timecreated)), DAY(FROM_UNIXTIME(timecreated))<br />
ORDER BY MONTH(FROM_UNIXTIME(timecreated)), DAY(FROM_UNIXTIME(timecreated))<br />
</code><br />
<br />
===System wide, daily unique user hits for the last 7 days===<br />
<code sql><br />
SELECT<br />
DATE_FORMAT(FROM_UNIXTIME(l.timecreated), '%m%d') 'Day'<br />
,COUNT(DISTINCT l.userid) AS 'Distinct Users Hits'<br />
,COUNT( l.userid) AS 'Users Hits'<br />
<br />
FROM mdl_logstore_standard_log AS l<br />
WHERE l.courseid > 1<br />
AND FROM_UNIXTIME(l.timecreated) >= DATE_SUB(NOW(), INTERVAL 7 DAY)<br />
GROUP BY DAY(FROM_UNIXTIME(timecreated))<br />
</code><br />
<br />
===User detailed activity in course modules===<br />
Considering only several modules: url, resource, forum, quiz, questionnaire.<br />
<br />
<code sql><br />
SELECT u.id, ra.roleid,<br />
CONCAT(u.lastname, ' ', u.firstname) AS 'Student'<br />
,COUNT(l.id) AS 'Actions'<br />
,l.component "Module type"<br />
,l.objectid "Module ID"<br />
,CASE <br />
WHEN l.component = 'mod_url' THEN (SELECT u.name FROM mdl_url AS u WHERE u.id = l.objectid )<br />
WHEN l.component = 'mod_resource' THEN (SELECT r.name FROM mdl_resource AS r WHERE r.id = l.objectid )<br />
WHEN l.component = 'mod_forum' THEN (SELECT f.name FROM mdl_forum AS f WHERE f.id = l.objectid )<br />
WHEN l.component = 'mod_quiz' THEN (SELECT q.name FROM mdl_quiz AS q WHERE q.id = l.objectid )<br />
WHEN l.component = 'mod_questionnaire' THEN (SELECT q.name FROM mdl_questionnaire AS q WHERE q.id = l.objectid )<br />
END AS 'Module name'<br />
<br />
,(SELECT GROUP_CONCAT(g.name) FROM mdl_groups AS g<br />
JOIN mdl_groups_members AS m ON g.id = m.groupid WHERE g.courseid = l.courseid AND m.userid = u.id) "user_groups"<br />
<br />
,(SELECT s.name <br />
FROM mdl_course_modules AS cm <br />
JOIN mdl_course_sections AS s ON s.course = cm.course AND s.id = cm.section <br />
WHERE cm.id = l.contextinstanceid) AS "Section name"<br />
<br />
FROM mdl_logstore_standard_log AS l <br />
JOIN mdl_user AS u ON u.id = l.userid<br />
JOIN mdl_role_assignments AS ra ON ra.userid = l.userid <br />
AND ra.contextid = (SELECT id FROM mdl_context WHERE instanceid = l.courseid AND contextlevel = 50) <br />
WHERE l.courseid = %%COURSEID%%<br />
AND l.component IN ('mod_url', 'mod_resource', 'mod_forum', 'mod_quiz', 'mod_questionnaire') <br />
%%FILTER_STARTTIME:l.timecreated:>%% %%FILTER_ENDTIME:l.timecreated:<%%<br />
<br />
GROUP BY u.id, l.component<br />
ORDER BY u.lastname, u.firstname<br />
</code><br />
<br />
===What teachers and courses considered active?===<br />
This report display several calculations and parameters that help the Online academic training team find teachers that might need more support getting their courses more supporting of online learning pedagogical methodologies. <br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',<br />
course.id,'">',course.fullname,'</a>') AS Course <br />
<br />
#,course.shortname<br />
<br />
,CASE <br />
WHEN course.fullname LIKE '%2012%' THEN '2012'<br />
WHEN course.fullname LIKE '%2013%' THEN '2013' <br />
WHEN course.fullname LIKE '%2014%' THEN '2014'<br />
WHEN course.fullname LIKE '%2015%' THEN '2015'<br />
END AS Year<br />
<br />
,CASE <br />
WHEN course.fullname LIKE '%semester a%' THEN 'Spring semester'<br />
WHEN course.fullname LIKE '%semester b%' THEN 'Fall semester'<br />
WHEN course.fullname LIKE '%semester s%' THEN 'Summer semester'<br />
END AS Semester<br />
<br />
,IF(course.startdate>0, DATE_FORMAT(FROM_UNIXTIME(startdate), '%d-%m-%Y'), 'no date') AS "Course Start Date" <br />
<br />
,(SELECT COUNT( ra.userid ) AS Users<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = course.id<br />
) AS Students<br />
<br />
,(SELECT COUNT( ra.userid ) AS Users<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 4 AND ctx.instanceid = course.id<br />
) AS "Assistant teacher"<br />
<br />
,(SELECT COUNT( ra.userid ) AS Users<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 3 AND ctx.instanceid = course.id<br />
) AS Teachers<br />
<br />
# Uncomment to use the new Moodle 2.8+ logstore<br />
#,(SELECT COUNT(*) FROM mdl_logstore_standard_log AS l WHERE l.courseid = course.id) AS Hits<br />
<br />
#,(SELECT COUNT(*)<br />
#FROM mdl_logstore_standard_log AS l<br />
#JOIN mdl_role_assignments AS ra ON ra.userid= l.userid AND ra.roleid = 5 AND ra.contextid = (SELECT id FROM mdl_context WHERE instanceid = l.courseid AND contextlevel = 50) <br />
#WHERE l.courseid = course.id ) AS "Student HITs"<br />
<br />
#,(SELECT COUNT(*)<br />
#FROM mdl_logstore_standard_log AS l<br />
#JOIN mdl_role_assignments AS ra ON ra.userid= l.userid AND ra.roleid = 3 AND ra.contextid = (SELECT id FROM mdl_context WHERE instanceid = l.courseid AND contextlevel = 50) <br />
#WHERE l.courseid = course.id ) AS "Teacher HITs"<br />
<br />
,(SELECT COUNT(*) FROM mdl_log AS l WHERE l.course = course.id) AS Hits<br />
<br />
,(SELECT COUNT(*)<br />
FROM mdl_log AS l<br />
JOIN mdl_context AS con ON con.instanceid= l.course AND con.contextlevel=50<br />
JOIN mdl_role_assignments AS ra ON ra.contextid= con.id AND ra.userid= l.userid AND ra.roleid = 5 <br />
WHERE l.course = course.id) AS "Students HITs"<br />
<br />
,(SELECT COUNT(*)<br />
FROM mdl_log AS l<br />
JOIN mdl_context AS con ON con.instanceid= l.course AND con.contextlevel=50<br />
JOIN mdl_role_assignments AS ra ON ra.contextid= con.id AND ra.userid= l.userid AND ra.roleid = 3 <br />
WHERE l.course = course.id) AS "Teachers HITs"<br />
<br />
,(SELECT GROUP_CONCAT( CONCAT( u.firstname, " ", u.lastname ) ) <br />
FROM prefix_course c<br />
JOIN prefix_context con ON con.instanceid = c.id<br />
JOIN prefix_role_assignments ra ON con.id = ra.contextid AND con.contextlevel = 50<br />
JOIN prefix_role r ON ra.roleid = r.id<br />
JOIN prefix_user u ON u.id = ra.userid<br />
WHERE r.id = 3 AND c.id = course.id<br />
GROUP BY c.id<br />
) AS Teachers<br />
<br />
,(SELECT COUNT(*) FROM prefix_course_modules cm WHERE cm.course = course.id) Modules<br />
<br />
,(SELECT COUNT(DISTINCT cm.module) FROM prefix_course_modules cm <br />
WHERE cm.course = course.id) UniqueModules<br />
<br />
,(SELECT GROUP_CONCAT(DISTINCT m.name) <br />
FROM prefix_course_modules cm <br />
JOIN mdl_modules as m ON m.id = cm.module<br />
WHERE cm.course = course.id) UniqueModuleNames<br />
<br />
,(SELECT COUNT(*) FROM mdl_course_modules cm JOIN mdl_modules as m ON m.id = cm.module <br />
WHERE cm.course = course.id AND m.name IN ( 'ouwiki', 'wiki') ) "Num Wikis"<br />
<br />
,(SELECT COUNT(*) FROM mdl_course_modules cm JOIN mdl_modules as m ON m.id = cm.module <br />
WHERE cm.course = course.id AND m.name IN ( 'oublog') ) "Num Blogs"<br />
<br />
,(SELECT COUNT(*) FROM mdl_course_modules cm JOIN mdl_modules as m ON m.id = cm.module <br />
WHERE cm.course = course.id AND m.name IN ( 'forum', 'forumng') ) "Num Forums"<br />
<br />
,(SELECT COUNT(*) FROM prefix_course_modules cm JOIN mdl_modules as m ON m.id = cm.module <br />
WHERE cm.course = course.id AND m.name IN ('resource', 'folder', 'url', 'tab', 'file', 'book', 'page') ) Resources<br />
<br />
,(SELECT COUNT(*) FROM prefix_course_modules cm JOIN mdl_modules as m ON m.id = cm.module <br />
WHERE cm.course = course.id AND m.name IN ('forum', 'forumng', 'oublog', 'page', 'file', 'url', 'wiki' , 'ouwiki') ) "Basic Activities"<br />
<br />
,(SELECT COUNT(*) FROM prefix_course_modules cm JOIN mdl_modules as m ON m.id = cm.module <br />
WHERE cm.course = course.id AND m.name IN ('advmindmap', 'assign', 'attendance', 'book', 'choice', 'folder', 'tab', 'glossary', 'questionnaire', 'quiz', 'label' ) ) "Avarage Activities"<br />
<br />
,(SELECT COUNT(*) FROM prefix_course_modules cm JOIN mdl_modules as m ON m.id = cm.module <br />
WHERE cm.course = course.id AND m.name IN ('elluminate', 'game', 'workshop') ) "Advanced Activities"<br />
<br />
FROM prefix_course AS course<br />
<br />
#WHERE course.shortname LIKE '%2015%'<br />
#WHERE 1=1<br />
#%%FILTER_SEARCHTEXT:course.shortname:~%%<br />
<br />
WHERE course.fullname LIKE '%2015%' <br />
<br />
HAVING Modules > 2<br />
ORDER BY UniqueModules DESC<br />
</code><br />
<br />
===Weekly attendance report===<br />
This report display weekly report in format HH:M:SS This MySQL query works together with AttendaceRegister module, and gather Log information from Attendanceregister_log table. <br />
<code sql><br />
SELECT u.username, SEC_TO_TIME (SUM(arsess.duration)) AS weekly_online_attendance, FROM_UNIXTIME (arsess.logout) AS Last_Logout<br />
FROM prefix_attendanceregister_session AS arsess<br />
JOIN prefix_user AS u ON arsess.userid = u.id<br />
<br />
WHERE (((arsess.logout) BETWEEN UNIX_TIMESTAMP(DATE_SUB(CURDATE(), INTERVAL 7 DAY)) AND UNIX_TIMESTAMP(CURDATE())))<br />
<br />
GROUP BY arsess.userid<br />
</code><br />
<br />
===How many distinct users connected to Moodle using the app by month===<br />
https://moodle.org/mod/forum/discuss.php?d=336086#p1354194 by <br />
Iñigo Zendegi Urzelai<br />
<code sql><br />
SELECT <br />
to_char(to_timestamp("timecreated"),'YYYY') as year, <br />
to_char(to_timestamp("timecreated"),'MM') as month, <br />
count(distinct userid) as distinct_users<br />
<br />
FROM mdl_logstore_standard_log m<br />
WHERE m.origin='ws'<br />
GROUP BY to_char(to_timestamp("timecreated"),'YYYY'), to_char(to_timestamp("timecreated"),'MM') <br />
ORDER BY to_char(to_timestamp("timecreated"),'YYYY'), to_char(to_timestamp("timecreated"),'MM');<br />
</code><br />
<br />
==Course Reports==<br />
===Most Active courses===<br />
<code sql><br />
SELECT count(l.userid) AS Views<br />
FROM `mdl_logstore_standard_log` l, `mdl_user` u, `mdl_role_assignments` r<br />
WHERE l.courseid=35<br />
AND l.userid = u.id<br />
AND (l.timecreated > UNIX_TIMESTAMP('2015-01-01 00:00:00') AND l.timecreated <= UNIX_TIMESTAMP('2015-01-31 23:59:59'))AND r.contextid= (<br />
SELECT id<br />
FROM mdl_context<br />
WHERE contextlevel=50 AND instanceid=l.courseid<br />
)<br />
AND r.roleid=5<br />
AND r.userid = u.id<br />
</code><br />
<br />
===Active courses, advanced===<br />
Including: Teacher's name, link to the course, All types of log activities, special YEAR generated field, Activities and Resource count, enrolled Student count<br />
<code sql><br />
SELECT COUNT(l.id) hits, concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS Course <br />
<br />
,(SELECT CONCAT(u.firstname,' ', u.lastname) AS Teacher<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS Teacher<br />
<br />
,CASE <br />
WHEN c.fullname LIKE '%תשע' THEN 'תשע'<br />
WHEN c.fullname LIKE '%תשעא' THEN 'תשעא'<br />
WHEN c.fullname LIKE '%תשעב' THEN 'תשעב'<br />
END AS Year<br />
<br />
,(SELECT count(*) FROM prefix_course_modules cm WHERE cm.course = l.course) Modules<br />
<br />
,(SELECT Count( ra.userid ) AS Users FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = c.id) AS Students<br />
<br />
FROM prefix_log l <br />
INNER JOIN prefix_course c ON l.course = c.id<br />
GROUP BY c.id<br />
#The following line restricts the courses returned to those having more than 2 modules. Adjust based on your needs.<br />
HAVING Modules > 2<br />
ORDER BY Year DESC, hits DESC<br />
</code><br />
<br />
=== Least active or probably empty courses===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
It is difficult to know sometimes when a course is actually empty or was never really in use. Other than the simple case where the course was created and never touched again, in which case the course timecreated and timemodified will be the same, many courses created as shells for teachers or other users may be used once or a few times and have few or no test users enrollments in them. This query helps you see the range of such courses, showing you how many days if any it was used after initial creation, and how many user are enrolled. It denotes a course never ever modified by "-1" instead of "0" so you can sort those to the top. By default it limits this to courses used within 60 days of creation, and to courses with 3 or less enrollments (for example, teacher and assistant and test student account only.) You can easily adjust these numbers. The query includes a link to the course as well. <br />
<br />
<code sql><br />
SELECT<br />
c.fullname,<br />
CONCAT('<a target="_blank" href="%%WWWROOT%%/course/view.php',CHAR(63),'id=',c.id,'">',c.shortname,'</a>') AS 'CourseLink',<br />
DATE_FORMAT(FROM_UNIXTIME(c.timecreated), '%Y-%m-%d %H:%i') AS 'Timecreated',<br />
DATE_FORMAT(FROM_UNIXTIME(c.timemodified), '%Y-%m-%d %H:%i') AS 'Timemodified',<br />
CASE<br />
WHEN c.timecreated = c.timemodified THEN '-1'<br />
ELSE DATEDIFF(FROM_UNIXTIME(c.timemodified),FROM_UNIXTIME(c.timecreated))<br />
END AS 'DateDifference',<br />
COUNT(ue.id) AS Enroled<br />
FROM prefix_course AS c<br />
JOIN prefix_enrol AS en ON en.courseid = c.id<br />
LEFT JOIN prefix_user_enrolments AS ue ON ue.enrolid = en.id<br />
WHERE DATEDIFF(FROM_UNIXTIME(c.timemodified),FROM_UNIXTIME(c.timecreated) ) < 60<br />
GROUP BY c.id<br />
HAVING COUNT(ue.id) <= 3<br />
ORDER BY c.fullname<br />
</code><br />
<br />
===Count unique teachers with courses that use at least X module (Moodle19)===<br />
You can remove the outer "SELECT COUNT(*) FROM (...) AS ActiveTeachers" SQL query and get the list of the Teachers and Courses.<br />
<code sql><br />
SELECT COUNT(*)<br />
FROM (SELECT c.id AS CourseID, c.fullname AS Course, ra.roleid AS RoleID, CONCAT(u.firstname, ' ', u.lastname) AS Teacher<br />
,(SELECT COUNT(*) FROM prefix_course_modules cm WHERE cm.course = c.id) AS Modules<br />
FROM prefix_course AS c<br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid AND ctx.contextlevel = 50 <br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE ra.roleid = 3 <br />
GROUP BY u.id<br />
HAVING Modules > 5) AS ActiveTeachers<br />
</code><br />
<br />
===RESOURCE count for each COURSE===<br />
<code sql><br />
SELECT COUNT(l.id) count, l.course, c.fullname coursename<br />
FROM prefix_resource l INNER JOIN prefix_course c on l.course = c.id<br />
GROUP BY course<br />
ORDER BY count DESC<br />
</code><br />
<br />
===Common resource types count for each Category (Moodle19)===<br />
Including sub-categories in total count.<br />
<code sql><br />
SELECT mcc.id AS mccid, CONCAT( LPAD( '', mcc.depth, '.' ) , mcc.name ) AS Category<br />
,(SELECT COUNT( * ) <br />
FROM prefix_resource AS r<br />
JOIN prefix_course AS c ON c.id = r.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%', mccid, '%' ) AND r.TYPE = 'file' AND r.reference LIKE 'http://%'<br />
) AS Links<br />
<br />
,(SELECT COUNT( * ) <br />
FROM prefix_resource AS r<br />
JOIN prefix_course AS c ON c.id = r.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%', mccid, '%' ) AND r.TYPE = 'file' AND r.reference NOT LIKE 'http://%'<br />
) AS Files<br />
<br />
,(SELECT COUNT( * ) <br />
FROM prefix_resource AS r<br />
JOIN prefix_course AS c ON c.id = r.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%', mccid, '%' ) AND r.TYPE = 'directory' <br />
) AS Folders<br />
<br />
,(SELECT COUNT( * ) <br />
FROM prefix_resource AS r<br />
JOIN prefix_course AS c ON c.id = r.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%', mccid, '%' ) AND r.TYPE = 'html' <br />
) AS Pages<br />
<br />
,(SELECT COUNT(*) <br />
FROM stats_log_context_role_course <br />
WHERE roleid = 5 AND module = 'resource' AND category = mcc.id<br />
) AS Hits<br />
<br />
FROM prefix_course_categories AS mcc<br />
ORDER BY mcc.path<br />
</code><br />
Where "stats_log_context_role_course" (in the above SQL query) is a VIEW generated by:<br />
<code sql><br />
CREATE VIEW stats_log_context_role_course AS<br />
SELECT l.course, c.category, cc.path, l.module, l.action, ra.userid, ra.roleid<br />
FROM prefix_log AS l<br />
JOIN prefix_context AS context ON context.instanceid = l.course AND context.contextlevel = 50<br />
JOIN prefix_role_assignments AS ra ON ra.userid = l.userid AND ra.contextid = context.id<br />
JOIN prefix_course AS c ON c.id = l.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
</code><br />
<br />
Same query but for Moodle2+<br />
<code sql><br />
SELECT mcc.id AS mccid, CONCAT( LPAD( '', mcc.depth, '.' ) , mcc.name ) AS Category,<br />
mcc.path,<br />
<br />
(SELECT COUNT(*) <br />
FROM prefix_url AS u<br />
JOIN prefix_course AS c ON c.id = u.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%/', mccid, '%' )<br />
) AS URLs,<br />
<br />
(SELECT COUNT(*) <br />
FROM prefix_folder AS f<br />
JOIN prefix_course AS c ON c.id = f.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%/', mccid, '%' )<br />
) AS FOLDERs,<br />
<br />
(SELECT COUNT(*) <br />
FROM prefix_page AS p<br />
JOIN prefix_course AS c ON c.id = p.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%/', mccid, '%' )<br />
) AS PAGEs,<br />
<br />
(SELECT COUNT(*) <br />
FROM prefix_book AS b<br />
JOIN prefix_course AS c ON c.id = b.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%/', mccid, '%' )<br />
) AS BOOKs,<br />
<br />
(SELECT COUNT(*) <br />
FROM prefix_label AS l<br />
JOIN prefix_course AS c ON c.id = l.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%/', mccid, '%' )<br />
) AS LABELs,<br />
<br />
(SELECT COUNT(*) <br />
FROM prefix_tab AS t<br />
JOIN prefix_course AS c ON c.id = t.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%/', mccid, '%' )<br />
) AS TABs<br />
<br />
FROM prefix_course_categories AS mcc<br />
ORDER BY mcc.path<br />
</code><br />
<br />
===Detailed Resource COUNT by Teacher in each course===<br />
<br />
Including (optional) filter by: year, semester and course id.<br />
<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS CourseID<br />
, c.id<br />
,( SELECT DISTINCT CONCAT(u.firstname,' ',u.lastname)<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_user AS u ON ra.userid = u.id<br />
JOIN prefix_context AS ctx ON ctx.id = ra.contextid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id AND ctx.contextlevel = 50 LIMIT 1) AS Teacher<br />
<br />
, (CASE <br />
WHEN c.fullname LIKE '%תשעב%' THEN '2012' <br />
WHEN c.fullname LIKE '%תשעא%' THEN '2011'<br />
END ) as Year<br />
, (CASE <br />
WHEN c.fullname LIKE '%סמסטר א%' THEN 'Semester A' <br />
WHEN c.fullname LIKE '%סמסטר ב%' THEN 'Semester B'<br />
WHEN c.fullname LIKE '%סמסטר ק%' THEN 'Semester C'<br />
END ) as Semester<br />
,COUNT(c.id) AS Total<br />
,(SELECT count(*) FROM prefix_course_modules AS cm WHERE cm.course = c.id AND cm.module= 20) AS TABs<br />
,(SELECT count(*) FROM prefix_course_modules AS cm WHERE cm.course = c.id AND cm.module= 33) AS BOOKs<br />
<br />
FROM `prefix_resource` as r <br />
JOIN `prefix_course` AS c on c.id = r.course<br />
#WHERE type= 'file' and reference NOT LIKE 'http://%' <br />
<br />
#WHERE 1=1<br />
#%%FILTER_YEARS:c.fullname%%<br />
#AND c.fullname LIKE '%2013%'<br />
<br />
GROUP BY course<br />
ORDER BY COUNT(c.id) DESC<br />
</code><br />
<br />
===Courses that are defined as using GROUPs===<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/group/index.php?id=',c.id,'">',c.fullname,'</a>') AS Course<br />
,(SELECT count(*) FROM prefix_course_modules cm WHERE cm.course = c.id) Modules<br />
,(SELECT count(*) FROM prefix_groups g WHERE g.courseid = c.id) Groups<br />
FROM `prefix_course` AS c<br />
WHERE groupmode > 0<br />
</code><br />
<br />
===Courses with Groups===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
List of all courses with Groups in them (groupmode > 0). You can also use groupmode=1 to list just Separate type groups or groupmode=2 to list Visible type groups.<br />
<br />
<code sql><br />
SELECT c.shortname, g.name, c.groupmode<br />
FROM prefix_course AS c<br />
JOIN prefix_groups AS g ON c.id = g.courseid<br />
WHERE c.groupmode > 0<br />
</code><br />
<br />
===Users enrolled in a course with groups but not assigned a group ===<br />
<br />
Displays by course all enrolled users that have not been assigned a group in courses that have groups. NOTE: This needs to be optimized.<br />
<br />
<code sql><br />
SELECT DISTINCT<br />
user2.firstname AS Firstname,<br />
user2.lastname AS Lastname,<br />
user2.email AS Email,<br />
user2.city AS City,<br />
course.fullname AS Course<br />
,(SELECT shortname FROM prefix_role WHERE id=en.roleid) AS ROLE<br />
,(SELECT name FROM prefix_role WHERE id=en.roleid) AS RoleName<br />
<br />
FROM prefix_course AS course <br />
JOIN prefix_enrol AS en ON en.courseid = course.id<br />
JOIN prefix_user_enrolments AS ue ON ue.enrolid = en.id<br />
JOIN prefix_user AS user2 ON ue.userid = user2.id<br />
JOIN prefix_groups AS g ON g.courseid = course.id<br />
<br />
WHERE ue.enrolid NOT IN (select userid from prefix_groups_members WHERE g.id=groupid)<br />
<br />
ORDER BY Course, Lastname<br />
</code><br />
<br />
===Groups in course with member list===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
List the groups in a course (replace the # by the course id number) with the members of each group.<br />
<br />
<code sql><br />
SELECT c.shortname, g.name AS Groupname, u.username<br />
FROM prefix_course AS c<br />
JOIN prefix_groups AS g ON g.courseid = c.id<br />
JOIN prefix_groups_members AS m ON g.id = m.groupid<br />
JOIN prefix_user AS u ON m.userid = u.id<br />
WHERE c.id = #<br />
</code><br />
<br />
Note: if you are using Configurable Reports block and want to perform this query on the current course you are in, then you can use a WHERE clause like this:<br />
<code sql><br />
WHERE c.id = %%COURSEID%%<br />
</code><br />
<br />
===Group Export===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
There's a [[Import_groups|group import]] function, but no export. Use this to give you a report with the proper column order and headings to export to a csv file you can then import into another course to replicate the groups. This is a simple version with just the main fields: groupname, description, enrolment key.<br />
<br />
<code sql><br />
SELECT g.name AS groupname, g.description, g.enrolmentkey<br />
FROM prefix_groups AS g <br />
JOIN prefix_course as c ON g.courseid = c.id<br />
WHERE c.id = #<br />
</code><br />
Note: if you are using Configurable Reports block and want to perform this query on the current course you are in, then you can use a WHERE clause like this:<br />
<code sql><br />
WHERE c.id = %%COURSEID%%<br />
</code><br />
<br />
===List all Courses in and below a certain category===<br />
Use this SQL code to retrieve all courses that exist in or under a set category.<br />
<br />
$s should be the id of the category you want to know about...<br />
<code sql><br />
SELECT prefix_course. * , prefix_course_categories. *<br />
FROM prefix_course, prefix_course_categories<br />
WHERE prefix_course.category = prefix_course_categories.id<br />
AND (<br />
prefix_course_categories.path LIKE '%/$s/%'<br />
OR prefix_course_categories.path LIKE '%/$s'<br />
)<br />
</code><br />
<br />
===List all Categories in one level below a certain category===<br />
Use this PHP code to retrieve a list of all categories below a certain category.<br />
<br />
$s should be the id of the top level category you are interested in.<br />
<code php><br />
<?php<br />
<br />
require_once('./config.php');<br />
<br />
$parent_id = $s;<br />
<br />
$categories= array();<br />
<br />
$categories = get_categories($parent_id);<br />
<br />
echo '<ol>';<br />
foreach ($categories as $category)<br />
{<br />
echo '<li><a href="'.$CFG->wwwroot.'/course/category.php?id='.$category->id.'">'.$category->name.'</a></li>';<br />
}<br />
echo '</ol>';<br />
<br />
?><br />
</code><br />
<br />
===Blog activity per Course (not including VIEW)===<br />
Filter activity logging to some specific Course Categories!<br />
+ link course name to actual course (for quick reference)<br />
(you can change %blog% to %wiki% to filter down all wiki activity or any other module you wish)<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',cm.course,'">',c.fullname,'</a>') as CourseID<br />
,m.name ,count(cm.id) as counter <br />
,(SELECT Count( ra.userid ) AS Users<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5<br />
AND ctx.instanceid = c.id<br />
) AS Students<br />
, ( SELECT count(id) FROM prefix_log WHERE `module` LIKE '%blog%' AND course = c.id AND action NOT LIKE '%view%' ) as BlogActivity<br />
FROM `prefix_course_modules` as cm JOIN prefix_modules as m ON cm.module=m.id JOIN prefix_course as c ON cm.course = c.id <br />
WHERE m.name LIKE '%blog%' AND c.category IN ( 8,13,15)<br />
GROUP BY cm.course,cm.module order by counter desc<br />
</code><br />
<br />
===Student's posts content in all course blogs (oublog)===<br />
<code sql><br />
SELECT <br />
b.name <br />
,op.title<br />
,op.message<br />
,( SELECT CONCAT(u.firstname, ' ',u.lastname) FROM prefix_user AS u WHERE u.id = oi.userid) AS "Username"<br />
<br />
FROM prefix_oublog_posts AS op<br />
JOIN prefix_oublog_instances AS oi ON oi.id = op.oubloginstancesid <br />
JOIN prefix_oublog as b ON b.id = oi.oublogid<br />
JOIN prefix_course AS c ON b.course = c.id<br />
<br />
WHERE c.id = %%COURSEID%%<br />
</code><br />
<br />
===All Courses which uploaded a Syllabus file===<br />
+ under specific Category<br />
+ show first Teacher in that course<br />
+ link Course's fullname to actual course<br />
<code sql><br />
SELECT<br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') as Course<br />
,c.shortname,r.name<br />
,(SELECT CONCAT(u.firstname,' ', u.lastname) as Teacher<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user as u ON u.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) as Teacher<br />
FROM prefix_resource as r <br />
JOIN prefix_course as c ON r.course = c.id<br />
WHERE ( r.name LIKE '%סילבוס%' OR r.name LIKE '%סילאבוס%' OR r.name LIKE '%syllabus%' OR r.name LIKE '%תכנית הקורס%' ) <br />
AND c.category IN (10,18,26,13,28)<br />
</code><br />
<br />
===Site-wide completed SCORM activities by Course name===<br />
This report will list all completed attempts for all SCORM activities. It is ordered first by Course name, then student's last name, then student's first name, then attempt number. Please note: the FROM_UNIXTIME command is for MySQL.<br />
<code sql><br />
SELECT u.firstname First,u.lastname Last,c.fullname Course, st.attempt Attempt,st.value Status,FROM_UNIXTIME(st.timemodified,"%m-%d-%Y") Date <br />
FROM prefix_scorm_scoes_track AS st <br />
JOIN prefix_user AS u ON st.userid=u.id<br />
JOIN prefix_scorm AS sc ON sc.id=st.scormid<br />
JOIN prefix_course AS c ON c.id=sc.course<br />
WHERE st.value='completed' <br />
ORDER BY c.fullname, u.lastname,u.firstname, st.attempt<br />
</code><br />
===All users enrolled in a course without a role===<br />
Identifies All users that are enrolled in a course but are not assigned a role.<br />
<code sql><br />
SELECT<br />
user.firstname AS Firstname,<br />
user.lastname AS Lastname,<br />
user.idnumber Employee_ID,<br />
course.fullname AS Course<br />
<br />
FROM prefix_course AS course <br />
JOIN prefix_enrol AS en ON en.courseid = course.id<br />
JOIN prefix_user_enrolments AS ue ON ue.enrolid = en.id<br />
JOIN prefix_user as user ON user.id = ue.userid<br />
<br />
WHERE user.id NOT IN (<br />
SELECT u.id<br />
FROM prefix_course AS c<br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid<br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN prefix_role AS r ON r.id = ra.roleid<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE c.id=course.id<br />
)<br />
ORDER BY Course, Lastname, Firstname<br />
<br />
</code><br />
<br />
===List course resources accumulative file size and count===<br />
This is the main (first) report, which has a link (alias) to a second report (the following on this page) which list each file in the course.<br />
<code sql><br />
SELECT c.id "CourseID", context.id "ContextID"<br />
,CONCAT('<a target="_new" href="%%WWWROOT%%/course/view.php?id=', c.id, '">', c.fullname ,'</a>') AS "Course Name"<br />
, COUNT(*) "Course Files" , ROUND( SUM( f.filesize ) /1048576 ) AS file_size_MB<br />
,CONCAT('<a target="_new" href="%%WWWROOT%%/blocks/configurable_reports/viewreport.php?alias=coursefiles&courseid=1&filter_courses=', c.id, '">List files</a>') AS "List Files"<br />
<br />
FROM mdl_files AS f<br />
JOIN mdl_context AS context ON context.id = f.contextid<br />
JOIN mdl_course AS c ON c.id = (<br />
SELECT instanceid<br />
FROM mdl_context<br />
WHERE id = SUBSTRING_INDEX( SUBSTRING_INDEX( context.path, '/' , -2 ) , '/', 1 ) )<br />
WHERE filesize >0<br />
GROUP BY c.id<br />
</code><br />
<br />
With this report, you will have to define "alias" report property to "coursefiles" for it to be able to be called from the above report.<br />
And also setup (add) a FILTER_COURSES filter. <br />
<code sql><br />
SELECT <br />
id ,CONCAT('<a target="_new" href="%%WWWROOT%%/pluginfile.php/', contextid, '/', component, '/', filearea, '/', itemid, '/', filename, '">', filename,'</a>') AS "File"<br />
,filesize, mimetype ,author, license, timecreated, component, filearea, filepath<br />
<br />
FROM mdl_files AS f<br />
WHERE filesize >0<br />
AND f.contextid<br />
IN ( SELECT id<br />
FROM mdl_context<br />
WHERE path <br />
LIKE ( SELECT CONCAT('%/',id,'/%')<br />
AS contextquery<br />
FROM mdl_context<br />
WHERE 1=1<br />
%%FILTER_COURSES:instanceid%%<br />
AND contextlevel = 50<br />
)<br />
)<br />
</code><br />
<br />
===Which courses has redundant topics===<br />
This report list several "active topics" calculations, per course. which should give an administrator some indications for which topics/sections/weeks are filled with resources and activities and which ones are empty and not used (usually, at the end of the course).<br />
<br />
The following, second SQL query, could be used to "trim" down those redundant course topics/sections/weeks by updating the course format's numsection (Number of sections) setting. (It's a per course format setting!)<br />
<br />
<code sql><br />
SELECT id, format,<br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">', c.fullname,'</a>') AS Course <br />
<br />
,(SELECT value FROM `mdl_course_format_options` WHERE `courseid` = c.id AND `format` = c.format AND `name` = 'numsections' ) AS "numsections"<br />
,(SELECT COUNT(*) FROM `mdl_course_sections` WHERE `course` = c.id AND `sequence` != '' ) AS "Non empty sections count"<br />
,(SELECT COUNT(*) FROM `mdl_course_sections` WHERE `course` = c.id ) AS "Total section count"<br />
,(SELECT COUNT(*) FROM `mdl_course_sections` WHERE `course` = c.id AND sequence IS NOT NULL) AS "Non NULL sections count"<br />
,(SELECT COUNT(*) FROM `mdl_course_sections` WHERE `course` = c.id AND name != '') AS "Non empty section Name count"<br />
,(SELECT COUNT(*) FROM mdl_course_modules cm WHERE cm.course = c.id) "Modules count"<br />
<br />
FROM mdl_course AS c<br />
</code><br />
<br />
The following SQL REPLACE query is used for "fixing" (updating) the "numsections" of a specific course format "onetopics" (you can always change it, or discard it to use this SQL REPLACE on all course formats) <br />
<code sql><br />
REPLACE INTO `mdl_course_format_options` (`id`, `courseid`, `format`, `sectionid`, `name`, `value`) <br />
SELECT NULL, c.id, 'onetopic', '0', 'numsections', (SELECT COUNT(*) FROM `mdl_course_sections` WHERE `course` = c.id AND name != '')<br />
FROM `mdl_course` c where format = 'onetopic'<br />
</code><br />
<br />
===Hidden Courses with Students Enrolled===<br />
Contributed by Eric Strom<br />
<br />
This query identifies courses with student enrollment that are currently hidden from students. Includes the defined course start date, count of students and instructors, and a clickable email link of instructor (first found record if more than one).<br />
<br />
<code sql><br />
SELECT c.visible AS Visible, <br />
DATE(FROM_UNIXTIME(c.startdate)) AS StartDate, <br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php',CHAR(63),'id=',<br />
c.id,'">',c.idnumber,'</a>') AS Course_ID,<br />
<br />
(SELECT COUNT( ra.userid ) FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = c.id) AS Students,<br />
<br />
(SELECT COUNT( ra.userid ) FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id) AS Instructors,<br />
<br />
(SELECT DISTINCT concat('<a href="mailto:',u.email,'">',u.email,'</a>')<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_user AS u ON ra.userid = u.id<br />
JOIN prefix_context AS ctx ON ctx.id = ra.contextid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id AND ctx.contextlevel = 50 LIMIT 1) AS 'Instructor_Email', <br />
<br />
now() AS Report_Timestamp<br />
<br />
FROM prefix_course AS c <br />
WHERE c.visible = 0 AND (SELECT COUNT( ra.userid ) FROM prefix_role_assignments AS ra JOIN prefix_context AS ctx ON ra.contextid = ctx.id WHERE ra.roleid = 5 AND ctx.instanceid = c.id) > 0<br />
ORDER BY StartDate, Instructor_Email, Course_ID<br />
</code><br />
<br />
<br />
==Course Design Reports==<br />
<br />
These are reports which summarize course design aspects, such as activity and resource modules per section, types of activities used, etc.<br />
<br />
===Course Content/Week===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
This report assumes that the first 14 sections in a course, not including the "0" or "Welcome" section, correspond to weeks (with "Subsections" given numbers much higher in the sequence). Of those sections, each is checked to count the number of:<br />
<br />
Forums<br />
Graded Activities (may include Forums)<br />
Resources (not including a Label)<br />
<br />
Totals of each of these types of content elements per section are provided.<br />
<br />
'''Note''': Only visible resources and activities are counted.<br />
'''Note''': this is a "Global" report. Run it within a course to see a summary of the contents of that course.<br />
<br />
<code sql><br />
SELECT<br />
<br />
cs.section AS 'Week'<br />
, cs.name AS 'Section Name'<br />
<br />
, COUNT(DISTINCT IF((gi.id IS NULL) AND (m.name NOT LIKE 'label'),cm.id,NULL)) AS 'Ungraded Resources'<br />
<br />
, COUNT(DISTINCT IF(m.name LIKE 'forum', cm.id, NULL)) AS 'Forums'<br />
<br />
, COUNT(DISTINCT IF(gi.id, cm.id, NULL)) AS 'Graded Activities'<br />
<br />
FROM prefix_course AS c<br />
JOIN prefix_course_sections AS cs ON cs.course = c.id AND cs.section <= 14 AND cs.section > 0<br />
LEFT JOIN prefix_course_modules AS cm ON cm.course = c.id AND cm.section = cs.id <br />
JOIN prefix_modules AS m ON m.id = cm.module<br />
LEFT JOIN prefix_grade_items AS gi ON gi.courseid = c.id AND gi.itemmodule = m.name AND gi.iteminstance = cm.instance<br />
<br />
WHERE <br />
cs.visible = 1<br />
AND cm.visible = 1<br />
AND c.id = %%COURSEID%%<br />
<br />
GROUP BY cs.section<br />
ORDER BY cs.section<br />
<br />
</code><br />
<br />
===Assignments and Weights===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
Returns a list of grade book categories for the current course, grade book weightings, the first type of assignment included in the category, a count of different assignment types for each category, and a count of assignments for each category.<br />
<br />
Categories with weights of 0 are not included in this report.<br />
<br />
Only visible activities are included in this report.<br />
<br />
'''Note''': This is designed to be a "Global" report in Configurable Reports.<br />
<code sql><br />
SELECT<br />
<br />
IF(gc.parent IS NOT NULL, gc.fullname, 'None') AS 'Grade Book Category'<br />
, IF(gc.parent IS NOT NULL, ROUND(gic.aggregationcoef, 2), ROUND(SUM(DISTINCT gi.aggregationcoef), 2)+ROUND(SUM(DISTINCT mgi.aggregationcoef), 2)) AS 'Category weight'<br />
<br />
, CONCAT_WS(', ',GROUP_CONCAT(DISTINCT gi.itemmodule SEPARATOR ', '), IF(mgi.id, 'manual',NULL)) AS 'Activity Types'<br />
, COUNT(DISTINCT gi.itemmodule) + IF(mgi.id,1,0) AS 'Different Activity Types'<br />
, CONCAT_WS('<br>', GROUP_CONCAT(DISTINCT gi.itemname ORDER BY gi.itemname SEPARATOR '<br>'), GROUP_CONCAT(DISTINCT mgi.itemname ORDER BY mgi.itemname SEPARATOR '<br>')) AS 'Activity Names'<br />
, COUNT(DISTINCT IF(gi.id, cm.id, NULL)) + COUNT(DISTINCT mgi.id) AS 'Activity Count'<br />
<br />
FROM prefix_course AS c<br />
<br />
#get grade categories<br />
LEFT JOIN prefix_grade_categories AS gc ON gc.courseid = c.id <br />
# back from categories to grade items to get aggregations and weights<br />
JOIN prefix_grade_items AS gic ON gic.courseid = c.id AND gic.itemtype = 'category' AND gic.aggregationcoef != 0 AND (LOCATE(gic.iteminstance, gc.path) OR (gc.parent IS NULL))<br />
<br />
# attach activities to course<br />
JOIN prefix_course_modules AS cm ON cm.course = c.id <br />
# attach grade items to activities<br />
LEFT JOIN prefix_grade_items AS gi ON gi.courseid = c.id AND gi.iteminstance = cm.instance AND gi.itemtype = 'mod' AND gi.categoryid = gc.id AND gi.hidden != 1<br />
<br />
# attach manual grade items to course-- they don't have modules<br />
LEFT JOIN prefix_grade_items AS mgi ON mgi.courseid = c.id and mgi.itemtype = 'manual' AND mgi.categoryid = gc.id<br />
<br />
WHERE <br />
cm.visible = 1<br />
AND c.id = %%COURSEID%%<br />
<br />
GROUP BY gc.id<br />
ORDER BY gc.id<br />
<br />
</code><br />
<br />
===Pre-Term Course Review===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
Provides an overview of the readiness of ONLINE, HYBRID, and BLENDED courses in the Staging category and all subcategories. Links to each course are provided. Other details:<br />
<br />
# "Required blocks" include Instructor Block (mooprofile), Activities, and the Research block.<br />
# "Instructor Details" block is not the "Instructor" block (mooprofile) automatically provided by the system. It is an optional block that can be edited by the instructor. If not edited to remove boilerplate text, it should be hidden.<br />
# All courses should be in the "Collapsed Topics" format with the "Weeks" structure.<br />
# "Weeks defined in course settings" is taken from our SIS when the course shells are created, but can be edited by faculty. "# of weeks named and visible" should usually match or exceed this value.<br />
# We recommend that each week contain at least one forum, at least one graded activity, and at least one ungraded resource.<br />
# "Syllabus updated" date is for the first attached file found with the text "syllabus" in the name. The "Days ago" calculation is included for convenience.<br />
<br />
'''Note''': At our institution, we construct categories each term, and insert a text string "staging" in the Category ID for pre-term courses during the preparation or "staging" phase of course development. We remove this text string (and change it to "production") when courses go live at the start of the new term.<br />
<br />
<code sql><br />
SELECT CONCAT('<a target="_blank" href="%%WWWROOT%%/course/view.php',CHAR(63),'id=',c.id,'">',c.shortname,'</a>') AS Course<br />
<br />
#,RIGHT(c.idnumber,2) AS Type # Specific to GSC "Instructional Method" storage<br />
<br />
#, substring_index(substr(c.shortname FROM locate('.',c.shortname)+1),'-',1) AS Section # Specific to GSC<br />
<br />
,(SELECT CONCAT('<a target="_blank" href="%%WWWROOT%%/user/view.php',CHAR(63),'id=',u.id,'">',u.lastname,', ', u.firstname,'</a>')<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS 'Instructor' <br />
<br />
,(SELECT IF((u2.description IS NULL) OR (u2.description LIKE ''),'NO', 'YES')<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u2 ON u2.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS 'Profile Has Bio'<br />
<br />
,(SELECT IF(u3.picture > 0,'YES','NO')<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u3 ON u3.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS 'Profile Has Picture'<br />
<br />
, IF(((bpi.visible IS NULL) OR (bpi.visible !=0)) AND ((bpm.visible IS NULL) OR (bpm.visible !=0)) AND ((bpa.visible IS NULL) OR (bpa.visible !=0)) AND ((bpr.visible IS NULL) OR (bpr.visible !=0)),'YES','NO') AS 'Required blocks visible'<br />
#, IF((bpm.visible IS NULL) OR (bpm.visible !=0),'YES','NO') AS 'Messages block visible'<br />
#, IF((bpa.visible IS NULL) OR (bpa.visible !=0),'YES','NO') AS 'activities block visible'<br />
#, IF((bpr.visible IS NULL) OR (bpr.visible !=0),'YES','NO') AS 'research block visible'<br />
<br />
#, IF(SUM(IF(bi.configdata LIKE 'Tzo4OiJzdGRDbGFzcyI6Mzp7czo1OiJ0aXRsZSI7czoxODoiSW5zdHJ1Y3RvciBEZXRhaWxzI%',1,0)) AND (bip.visible !=0),'YES','') AS 'Instructor Details Block visible' # This is a hack based on UUencoded string data from the title of HTML "Instructor Details" block<br />
<br />
#, IF(bi.configdata LIKE '%ZGl0IHRoaXMgYmxvY2s%','NO','') AS 'Instructor Details Block Updated' # HTML block has string 'dit this block'<br />
<br />
#, IF(COUNT(bi.id) - SUM(IF(bi.configdata LIKE 'Tzo4OiJzdGRDbGFzcyI6Mzp7czo1OiJ0aXRsZSI7czoxODoiSW5zdHJ1Y3RvciBEZXRhaWxzI%',1,0)),'YES','') AS 'possible extra instructor blocks' #looking for any HTML block with "instructor" in the title<br />
<br />
, IF(c.format='topcoll','YES', c.format) AS 'Collapsed Topics course format' # change this if you want to test for a different format<br />
, IF(cfo.value = 2, 'YES','NO') AS 'weeks structure'<br />
<br />
, cfw.value AS 'weeks defined in course settings'<br />
<br />
, COUNT(DISTINCT IF(((cs.name IS NOT NULL) AND (cs.visible = 1) AND (cs.section != '0') AND (cs.sequence IS NOT NULL)),cs.id,NULL)) AS '# of weeks named & visible (includes orphans)'<br />
<br />
, COUNT(DISTINCT IF(m.name LIKE 'forum', cm.id, NULL)) AS 'Forums'<br />
, COUNT(DISTINCT IF(m.name LIKE 'forum' ,cs.id , NULL)) AS 'Weeks with Forum'<br />
<br />
, COUNT(DISTINCT IF(gi.id, cm.id, NULL)) AS 'Activities'<br />
, COUNT(DISTINCT IF(gi.id, cs.id, NULL)) AS 'Weeks with Activities'<br />
, COUNT(DISTINCT mgi.id) AS 'Manual Grade Items'<br />
<br />
, COUNT(DISTINCT IF((gi.id IS NULL) AND (m.name NOT IN ('forum','label')),cm.id,NULL)) AS 'Resources'<br />
, COUNT(DISTINCT IF((gi.id IS NULL) AND (m.name NOT IN ('forum','label')), cs.id, NULL)) AS 'Weeks with Resources'<br />
<br />
# Here are some other things you could check for per course<br />
#,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm JOIN prefix_modules AS m ON cm.module = m.id WHERE cm.course = c.id AND m.name LIKE '%forum%') AS Forums<br />
<br />
#,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm JOIN prefix_modules AS m ON cm.module = m.id WHERE cm.course = c.id AND m.name LIKE '%quiz%') AS Quizzes<br />
<br />
#,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm JOIN prefix_modules AS m ON cm.module = m.id WHERE cm.course = c.id AND m.name LIKE '%assign%') AS Assignments<br />
<br />
#,(SELECT COUNT(prefix_resource.id) FROM prefix_resource JOIN prefix_course ON prefix_course.id = prefix_resource.course WHERE c.id = prefix_resource.course) AS Files<br />
<br />
#,(SELECT COUNT(prefix_url.id) FROM prefix_url JOIN prefix_course ON prefix_course.id = prefix_url.course WHERE c.id = prefix_url.course) AS Links<br />
<br />
,(SELECT FROM_UNIXTIME(MAX(prefix_resource.timemodified))<br />
FROM prefix_resource<br />
JOIN prefix_course ON prefix_course.id = prefix_resource.course WHERE c.id = prefix_resource.course AND prefix_resource.name LIKE '%syllabus%') AS SyllabusDate<br />
<br />
,(SELECT TO_DAYS(NOW())-TO_DAYS(FROM_UNIXTIME(MAX(prefix_resource.timemodified)))<br />
FROM prefix_resource<br />
JOIN prefix_course ON prefix_course.id = prefix_resource.course WHERE c.id = prefix_resource.course AND prefix_resource.name LIKE '%syllabus%') AS DaysAgo<br />
<br />
, IF(COUNT(DISTINCT IF(f.type LIKE 'news', f.id,NULL)),'YES','NO' ) AS 'Announcement Forum Visible'<br />
<br />
, IF(COUNT(DISTINCT IF(f.type LIKE 'news', fd.id,NULL)),'YES','NO' ) AS 'Announcement posted'<br />
<br />
FROM prefix_course AS c<br />
LEFT JOIN prefix_course_categories as cc ON c.category = cc.id<br />
LEFT JOIN prefix_context AS ctxx ON c.id = ctxx.instanceid <br />
<br />
LEFT JOIN prefix_block_positions AS bpi ON bpi.contextid = ctxx.id AND bpi.blockinstanceid = '43692' # mooprofile<br />
LEFT JOIN prefix_block_positions AS bpm ON bpm.contextid = ctxx.id AND bpm.blockinstanceid = '43962' # messages<br />
LEFT JOIN prefix_block_positions AS bpa ON bpa.contextid = ctxx.id AND bpa.blockinstanceid = '43963' # activities<br />
LEFT JOIN prefix_block_positions AS bpr ON bpr.contextid = ctxx.id AND bpr.blockinstanceid = '38368' # html research help<br />
<br />
LEFT JOIN prefix_course_sections AS cs ON cs.course = c.id AND cs.visible = 1 AND cs.sequence IS NOT NULL<br />
LEFT JOIN prefix_course_modules AS cm ON cm.course = c.id AND cm.section = cs.id <br />
LEFT JOIN prefix_modules AS m ON m.id = cm.module<br />
LEFT JOIN prefix_grade_items AS gi ON gi.courseid = c.id AND gi.itemmodule = m.name AND gi.iteminstance = cm.instance<br />
<br />
LEFT JOIN prefix_forum AS f ON f.course = c.id AND cm.instance = f.id AND cm.visible = 1<br />
LEFT JOIN prefix_forum_discussions AS fd ON fd.forum = f.id<br />
<br />
# attach manual grade items to course-- they don't have modules<br />
LEFT JOIN prefix_grade_items AS mgi ON mgi.courseid = c.id and mgi.itemtype = 'manual'<br />
<br />
LEFT JOIN prefix_course_format_options AS cfo ON cfo.courseid = c.id AND cfo.name = 'layoutstructure'<br />
LEFT JOIN prefix_course_format_options AS cfw ON cfw.courseid = c.id AND cfw.name = 'numsections'<br />
<br />
LEFT JOIN prefix_block_instances AS bi ON bi.parentcontextid = ctxx.id AND bi.blockname = 'html' AND (bi.configdata LIKE '%SW5zdHJ1Y3Rvc%' or bi.configdata LIKE '%bnN0cnVjdG9y%')<br />
LEFT JOIN prefix_block_positions AS bip ON bip.blockinstanceid = bi.id<br />
<br />
WHERE RIGHT(c.idnumber,2) IN ('OL', 'BL', 'HY') <br />
# AND substring(cc.path,2,2) IN ('26') # Staging<br />
#AND substring(cc.path,2,3) IN ('158') # UG<br />
AND cc.idnumber LIKE '%staging%'<br />
AND ctxx.contextlevel = 50<br />
<br />
GROUP BY c.shortname<br />
</code><br />
<br />
===Module instances + Module HITs by role teacher and student in course===<br />
<code sql><br />
SELECT <br />
m.name AS "Module name"<br />
, COUNT(*) AS "Module count"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_log AS l <br />
WHERE l.course = cm.course AND l.module = m.name ) AS "Hits"<br />
<br />
,(SELECT COUNT(*)<br />
FROM prefix_log AS l<br />
JOIN prefix_context AS con ON con.instanceid= l.course AND con.contextlevel=50<br />
JOIN prefix_role_assignments AS ra ON ra.contextid= con.id AND ra.userid= l.userid AND ra.roleid = 5 <br />
WHERE l.course = cm.course AND l.module = m.name) AS "Students HITs"<br />
<br />
,(SELECT COUNT(*)<br />
FROM prefix_log AS l<br />
JOIN prefix_context AS con ON con.instanceid= l.course AND con.contextlevel=50<br />
JOIN prefix_role_assignments AS ra ON ra.contextid= con.id AND ra.userid= l.userid AND ra.roleid = 3 <br />
WHERE l.course = cm.course AND l.module = m.name) AS "Teachers HITs"<br />
<br />
FROM mdl_course_modules AS cm<br />
JOIN mdl_modules AS m on m.id = cm.module<br />
WHERE cm.course = '%%COURSEID%%'<br />
GROUP BY cm.module<br />
</code><br />
<br />
===Course Syllabus===<br />
Contributed by Elizabeth Dalton, Granite State College / Moodle HQ<br />
<br />
This report requires ELIS. It runs from within a course and constructs a course syllabus based on content in the course and in the ELIS entries related to the course (Class Instance, Course Description, and Program). It is a proof-of-concept of an automated syllabus production tool. Fields such as "Course Policies" and "Teaching Philosophy" are added to the Class Instance records, and instructors enter them there. The Instructor Bio is pulled from the User Profile of all users with the Teacher role in the course.<br />
<br />
<code sql><br />
SELECT <br />
<br />
c.fullname AS 'fullname'<br />
, ec.idnumber AS 'elis-id'<br />
, DATE_FORMAT(FROM_UNIXTIME(ec.startdate), '%b %e, %Y') AS 'start'<br />
, DATE_FORMAT(FROM_UNIXTIME(ec.enddate), '%b %e, %Y') AS 'end'<br />
, ecd.name AS 'longname'<br />
, ecd.code AS 'coursecode'<br />
, ecd.credits AS 'coursecredits'<br />
, ecd.syllabus AS 'description'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'learning-outcomes'<br />
WHERE ctxecd.id = eft.contextid) AS 'outcomes'<br />
<br />
,(SELECT CONCAT('<a target="_blank" href="%%WWWROOT%%/user/view.php',CHAR(63),'id=',u.id,'">',u.firstname,' ', u.lastname,'</a> ', u.email)<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS 'Instructor' <br />
<br />
, (SELECT efc.data<br />
FROM prefix_local_eliscore_fld_data_char AS efc<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = efc.fieldid AND ef.shortname = 'term-code'<br />
WHERE ctxci.id = efc.contextid) AS 'termcode'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'prerequisites'<br />
WHERE ctxecd.id = eft.contextid) AS 'prerequisites'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'textbooks'<br />
WHERE ctxci.id = eft.contextid) AS 'textbooks'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'other-class-materials'<br />
WHERE ctxci.id = eft.contextid) AS 'other-class-materials'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'course-policies'<br />
WHERE ctxci.id = eft.contextid) AS 'course-policies'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'teaching-philosophy'<br />
WHERE ctxci.id = eft.contextid) AS 'teaching-philosophy'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'course-methods'<br />
WHERE ctxci.id = eft.contextid) AS 'course-methods'<br />
<br />
,(SELECT u2.description<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u2 ON u2.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS 'Bio'<br />
<br />
,(SELECT<br />
<br />
GROUP_CONCAT(DISTINCT CONCAT(<br />
<br />
'<tr><td style="border: solid #000 .5px">',IF(gc.parent IS NOT NULL, gc.fullname, 'None')<br />
, ' </td><td style="border: solid #000 .5px"> '<br />
,IF(gc.parent IS NOT NULL, ROUND(gic.aggregationcoef, 2), ROUND( gi.aggregationcoef, 2)+ROUND(mgi.aggregationcoef, 2))<br />
<br />
) SEPARATOR '</td></tr>')<br />
#get grade categories<br />
FROM prefix_grade_categories AS gc <br />
# back from categories to grade items to get aggregations and weights<br />
LEFT JOIN prefix_grade_items AS gic ON gic.courseid = gc.courseid AND gic.itemtype = 'category' AND gic.aggregationcoef != 0 AND (LOCATE(gic.iteminstance, gc.path) OR (gc.parent IS NULL))<br />
# attach grade items to activities<br />
LEFT JOIN prefix_grade_items AS gi ON gi.courseid = gc.courseid AND gi.itemtype = 'mod' AND gi.categoryid = gc.id AND gi.hidden != 1<br />
# attach manual grade items to course-- they don't have modules<br />
LEFT JOIN prefix_grade_items AS mgi ON mgi.courseid = gc.courseid and mgi.itemtype = 'manual' AND mgi.categoryid = gc.id<br />
WHERE gc.courseid = c.id ) AS 'grade categories'<br />
<br />
, '<table width = "50%" >' AS 'table start'<br />
, '<table width = "100%" >' AS 'table start 2'<br />
, '</table>' AS 'table end'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'activities-schedule'<br />
WHERE ctxci.id = eft.contextid) AS 'activities'<br />
<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'schedule'<br />
WHERE ctxci.id = eft.contextid) AS 'schedule'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'grading-scale'<br />
WHERE ctxepm.id = eft.contextid) AS 'gradescale'<br />
<br />
FROM<br />
prefix_course AS c <br />
<br />
# connect moodle course to ELIS class instance<br />
LEFT JOIN prefix_local_elisprogram_cls_mdl AS ecm ON ecm.moodlecourseid = c.id<br />
LEFT JOIN prefix_local_elisprogram_cls AS ec ON ec.id = ecm.classid<br />
# class instance context<br />
LEFT JOIN prefix_context AS ctxci ON ctxci.instanceid = ec.id AND ctxci.contextlevel = '14'<br />
<br />
# connect ELIS class instance to ELIS course description<br />
LEFT JOIN prefix_local_elisprogram_crs AS ecd ON ecd.id = ec.courseid<br />
# course description context<br />
LEFT JOIN prefix_context AS ctxecd ON ctxecd.instanceid = ecd.id AND ctxecd.contextlevel = '13'<br />
<br />
#connect ELIS program to ELIS Course Description<br />
LEFT JOIN prefix_local_elisprogram_pgm_crs AS epc ON epc.courseid = ecd.id<br />
LEFT JOIN prefix_local_elisprogram_pgm AS epm ON epm.id = epc.curriculumid<br />
# course program context<br />
LEFT JOIN prefix_context AS ctxepm ON ctxepm.instanceid = epm.id AND ctxepm.contextlevel = '11'<br />
<br />
WHERE<br />
<br />
c.id = %%COURSEID%%<br />
</code><br />
<br />
===Course Activities Helper===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
This report provides a list of the graded activities in a course.<br />
* '''Note''': Only graded activities are displayed.<br />
* '''Note''': This is a "Global" report. Run it within a course to see a summary of the contents of that course.<br />
* '''Note''': This report assumes that course sections each last one week.<br />
<br />
<code sql><br />
# 303 Course Activities Helper<br />
<br />
SELECT <br />
<br />
gi.itemmodule AS 'activity type'<br />
# cs.section AS 'section number'<br />
<br />
# Calculation assumes each section lasts one week<br />
, CONCAT(DATE_FORMAT(FROM_UNIXTIME(c.startdate + (7*24*60*60* (cs.section-1))), '%b %e, %Y'),' - <br>',DATE_FORMAT(FROM_UNIXTIME(c.startdate + (7*24*60*60* (cs.section))), '%b %e, %Y')) AS 'Date'<br />
<br />
, gi.itemname AS 'activity name'<br />
<br />
#, (SELECT asg.intro FROM prefix_assign AS asg WHERE asg.id = cm.instance) AS 'intro'<br />
<br />
#, (SELECT f.intro FROM prefix_forum AS f WHERE f.id = cm.instance) AS 'f intro'<br />
<br />
, CASE gi.itemmodule <br />
WHEN 'assign' THEN (SELECT asg.intro FROM prefix_assign AS asg WHERE asg.id = gi.iteminstance) <br />
WHEN 'forum' THEN (SELECT f.intro FROM prefix_forum AS f WHERE f.id = gi.iteminstance) <br />
WHEN 'quiz' THEN (SELECT q.intro FROM prefix_quiz AS q WHERE q.id = gi.iteminstance) <br />
END AS 'test case'<br />
<br />
#, (SELECT GROUP_CONCAT(CONCAT(' - ',gi.itemname) SEPARATOR '<BR>') FROM prefix_grade_items AS gi JOIN prefix_course_modules AS cm ON gi.iteminstance = cm.instance WHERE gi.gradetype = 1 AND gi.hidden != 1 AND gi.courseid = c.id AND cm.course = c.id AND cm.section = cs.id ) AS 'activities'<br />
<br />
<br />
FROM<br />
prefix_course AS c <br />
<br />
#get grade sections<br />
LEFT JOIN prefix_course_sections AS cs ON cs.course = c.id AND cs.section > 0 AND cs.section <=14<br />
LEFT JOIN prefix_course_modules AS cm ON cm.course = c.id AND cm.section = cs.id<br />
<br />
#LEFT JOIN prefix_assign AS asg ON asg.id = cm.instance<br />
<br />
JOIN prefix_grade_items AS gi ON gi.iteminstance = cm.instance AND gi.gradetype = 1 AND gi.hidden != 1 AND gi.courseid = c.id AND cm.course = c.id AND cm.section = cs.id<br />
<br />
WHERE<br />
c.id = %%COURSEID%%<br />
AND cs.visible = 1<br />
<br />
ORDER BY gi.itemmodule, cs.section<br />
</code><br />
<br />
==Grade and Course Completion Reports==<br />
===Site-Wide Grade Report with All Items===<br />
Shows grades for all course items along with course totals for each student. Works with ad-hoc reports or Configurable Reports<br />
<code sql><br />
SELECT u.firstname AS 'First' , u.lastname AS 'Last', <br />
u.firstname + ' ' + u.lastname AS 'Display Name', <br />
c.fullname AS 'Course', <br />
cc.name AS 'Category',<br />
<br />
CASE <br />
WHEN gi.itemtype = 'course' <br />
THEN c.fullname + ' Course Total'<br />
ELSE gi.itemname<br />
END AS 'Item Name',<br />
<br />
ROUND(gg.finalgrade,2) AS Grade,<br />
DATEADD(ss,gg.timemodified,'1970-01-01') AS Time<br />
<br />
FROM prefix_course AS c<br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid<br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
JOIN prefix_grade_grades AS gg ON gg.userid = u.id<br />
JOIN prefix_grade_items AS gi ON gi.id = gg.itemid<br />
JOIN prefix_course_categories as cc ON cc.id = c.category<br />
<br />
WHERE gi.courseid = c.id <br />
ORDER BY lastname<br />
</code><br />
For MySQL users, you'll need to use the MySQL DATE_ADD function instead of DATEADD. Replace the line:<br />
<code><br />
DATEADD(ss,gg.timemodified,'1970-01-01') AS Time<br />
</code><br />
with:<br />
<code><br />
FROM_UNIXTIME(gg.timemodified) AS Time<br />
</code><br />
And:<br />
<code><br />
u.firstname + ' ' + u.lastname AS 'Display Name', <br />
</code><br />
with:<br />
<code><br />
CONCAT(u.firstname,' ',u.lastname) AS 'Display Name', <br />
</code><br />
<br />
===Site-Wide Grade Report with Just Course Totals===<br />
A second site-wide grade report for all students that just shows course totals. Works with ad-hoc reports or Configurable Reports<br />
<code sql><br />
SELECT u.firstname AS 'First' , u.lastname AS 'Last', u.firstname + ' ' + u.lastname AS 'Display Name', <br />
cc.name AS 'Category',<br />
CASE <br />
WHEN gi.itemtype = 'course' <br />
THEN c.fullname + ' Course Total'<br />
ELSE gi.itemname<br />
END AS 'Item Name',<br />
<br />
ROUND(gg.finalgrade,2) AS Grade,<br />
DATEADD(ss,gg.timemodified,'1970-01-01') AS Time<br />
<br />
FROM prefix_course AS c<br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid<br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
JOIN prefix_grade_grades AS gg ON gg.userid = u.id<br />
JOIN prefix_grade_items AS gi ON gi.id = gg.itemid<br />
JOIN prefix_course_categories as cc ON cc.id = c.category<br />
<br />
WHERE gi.courseid = c.id AND gi.itemtype = 'course'<br />
<br />
ORDER BY lastname<br />
</code><br />
<br />
For MySQL users:<br />
<code sql><br />
SELECT u.firstname AS 'First' , u.lastname AS 'Last', CONCAT(u.firstname , ' ' , u.lastname) AS 'Display Name', <br />
c.fullname AS 'Course', <br />
cc.name AS 'Category',<br />
CASE <br />
WHEN gi.itemtype = 'course' <br />
THEN CONCAT(c.fullname, ' - Total')<br />
ELSE gi.itemname<br />
END AS 'Item Name',<br />
<br />
ROUND(gg.finalgrade,2) AS Grade,<br />
FROM_UNIXTIME(gg.timemodified) AS TIME<br />
<br />
FROM prefix_course AS c<br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid<br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
JOIN prefix_grade_grades AS gg ON gg.userid = u.id<br />
JOIN prefix_grade_items AS gi ON gi.id = gg.itemid<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
<br />
WHERE gi.courseid = c.id AND gi.itemtype = 'course'<br />
ORDER BY lastname<br />
</code><br />
<br />
===Learner report by Learner with grades===<br />
Which Learners in which course and what are the grades<br />
<code sql><br />
SELECT u.firstname AS 'Name' , u.lastname AS 'Surname', c.fullname AS 'Course', cc.name AS 'Category', <br />
CASE WHEN gi.itemtype = 'Course' <br />
THEN c.fullname + ' Course Total' <br />
ELSE gi.itemname <br />
END AS 'Item Name', ROUND(gg.finalgrade,2) AS Score,ROUND(gg.rawgrademax,2) AS Max, ROUND(gg.finalgrade / gg.rawgrademax * 100 ,2) as Percentage,<br />
<br />
if (ROUND(gg.finalgrade / gg.rawgrademax * 100 ,2) > 79,'Yes' , 'No') as Pass<br />
<br />
FROM prefix_course AS c <br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid <br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id <br />
JOIN prefix_user AS u ON u.id = ra.userid <br />
JOIN prefix_grade_grades AS gg ON gg.userid = u.id <br />
JOIN prefix_grade_items AS gi ON gi.id = gg.itemid <br />
JOIN prefix_course_categories AS cc ON cc.id = c.category <br />
WHERE gi.courseid = c.id and gi.itemname != 'Attendance'<br />
ORDER BY `Name` ASC<br />
</code><br />
<br />
===User Course Completion===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
A very simple report with a list of course completion status by username. Completions are noted by date, blank otherwise. <br />
<br />
<code sql><br />
SELECT <br />
u.username, <br />
c.shortname, <br />
DATE_FORMAT(FROM_UNIXTIME(p.timecompleted),'%Y-%m-%d') AS completed<br />
FROM prefix_course_completions AS p<br />
JOIN prefix_course AS c ON p.course = c.id<br />
JOIN prefix_user AS u ON p.userid = u.id<br />
WHERE c.enablecompletion = 1<br />
ORDER BY u.username<br />
</code><br />
<br />
===User Course Completion with Criteria===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
A report with course completions by username, with Aggregation method, Criteria types, and Criteria detail where available.<br />
<br />
<code sql><br />
SELECT u.username AS user, <br />
c.shortname AS course,<br />
DATE_FORMAT(FROM_UNIXTIME(t.timecompleted),'%Y-%m-%d') AS completed,<br />
CASE<br />
WHEN (SELECT a.method FROM prefix_course_completion_aggr_methd AS a WHERE (a.course = c.id AND a.criteriatype IS NULL) = 1) THEN "Any"<br />
ELSE "All"<br />
END AS aggregation,<br />
CASE <br />
WHEN p.criteriatype = 1 THEN "Self"<br />
WHEN p.criteriatype = 2 THEN "By Date"<br />
WHEN p.criteriatype = 3 THEN "Unenrol Status"<br />
WHEN p.criteriatype = 4 THEN "Activity"<br />
WHEN p.criteriatype = 5 THEN "Duration"<br />
WHEN p.criteriatype = 6 THEN "Course Grade"<br />
WHEN p.criteriatype = 7 THEN "Approve by Role"<br />
WHEN p.criteriatype = 8 THEN "Previous Course"<br />
END AS criteriatype,<br />
CASE <br />
WHEN p.criteriatype = 1 THEN "*"<br />
WHEN p.criteriatype = 2 THEN DATE_FORMAT(FROM_UNIXTIME(p.timeend),'%Y-%m-%d')<br />
WHEN p.criteriatype = 3 THEN t.unenroled<br />
WHEN p.criteriatype = 4 THEN <br />
CONCAT('<a target="_new" href="%%WWWROOT%%/mod/',p.module,'/view.php?id=',p.moduleinstance,'">',p.module,'</a>')<br />
WHEN p.criteriatype = 5 THEN p.enrolperiod<br />
WHEN p.criteriatype = 6 THEN CONCAT('Needed: ',ROUND(p.gradepass,2),' Achieved: ',ROUND(t.gradefinal,2)) <br />
WHEN p.criteriatype = 7 THEN p.role<br />
WHEN p.criteriatype = 8 THEN (SELECT pc.shortname FROM prefix_course AS pc WHERE pc.id = p.courseinstance)<br />
END AS criteriadetail <br />
FROM prefix_course_completion_crit_compl AS t<br />
JOIN prefix_user AS u ON t.userid = u.id<br />
JOIN prefix_course AS c ON t.course = c.id<br />
JOIN prefix_course_completion_criteria AS p ON t.criteriaid = p.id<br />
<br />
</code><br />
<br />
===Courses with Completion Enabled and their settings===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
List of all courses with completion enabled and their Aggregation setting, Criteria types, and Criteria details.<br />
<br />
<code sql><br />
<br />
SELECT c.shortname AS Course, <br />
CASE<br />
WHEN (SELECT a.method FROM prefix_course_completion_aggr_methd AS a WHERE (a.course = t.course AND a.criteriatype IS NULL)) = 2 THEN "All"<br />
ELSE "Any"<br />
END AS Course_Aggregation,<br />
CASE<br />
WHEN t.criteriatype = 1 THEN "Self completion"<br />
WHEN t.criteriatype = 2 THEN "Date done by" <br />
WHEN t.criteriatype = 3 THEN "Unenrolement" <br />
WHEN t.criteriatype = 4 THEN "Activity completion" <br />
WHEN t.criteriatype = 5 THEN "Duration in days" <br />
WHEN t.criteriatype = 6 THEN "Final grade" <br />
WHEN t.criteriatype = 7 THEN "Approve by role" <br />
WHEN t.criteriatype = 8 THEN "Previous course"<br />
END AS Criteria_type,<br />
CASE<br />
WHEN t.criteriatype = 1 THEN "On"<br />
WHEN t.criteriatype = 2 THEN DATE_FORMAT(FROM_UNIXTIME(t.timeend),'%Y-%m-%d')<br />
WHEN t.criteriatype = 3 THEN "On"<br />
WHEN t.criteriatype = 4 THEN<br />
CONCAT('<a target="_new" href="%%WWWROOT%%/mod/',t.module,'/view.php?id=',t.moduleinstance,'">',t.module,'</a>')<br />
WHEN t.criteriatype = 5 THEN ROUND(t.enrolperiod/86400)<br />
WHEN t.criteriatype = 6 THEN ROUND(t.gradepass,2)<br />
WHEN t.criteriatype = 7 THEN (SELECT r.shortname FROM prefix_role AS r WHERE r.id = t.role)<br />
WHEN t.criteriatype = 8 THEN (SELECT pc.shortname FROM prefix_course AS pc WHERE pc.id = t.courseinstance)<br />
END AS Criteria_detail<br />
FROM prefix_course_completion_criteria as t<br />
JOIN prefix_course AS c ON t.course = c.id<br />
WHERE c.enablecompletion = 1<br />
ORDER BY course<br />
</code><br />
<br />
===Course Completion Report with custom dates===<br />
<br />
List of users who completed multiple or single course/s from a start date to end date chosen by the user. The output gives username, name, course name, completion date and score<br />
<br />
<code sql><br />
<br />
SELECT u.username AS 'User Name',<br />
CONCAT(u.firstname , ' ' , u.lastname) AS 'Name',<br />
c.shortname AS 'Course Name', <br />
DATE_FORMAT(FROM_UNIXTIME(p.timecompleted),'%W %e %M, %Y') AS 'Completed Date',<br />
ROUND(c4.gradefinal,2) AS 'Score'<br />
FROM prefix_course_completions AS p<br />
JOIN prefix_course AS c ON p.course = c.id<br />
JOIN prefix_user AS u ON p.userid = u.id<br />
JOIN prefix_course_completion_crit_compl AS c4 ON u.id = c4.userid<br />
WHERE c.enablecompletion = 1 AND (p.timecompleted IS NOT NULL OR p.timecompleted !='') <br />
AND (p.timecompleted>= :start_date AND p.timecompleted<=:end_date)<br />
GROUP BY u.username<br />
ORDER BY c.shortname<br />
<br />
</code><br />
<br />
===Scales used in activities===<br />
<code sql><br />
SELECT scale.name<br />
,CONCAT('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS Course<br />
,CONCAT('<a target="_new" href="%%WWWROOT%%/mod/',gi.itemmodule,'/view.php?id=',cm.id,'">',gi.itemname,'</a>') AS "Module View"<br />
,CONCAT('<a target="_new" href="%%WWWROOT%%/course/modedit.php?up','date=',cm.id,'">',gi.itemname,'</a>') AS "Module Settings"<br />
<br />
FROM prefix_grade_items AS gi<br />
JOIN prefix_course AS c ON c.id = gi.courseid<br />
JOIN prefix_course_modules AS cm ON cm.course = gi.courseid AND cm.instance = gi.iteminstance<br />
JOIN prefix_scale AS scale ON scale.id = gi.scaleid<br />
WHERE gi.scaleid IS NOT NULL<br />
</code><br />
<br />
<br />
===Extra Credit Items by Name Only===<br />
Contributed by Eric Strom<br />
<br />
This query identifies grade items in visible courses with student enrollment that have "extra credit" in the name of the item but set as extra credit in the grade settings. Includes the defined course start date, count of students and instructors, and a clickable email link of instructor (first found record if more than one).<br />
<br />
<code sql><br />
SELECT DATE(FROM_UNIXTIME(c.startdate)) AS StartDate, <br />
concat('<a target="_new" href="%%WWWROOT%%/grade/edit/tree/index.php',CHAR(63),'id=',<br />
c.id,'">',c.idnumber,'</a>') AS Course_ID, gi.itemname AS Item_Name<br />
<br />
,(SELECT COUNT( ra.userid ) FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = c.id) AS Students<br />
<br />
,(SELECT COUNT( ra.userid ) FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id) AS Instructors<br />
<br />
,(SELECT DISTINCT concat('<a href="mailto:',u.email,'">',u.email,'</a>')<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_user AS u ON ra.userid = u.id<br />
JOIN prefix_context AS ctx ON ctx.id = ra.contextid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id AND ctx.contextlevel = 50 LIMIT 1) AS 'Instructor_Email'<br />
<br />
,now() AS Report_Timestamp<br />
<br />
FROM prefix_grade_items AS gi<br />
JOIN prefix_course AS c ON gi.courseid = c.id<br />
<br />
WHERE gi.itemname LIKE '%extra credit%' <br />
AND gi.gradetype = '1' <br />
AND gi.hidden = '0' <br />
AND gi.aggregationcoef = '0' <br />
AND c.visible = 1<br />
AND (SELECT COUNT( ra.userid ) FROM prefix_role_assignments AS ra JOIN prefix_context AS ctx ON ra.contextid = ctx.id WHERE ra.roleid = 5 AND ctx.instanceid = c.id) > 0<br />
<br />
GROUP BY Course_ID, gi.id<br />
ORDER BY StartDate, Course_ID<br />
<br />
%%FILTER_SEARCHTEXT:Course_ID:~%%<br />
</code><br />
<br />
===Site Wide Number of Courses Completed by User===<br />
Contributed by Ken St. John<br />
<br />
Simple report that shows the number of completed courses for all users site wide<br />
<br />
<code sql><br />
SELECT u.lastname, u.firstname,<br />
COUNT(p.timecompleted) AS TotalCompletions<br />
FROM prefix_course_completions AS p<br />
JOIN prefix_user AS u ON p.userid = u.id<br />
GROUP BY p.userid<br />
ORDER BY u.lastname<br />
</code><br />
<br />
==Activity Module Reports==<br />
<br />
=== User activity completions with dates===<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
This report shows the users completion status of activities across all courses. It is intended to be uses with Configurable Reports filters for user, start and end times, and also to be able to search the Module names. <br />
<br />
Note: The CASE statement with module numbers may differ on different systems, depending on the number give to the module when the site was created or the module added to the site. These are common default numbers, but you should check your id numbers for them in the course_modules table and adjust as required. You can also add other, third-party plugins too if you wish. <br />
<br />
<code sql><br />
SELECT<br />
u.username As 'User',<br />
c.shortname AS 'Course',<br />
m.name AS Activitytype, <br />
CASE <br />
WHEN cm.module = 1 THEN (SELECT a1.name FROM prefix_assign a1 WHERE a1.id = cm.instance)<br />
WHEN cm.module = 2 THEN (SELECT a2.name FROM prefix_assignment a2 WHERE a2.id = cm.instance)<br />
WHEN cm.module = 3 THEN (SELECT a3.name FROM prefix_book a3 WHERE a3.id = cm.instance)<br />
WHEN cm.module = 4 THEN (SELECT a4.name FROM prefix_chat a4 WHERE a4.id = cm.instance)<br />
WHEN cm.module = 5 THEN (SELECT a5.name FROM prefix_choice a5 WHERE a5.id = cm.instance)<br />
WHEN cm.module = 6 THEN (SELECT a6.name FROM prefix_data a6 WHERE a6.id = cm.instance)<br />
WHEN cm.module = 7 THEN (SELECT a7.name FROM prefix_feedback a7 WHERE a7.id = cm.instance)<br />
WHEN cm.module = 8 THEN (SELECT a8.name FROM prefix_folder a8 WHERE a8.id = cm.instance)<br />
WHEN cm.module = 9 THEN (SELECT a9.name FROM prefix_forum a9 WHERE a9.id = cm.instance)<br />
WHEN cm.module = 10 THEN (SELECT a10.name FROM prefix_glossary a10 WHERE a10.id = cm.instance)<br />
WHEN cm.module = 11 THEN (SELECT a11.name FROM prefix_imscp a11 WHERE a11.id = cm.instance)<br />
WHEN cm.module = 12 THEN (SELECT a12.name FROM prefix_label a12 WHERE a12.id = cm.instance)<br />
WHEN cm.module = 13 THEN (SELECT a13.name FROM prefix_lesson a13 WHERE a13.id = cm.instance)<br />
WHEN cm.module = 14 THEN (SELECT a14.name FROM prefix_lti a14 WHERE a14.id = cm.instance)<br />
WHEN cm.module = 15 THEN (SELECT a15.name FROM prefix_page a15 WHERE a15.id = cm.instance)<br />
WHEN cm.module = 16 THEN (SELECT a16.name FROM prefix_quiz a16 WHERE a16.id = cm.instance)<br />
WHEN cm.module = 17 THEN (SELECT a17.name FROM prefix_resource a17 WHERE a17.id = cm.instance)<br />
WHEN cm.module = 18 THEN (SELECT a18.name FROM prefix_scorm a18 WHERE a18.id = cm.instance)<br />
WHEN cm.module = 19 THEN (SELECT a19.name FROM prefix_survey a19 WHERE a19.id = cm.instance)<br />
WHEN cm.module = 20 THEN (SELECT a20.name FROM prefix_url a20 WHERE a20.id = cm.instance)<br />
WHEN cm.module = 21 THEN (SELECT a21.name FROM prefix_wiki a21 WHERE a21.id = cm.instance)<br />
WHEN cm.module = 22 THEN (SELECT a22.name FROM prefix_workshop a22 WHERE a22.id = cm.instance)<br />
END AS Actvityname,<br />
# cm.section AS Coursesection,<br />
CASE<br />
WHEN cm.completion = 0 THEN '0 None'<br />
WHEN cm.completion = 1 THEN '1 Self'<br />
WHEN cm.completion = 2 THEN '2 Auto'<br />
END AS Activtycompletiontype, <br />
CASE<br />
WHEN cmc.completionstate = 0 THEN 'In Progress'<br />
WHEN cmc.completionstate = 1 THEN 'Completed'<br />
WHEN cmc.completionstate = 2 THEN 'Completed with Pass'<br />
WHEN cmc.completionstate = 3 THEN 'Completed with Fail'<br />
ELSE 'Unknown'<br />
END AS 'Progress', <br />
DATE_FORMAT(FROM_UNIXTIME(cmc.timemodified), '%Y-%m-%d %H:%i') AS 'When'<br />
FROM prefix_course_modules_completion cmc <br />
JOIN prefix_user u ON cmc.userid = u.id<br />
JOIN prefix_course_modules cm ON cmc.coursemoduleid = cm.id<br />
JOIN prefix_course c ON cm.course = c.id<br />
JOIN prefix_modules m ON cm.module = m.id<br />
# skip the predefined admin and guest user<br />
WHERE u.id > 2<br />
# config reports filters<br />
%%FILTER_USERS:u.username%%<br />
%%FILTER_SEARCHTEXT:m.name:~%%<br />
%%FILTER_STARTTIME:cmc.timemodified:>%% %%FILTER_ENDTIME:cmc.timemodified:<%%<br />
<br />
ORDER BY u.username<br />
<br />
</code><br />
<br />
===How many SCORM activities are used in each Course===<br />
<code sql><br />
SELECT cm.course,c.fullname ,m.name <br />
,concat('<a target="_new" href="%%WWWROOT%%/mod/scorm/index.php?id=',c.id,'">',count(cm.id),'</a>') AS Counter<br />
<br />
FROM `prefix_course_modules` as cm <br />
JOIN prefix_modules as m ON cm.module=m.id <br />
JOIN prefix_course as c ON cm.course = c.id <br />
WHERE m.name LIKE '%scorm%' <br />
GROUP BY cm.course,cm.module <br />
ORDER BY count(cm.id) desc<br />
</code><br />
<br />
===SCORM Usage by Course Start Date===<br />
Contributed by Elizabeth Dalton, Granite State College <br />
<br />
Report of number of inclusions of SCORM activities in courses, filtered by course start date.<br />
<br />
<code sql><br />
SELECT <br />
<br />
CONCAT('<a target="_blank" href="%%WWWROOT%%/course/view.php',CHAR(63),'id=',c.id,'">',c.shortname,'</a>') AS 'course'<br />
<br />
, cc.name AS 'Category'<br />
, scm.name AS 'Sample Activity Name'<br />
, FROM_UNIXTIME(c.startdate) AS 'Course Start Date'<br />
, COUNT(DISTINCT cm.id) AS 'Resources Used'<br />
#, FROM_UNIXTIME(cm.added) AS 'resource added'<br />
<br />
<br />
FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id AND m.name LIKE 'SCO%'<br />
<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
JOIN prefix_scorm AS scm ON scm.id = cm.instance<br />
<br />
WHERE<br />
1<br />
<br />
%%FILTER_STARTTIME:c.startdate:>%%<br />
%%FILTER_ENDTIME:c.startdate:<%%<br />
<br />
GROUP BY c.shortname, m.name<br />
ORDER BY c.startdate, c.shortname <br />
</code><br />
<br />
=== LTI (External Tool) Usage by Course Start Date===<br />
Contributed by Elizabeth Dalton, Granite State College <br />
<br />
Report of number of inclusions of LTI (External Tool) Usage activities in courses, filtered by course start date.<br />
<br />
<code sql><br />
SELECT <br />
<br />
CONCAT('<a target="_blank" href="%%WWWROOT%%/course/view.php',CHAR(63),'id=',c.id,'">',c.shortname,'</a>') AS 'course'<br />
<br />
, cc.name AS 'Category'<br />
, lti.name AS 'Sample Activity Name'<br />
, FROM_UNIXTIME(c.startdate) AS 'Course Start Date'<br />
, COUNT(DISTINCT cm.id) AS 'Resources Used'<br />
#, FROM_UNIXTIME(cm.added) AS 'resource added'<br />
<br />
<br />
FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id AND m.name LIKE 'lti'<br />
<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
JOIN prefix_lti AS lti ON lti.id = cm.instance<br />
WHERE<br />
1<br />
<br />
%%FILTER_STARTTIME:c.startdate:>%%<br />
%%FILTER_ENDTIME:c.startdate:<%%<br />
<br />
GROUP BY c.shortname, m.name<br />
ORDER BY c.startdate, c.shortname <br />
</code><br />
<br />
===Detailed ACTIONs for each MODULE===<br />
<code sql><br />
SELECT module,action,count(id) as counter<br />
FROM prefix_log<br />
GROUP BY module,action<br />
ORDER BY module,counter desc<br />
</code><br />
<br />
===Most popular ACTIVITY===<br />
<code sql><br />
SELECT COUNT(l.id) hits, module<br />
FROM prefix_log l<br />
WHERE module != 'login' AND module != 'course' AND module != 'role'<br />
GROUP BY module<br />
ORDER BY hits DESC<br />
</code><br />
<br />
===System wide use of ACTIVITIES and RESOURCES===<br />
<code sql><br />
SELECT count( cm.id ) AS counter, m.name<br />
FROM `prefix_course_modules` AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
GROUP BY cm.module<br />
ORDER BY counter DESC<br />
</code><br />
<br />
===LOG file ACTIONS per MODULE per COURSE (IDs)===<br />
<code sql><br />
select course,module,action,count(action) as summa from prefix_log<br />
where action <> 'new'<br />
group by course,action,module<br />
order by course,module,action<br />
</code><br />
<br />
===System Wide usage count of various course Activities===<br />
(Tested and works fine in Moodle 2.x)<br />
Like: Forum, Wiki, Blog, Assignment, Database,<br />
#Within specific category<br />
#Teacher name in course<br />
<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') as Course<br />
<br />
,(SELECT CONCAT(u.firstname,' ', u.lastname) AS Teacher<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS Teacher <br />
<br />
,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%') AS Wikis<br />
,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
WHERE cm.course = c.id AND m.name LIKE '%blog%') AS Blogs<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
WHERE cm.course = c.id AND m.name LIKE '%forum%') AS Forums<br />
<br />
,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
WHERE cm.course = c.id AND m.name LIKE '%data%') AS Databses<br />
<br />
,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
WHERE cm.course = c.id AND m.name LIKE '%assignment%') AS Assignments<br />
<br />
,(SELECT Count( ra.userid ) AS Users FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = c.id) AS Students<br />
<br />
FROM prefix_course AS c<br />
WHERE c.category IN ( 18)<br />
ORDER BY Wikis DESC,Blogs DESC, Forums DESC<br />
</code><br />
<br />
===Course wiki usage/activity over the last 6 semesters===<br />
<code sql><br />
SELECT "Courses with Wikis"<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%'<br />
and c.fullname LIKE CONCAT('%','2010','%') and c.fullname LIKE '%Semester A%') AS '2010 <br/> Semester A'<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%'<br />
and c.fullname LIKE CONCAT('%','2010','%') and c.fullname LIKE '%Semester B%') AS '2010 <br/> Semester B'<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%'<br />
and c.fullname LIKE CONCAT('%','תשעא','%') and c.fullname LIKE '%סמסטר א%') AS 'תשעא <br/> סמסטר א'<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%'<br />
and c.fullname LIKE CONCAT('%','תשעא','%') and c.fullname LIKE '%סמסטר ב%') AS 'תשעא <br/> סמסטר ב'<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%'<br />
and c.fullname LIKE CONCAT('%','תשעב','%') and c.fullname LIKE '%סמסטר א%') AS 'תשעב <br/> סמסטר א'<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%'<br />
and c.fullname LIKE CONCAT('%','תשעב','%') and c.fullname LIKE '%סמסטר ב%') AS 'תשעב <br/> סמסטר ב'<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%'<br />
and c.fullname LIKE CONCAT('%','תשעג','%') and c.fullname LIKE '%סמסטר א%') AS 'תשעג <br/> סמסטר א'<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%'<br />
and c.fullname LIKE CONCAT('%','תשעג','%') and c.fullname LIKE '%סמסטר ב%') AS 'תשעג <br/> סמסטר ב'<br />
</code><br />
<br />
===Detailed WIKI activity (per wiki per course)===<br />
Including Number of Students in course (for reference)<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',cm.course,'">',c.fullname,'</a>') as CourseID <br />
,(SELECT Count( ra.userid ) AS Users<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = c.id ) AS Students<br />
,m.name<br />
, ( SELECT count(id) FROM prefix_log WHERE cmid = cm.id AND action LIKE '%updat%' ) as 'UPDAT E'<br />
, ( SELECT count(id) FROM prefix_log WHERE cmid = cm.id AND action LIKE '%annotate%' ) as ANNOTATE<br />
, ( SELECT count(id) FROM prefix_log WHERE cmid = cm.id AND action LIKE '%comment%' ) as COMMENT<br />
, ( SELECT count(id) FROM prefix_log WHERE cmid = cm.id AND action LIKE '%add%' ) as 'A DD'<br />
, ( SELECT count(id) FROM prefix_log WHERE cmid = cm.id AND action LIKE '%edit%' ) as EDIT<br />
, ( SELECT count(id) FROM prefix_log WHERE cmid = cm.id AND action NOT LIKE '%view%' ) as 'All (NO View)'<br />
FROM `prefix_course_modules` as cm <br />
JOIN prefix_modules as m ON cm.module=m.id <br />
JOIN prefix_course as c ON cm.course = c.id <br />
WHERE m.name LIKE '%wiki%'<br />
GROUP BY cm.course,cm.module<br />
ORDER BY 'All (NO View)' DESC<br />
</code><br />
<br />
===Wiki usage, system wide===<br />
(you can filter the output by selecting some specific course categories : "WHERE c.category IN ( 8,13,15)")<br />
<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') as Course<br />
<br />
,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%') AS Wikis<br />
<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.course = c.id AND l.module LIKE '%wiki%') AS 'WikiActivity<br/>ALL'<br />
<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.course = c.id AND l.module LIKE '%wiki%' and l.action LIKE '%add%' ) AS 'WikiActivity<br/>ADD'<br />
<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.course = c.id AND l.module LIKE '%wiki%' and l.action LIKE '%edit%' ) AS 'WikiActivity<br/>EDIT'<br />
<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.course = c.id AND l.module LIKE '%wiki%' and l.action LIKE '%annotate%' ) AS 'WikiActivity<br/>ANNOTATE'<br />
<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.course = c.id AND l.module LIKE '%wiki%' and l.action LIKE '%comments%' ) AS 'WikiActivity<br/>Comments'<br />
<br />
,(SELECT Count( ra.userid ) AS Users FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = c.id) AS Students<br />
<br />
,(SELECT count(*) FROM prefix_ouwiki_pages as ouwp<br />
JOIN prefix_ouwiki as ouw ON ouw.id = ouwp.subwikiid<br />
WHERE ouw.course = c.id GROUP BY ouw.course ) as OUWikiPages<br />
<br />
,(SELECT count( DISTINCT nwp.pagename ) FROM prefix_wiki_pages AS nwp<br />
JOIN prefix_wiki AS nw ON nw.id = nwp.dfwiki WHERE nw.course = c.id ) As NWikiPages<br />
<br />
FROM prefix_course AS c<br />
WHERE c.category IN ( 8,13,15)<br />
HAVING Wikis > 0<br />
ORDER BY 'WikiActivity<br/>ALL' DESC<br />
</code><br />
<br />
===Aggregated Teacher activity by "WEB2" Modules===<br />
(Tested and works fine in Moodle 2.x)<br />
The NV column shows activity without VIEW log activity<br />
<code sql><br />
SELECT ra.userid, u.firstname,u.lastname<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.userid = u.id AND l.module LIKE '%wiki%') AS Wiki<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.userid = u.id AND l.module LIKE '%wiki%' AND l.action NOT LIKE '%view%') AS Wiki_NV<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.userid = u.id AND l.module LIKE '%forum%') AS Forum<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.userid = u.id AND l.module LIKE '%forum%' AND l.action NOT LIKE '%view%') AS Forum_NV<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.userid = u.id AND l.module LIKE '%blog%') AS Blog<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.userid = u.id AND l.module LIKE '%blog%' AND l.action NOT LIKE '%view%') AS Blog_NV<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.userid = u.id AND l.module LIKE '%assignment%') AS Assignment<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.userid = u.id AND l.module LIKE '%assignment%' AND l.action NOT LIKE '%view%') AS Assignment_NV<br />
FROM prefix_role_assignments AS ra <br />
JOIN prefix_user AS u ON u.id = ra.userid <br />
WHERE ra.roleid = 3 <br />
GROUP BY ra.userid<br />
</code><br />
<br />
===List all the certificates issued, sort by variables in the custom profile fields===<br />
Note: The SQL queries look intimidating at first, but isn't really that difficult to learn. I've seen in the forums that users wanted to do 'site-wide' groups in 1.9x. This is sort of the idea. It pulls all the certificates issued to all users sorted by the custom profile fields, which in my case is the Units or Depts (i.e. my site wide groups). Why certificates? I've explored with both grades and quizzes, the course admins are not really interested in the actual grades but whether the learner received a certificate (i.e. passed the course with x, y, z activities). It also saves me from creating groups and assigning them into the right groups. Even assigning in bulk is not efficient, since I have upward of 25 groups per course and constantly new learners enrolling in courses. The limitation is something to do with the server? as it only pull 5000 rows of data. If anyone figured out how to change this, please let me know. In the meantime, the work around is to pull only a few units/depts at a time to limit the number of rows. This is fine at the moment, since each course admin are only responsible for certain units/depts.<br />
<br />
<code sql><br />
SELECT<br />
DATE_FORMAT( FROM_UNIXTIME(prefix_certificate_issues.timecreated), '%Y-%m-%d' ) AS Date,<br />
prefix_certificate_issues.classname AS Topic,<br />
prefix_certificate.name AS Certificate,<br />
prefix_certificate_issues.studentname as Name,<br />
prefix_user_info_data.data AS Units<br />
<br />
FROM<br />
prefix_certificate_issues<br />
<br />
INNER JOIN prefix_user_info_data<br />
on prefix_certificate_issues.userid = prefix_user_info_data.userid<br />
<br />
INNER JOIN prefix_certificate<br />
on prefix_certificate_issues.certificateid = prefix_certificate.id<br />
<br />
WHERE prefix_user_info_data.data='Unit 1'<br />
OR prefix_user_info_data.data='Unit 2'<br />
OR prefix_user_info_data.data='Unit 3'<br />
<br />
ORDER BY Units, Name, Topic ASC<br />
</code><br />
<br />
<br />
=== All Simple Certificates Earned in the Site===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
Basic report of all certificates earned with the Simple Certificate plugin module in the whole site, sorted by most recent first. (Note: this uses the MySQL [http://www.mysqltutorial.org/mysql-date_format/ DATE_FORMAT] function.)<br />
<br />
<code sql><br />
SELECT<br />
CONCAT (u.firstname, ' ',u.lastname) As 'User',<br />
c.fullname AS 'Course',<br />
sc.name AS 'Certificate',<br />
DATE_FORMAT( FROM_UNIXTIME(sci.timecreated), '%Y-%m-%d' ) As 'Date Awarded'<br />
# sci.code 'CertificateId'<br />
FROM prefix_simplecertificate_issues sci<br />
JOIN prefix_user u ON sci.userid = u.id<br />
JOIN prefix_simplecertificate sc ON sci.certificateid = sc.id<br />
JOIN prefix_course AS c ON sc.course = c.id<br />
ORDER BY sci.timecreated DESC<br />
</code><br />
<br />
If you want to limit this to the most recent ones, you can add a condition to limit it to a certain number of days past. For example, adding this WHERE clause (above the ORDER BY) will show only those earned in the last 30 days:<br />
<code sql><br />
WHERE DATEDIFF(NOW(),FROM_UNIXTIME(sci.timecreated) ) < 30<br />
</code><br />
<br />
===Counter Blog usage in Courses,system wide===<br />
What teachers in what courses, uses blogs and how many + student count in that course.<br />
<code sql><br />
<br />
SELECT ( @counter := @counter+1) as counter, <br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') as Course<br />
<br />
,( SELECT DISTINCT CONCAT(u.firstname,' ',u.lastname)<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_user AS u ON ra.userid = u.id<br />
JOIN prefix_context AS ctx ON ctx.id = ra.contextid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id AND ctx.contextlevel = 50 LIMIT 1) AS Teacher<br />
<br />
,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
WHERE cm.course = c.id AND m.name LIKE '%blog%') AS Blogs<br />
<br />
,(SELECT Count( ra.userid ) AS Users FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = c.id) AS Students<br />
<br />
FROM prefix_course AS c, (SELECT @counter := 0) as s_init<br />
WHERE c.category IN ( 8,13,15)<br />
HAVING Blogs > 0<br />
ORDER BY Blogs DESC<br />
</code><br />
<br />
=== Elluminate (Blackboard Collaborate) - system wide usage===<br />
<code sql><br />
SELECT e.name As Session ,er.recordingsize<br />
,c.fullname As Course<br />
,u.firstname,u.lastname <br />
,DATE_FORMAT(FROM_UNIXTIME(e.timestart),'%d-%m-%Y') AS dTimeStart<br />
,concat('<a target="_new" href="%%WWWROOT%%/moodle/mod/elluminate/loadrecording.php?id=',er.id,'">Show</a>') AS RecordedSession<br />
<br />
FROM prefix_elluminate_recordings AS er<br />
JOIN prefix_elluminate AS e ON e.meetingid = er.meetingid<br />
JOIN prefix_course as c ON c.id = e.course<br />
JOIN prefix_user AS u ON u.id = e.creator <br />
ORDER BY er.recordingsize DESC<br />
</code><br />
<br />
<br />
=== Choice ===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
Results of the Choice activity. For all courses, shows course shortname, username, the Choice text, and the answer chosen by the user.<br />
<br />
<code sql><br />
SELECT c.shortname AS course, u.username, h.name as question, o.text AS answer<br />
FROM prefix_choice AS h<br />
JOIN prefix_course AS c ON h.course = c.id<br />
JOIN prefix_choice_answers AS a ON h.id = a.choiceid<br />
JOIN prefix_user AS u ON a.userid = u.id<br />
JOIN prefix_choice_options AS o ON a.optionid = o.id<br />
</code><br />
<br />
=== Assignment type usage in courses ===<br />
<code sql><br />
SELECT <br />
<br />
CONCAT('<a target="_new" href="%%WWWROOT%%/mod/assign/index.php?id=',c.id,'">',c.fullname,'</a>') AS "List assignments"<br />
<br />
,(SELECT COUNT(*) FROM prefix_assign WHERE c.id = course) AS Assignments<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_assign_plugin_config AS apc<br />
JOIN prefix_assign AS iassign ON iassign.id = apc.assignment <br />
WHERE iassign.course = c.id AND apc.plugin = 'file' AND apc.subtype = 'assignsubmission' AND apc.name = 'enabled' AND apc.value = '1'<br />
#GROUP BY apc.plugin<br />
) AS "File Assignments"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_assign_plugin_config AS apc<br />
JOIN prefix_assign AS iassign ON iassign.id = apc.assignment <br />
WHERE iassign.course = c.id AND apc.plugin = 'onlinetext' AND apc.subtype = 'assignsubmission' AND apc.name = 'enabled' AND apc.value = '1'<br />
) AS "Online Assignments"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_assign_plugin_config AS apc<br />
JOIN prefix_assign AS iassign ON iassign.id = apc.assignment <br />
WHERE iassign.course = c.id AND apc.plugin = 'pdf' AND apc.subtype = 'assignsubmission' AND apc.name = 'enabled' AND apc.value = '1'<br />
) AS "PDF Assignments"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_assign_plugin_config AS apc<br />
JOIN prefix_assign AS iassign ON iassign.id = apc.assignment <br />
WHERE iassign.course = c.id AND apc.plugin = 'offline' AND apc.subtype = 'assignsubmission' AND apc.name = 'enabled' AND apc.value = '1'<br />
) AS "Offline Assignments"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_assign_plugin_config AS apc<br />
JOIN prefix_assign AS iassign ON iassign.id = apc.assignment <br />
WHERE iassign.course = c.id AND apc.plugin = 'comments' AND apc.subtype = 'assignsubmission' AND apc.name = 'enabled' AND apc.value = '1'<br />
) AS "Assignments Comments"<br />
<br />
FROM prefix_assign AS assign<br />
JOIN prefix_course AS c ON c.id = assign.course<br />
GROUP BY c.id <br />
</code><br />
<br />
==Moodle Learning Analytics Reports==<br />
<br />
===Average Cognitive Depth and Social Breadth===<br />
<br />
Here is a simple SQL snippet to calculate average cognitive depth and social breadth indicators for all students in the system. This one ignores indicator values of 0, as they are nulls as defined in this model.<br />
Contributed by Elizabeth Dalton, Moodle HQ<br />
<br />
<code sql><br />
SELECT<br />
<br />
i.contextid,<br />
i.sampleid,<br />
<br />
TRUNC(AVG(CASE<br />
WHEN i.indicator LIKE '%cognitive%' THEN i.value <br />
ELSE '0'<br />
END),2) AS "Average Cognitive Depth",<br />
<br />
TRUNC(AVG(CASE<br />
WHEN i.indicator LIKE '%social%' THEN i.value <br />
ELSE '0'<br />
END),2) AS "Average Social Breadth"<br />
<br />
FROM prefix_analytics_indicator_calc as i<br />
WHERE<br />
i.value != 0<br />
GROUP BY i.contextid, i.sampleid<br />
</code><br />
<br />
==Assignment Module Reports==<br />
===All Ungraded Assignments===<br />
<br />
'''NOTE: This query is for the deprecated old Assignment module from Moodle 2.2, not the new Assignments module. Please update this query if you are the author or it will be removed as the 2.2 Assignment module is no longer supported since release 2.7.<br />
''' See: [https://docs.moodle.org/dev/Moodle_2.7_release_notes#Assignment]<br />
<br />
Returns all the submitted assignments that still need grading<br />
<code sql><br />
select <br />
u.firstname AS "First",<br />
u.lastname AS "Last",<br />
c.fullname AS "Course",<br />
a.name AS "Assignment"<br />
<br />
from prefix_assignment_submissions as asb<br />
join prefix_assignment as a ON a.id = asb.assignment<br />
join prefix_user as u ON u.id = asb.userid<br />
join prefix_course as c ON c.id = a.course<br />
join prefix_course_modules as cm ON c.id = cm.course<br />
<br />
where asb.grade < 0 and cm.instance = a.id<br />
and cm.module = 1<br />
<br />
order by c.fullname, a.name, u.lastname<br />
</code><br />
<br />
===All Ungraded Assignments w/ Link===<br />
<br />
'''NOTE: This query is for the deprecated old Assignment module from Moodle 2.2, not the new Assignments module. Please update this query if you are the author or it will be removed as the 2.2 Assignment module is no longer supported since release 2.7.<br />
''' See: [https://docs.moodle.org/dev/Moodle_2.7_release_notes#Assignment]<br />
<br />
<br />
Returns all the submitted assignments that still need grading, along with a link that goes directly to the submission to grade it. The links work if you view the report within Moodle.<br />
<code sql><br />
select <br />
u.firstname AS "First",<br />
u.lastname AS "Last",<br />
c.fullname AS "Course",<br />
a.name AS "Assignment",<br />
<br />
'<a href="http://education.varonis.com/mod/assignment/submissions.php' + char(63) +<br />
+ 'id=' + cast(cm.id as varchar) + '&userid=' + cast(u.id as varchar) <br />
+ '&mode=single&filter=0&offset=2">' + a.name + '</a>'<br />
AS "Assignmentlink"<br />
<br />
<br />
from prefix_assignment_submissions as asb<br />
join prefix_assignment as a ON a.id = asb.assignment<br />
join prefix_user as u ON u.id = asb.userid<br />
join prefix_course as c ON c.id = a.course<br />
join prefix_course_modules as cm ON c.id = cm.course<br />
<br />
where asb.grade < 0 and cm.instance = a.id and cm.module = 1<br />
<br />
order by c.fullname, a.name, u.lastname<br />
</code><br />
<br />
===Assignments (and Quizzes) waiting to be graded===<br />
<br />
'''NOTE: This query is for the deprecated old Assignment module from Moodle 2.2, not the new Assignments module. Please update this query if you are the author or it will be removed as the 2.2 Assignment module is no longer supported since release 2.7.<br />
''' See: [https://docs.moodle.org/dev/Moodle_2.7_release_notes#Assignment]<br />
<br />
<br />
This report requires a YEAR filter to be added (Available when using the latest block/configurable_reports)<br />
<br />
Which you can always remove, to make this query work on earlier versions.<br />
<br />
The report includes: <br />
*number of quizzes<br />
*unFinished Quiz attempts<br />
*Finished Quiz attempts<br />
*number of students<br />
*number of Assignments<br />
*number of submitted answers by students <br />
*number of unchecked assignments (waiting for the Teacher) in a Course.<br />
<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS Course<br />
<br />
,(SELECT CONCAT(u.firstname,' ', u.lastname) AS Teacher<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS Teacher <br />
<br />
,concat('<a target="_new" href="%%WWWROOT%%/mod/assignment/index.php?id=',c.id,'">מטלות</a>') AS Assignments<br />
<br />
,concat('<a target="_new" href="%%WWWROOT%%/mod/quiz/index.php?id=',c.id,'">בחנים</a>') AS 'Quizzes'<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_course_modules cm <br />
JOIN prefix_modules as m ON m.id = cm.module <br />
WHERE m.name LIKE 'quiz' AND cm.course = c.id <br />
GROUP BY cm.course <br />
) AS 'nQuizzes'<br />
<br />
,(SELECT COUNT(*)<br />
FROM prefix_quiz_attempts AS qa<br />
JOIN prefix_quiz AS q ON q.id = qa.quiz<br />
WHERE q.course = c.id<br />
AND qa.timefinish = 0<br />
GROUP BY q.course) AS 'unFinished Quiz attempts'<br />
<br />
,(SELECT COUNT(*)<br />
FROM prefix_quiz_attempts AS qa<br />
JOIN prefix_quiz AS q ON q.id = qa.quiz<br />
WHERE q.course = c.id<br />
AND qa.timefinish > 0<br />
GROUP BY q.course) AS 'finished quiz attempts'<br />
<br />
,(SELECT Count( ra.userid ) AS Users<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5<br />
AND ctx.instanceid = c.id<br />
) AS nStudents<br />
<br />
<br />
,(<br />
SELECT count(a.id)<br />
FROM prefix_assignment AS a <br />
JOIN prefix_course_modules AS cm ON a.course = cm.course <br />
WHERE cm.instance = a.id AND cm.module = 1 AND a.course = c.id<br />
) nAssignments<br />
<br />
,(<br />
SELECT count(*)<br />
FROM prefix_assignment AS a <br />
WHERE a.course = c.id AND FROM_UNIXTIME(a.timedue) > NOW()<br />
GROUP BY a.course<br />
) 'Open <br/>Assignments'<br />
<br />
, CONCAT(ROUND( (100 / iAssignments ) * iOpenAssignments ) ,'%') 'unFinished <br/>Assignments <br/>(percent)'<br />
<br />
,(<br />
SELECT count(asb.id)<br />
FROM prefix_assignment_submissions AS asb<br />
JOIN prefix_assignment AS a ON a.id = asb.assignment<br />
JOIN prefix_course_modules AS cm ON a.course = cm.course <br />
WHERE asb.grade < 0 AND cm.instance = a.id AND cm.module = 1 AND a.course = c.id<br />
) 'unChecked <br/>Submissions' <br />
<br />
,(<br />
SELECT count(asb.id)<br />
FROM prefix_assignment_submissions AS asb<br />
JOIN prefix_assignment AS a ON a.id = asb.assignment<br />
JOIN prefix_course_modules AS cm ON a.course = cm.course <br />
WHERE cm.instance = a.id AND cm.module = 1 AND a.course = c.id<br />
) 'Submitted <br/>Assignments'<br />
<br />
FROM prefix_course AS c<br />
LEFT JOIN (<br />
SELECT course, count(*) AS iAssignments<br />
FROM prefix_assignment AS a <br />
GROUP BY a.course <br />
) AS tblAssignmentsCount ON tblAssignmentsCount.course = c.id<br />
<br />
LEFT JOIN (<br />
SELECT course, count(*) AS iOpenAssignments<br />
FROM prefix_assignment AS a <br />
WHERE FROM_UNIXTIME(a.timedue) > NOW()<br />
GROUP BY a.course <br />
) AS tblOpenAssignmentsCount ON tblOpenAssignmentsCount.course = c.id<br />
<br />
WHERE 1=1 <br />
#AND c.fullname LIKE '%תשעג%'<br />
%%FILTER_YEARS:c.fullname%%<br />
## You can enable the SEMESTER filter as well, <br />
## by uncommenting the following line:<br />
## %%FILTER_SEMESTERS:c.fullname%%<br />
ORDER BY 'Open <br/>Assignments' DESC<br />
</code><br />
<br />
===Rubrics without zero values in criteria===<br />
Contributed by Eric Strom<br />
<br />
Rubric calculations in Moodle can fail to align with instructors expectations if they lack a zero value for each criterion used in the assessment. From documentation at https://docs.moodle.org/32/en/Rubrics#Grade_calculation:<br />
<br />
"For example, when the teacher in the previous example chose both levels with 1 point, the plain sum would be 2 points. But that is actually the lowest possible score so it maps to the grade 0 in Moodle.<br />
TIP: To avoid confusion from this sort of thing, we recommend including a level with 0 points in every rubric criterion."<br />
<br />
This report identifies rubrics having criteria without a zero value level and the courses they live in. This also refines to only assignments with active rubrics that are visible to students in the course. Links to the each rubric id is the direct link to edit the rubric. Fix by adding a zero level for each criteria that is missing it. In general, the grading changes that result will be in the students' favor.<br />
<br />
Includes search filter of course idnumber.<br />
<br />
<code sql><br />
SELECT cat.name AS Department, concat('<a target="_new" href="%%WWWROOT%%/course/view.php',CHAR(63),'id=',<br />
c.id,'">',c.idnumber,'</a>') AS Course_ID, <br />
c.fullname AS Course_Name, <br />
concat('<a target="_new" href="%%WWWROOT%%/grade/grading/form/rubric/edit.php',CHAR(63),'areaid=',gd.areaid,'">',gd.areaid,'</a>') AS Rubric<br />
FROM prefix_course AS c<br />
JOIN prefix_course_categories AS cat <br />
ON cat.id = c.category<br />
JOIN prefix_course_modules AS cm <br />
ON c.id=cm.course<br />
JOIN prefix_context AS ctx <br />
ON cm.id = ctx.instanceid<br />
JOIN prefix_grading_areas AS garea <br />
ON ctx.id = garea.contextid<br />
JOIN prefix_grading_definitions AS gd <br />
ON garea.id = gd.areaid<br />
JOIN prefix_gradingform_rubric_criteria AS crit <br />
ON gd.id = crit.definitionid<br />
JOIN prefix_gradingform_rubric_levels AS levels <br />
ON levels.criterionid = crit.id<br />
WHERE cm.visible='1' AND garea.activemethod = 'rubric' AND (crit.id NOT IN<br />
(SELECT crit.id<br />
FROM prefix_gradingform_rubric_criteria AS crit<br />
JOIN prefix_gradingform_rubric_levels AS levels <br />
ON levels.criterionid = crit.id WHERE levels.score = '0'))<br />
<br />
GROUP BY Rubric<br />
ORDER BY Course_ID, Rubric<br />
<br />
%%FILTER_SEARCHTEXT:c.idnumber:~%%<br />
</code><br />
<br />
===Who is using "Single File Upload" assignment===<br />
<code sql><br />
SELECT <br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS Course<br />
<br />
,(SELECT CONCAT(u.firstname,' ', u.lastname) AS Teacher<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS Teacher <br />
<br />
,ass.name as "Assignment Name"<br />
<br />
FROM <br />
prefix_assignment as ass<br />
<br />
JOIN <br />
prefix_course as c ON c.id = ass.course<br />
<br />
WHERE `assignmenttype` LIKE 'uploadsingle'<br />
</code><br />
<br />
==Feedback Module Reports==<br />
===List the answers to all the Feedback activities within the current course, submitted by the current user===<br />
<code sql><br />
SELECT /* crs.fullname as "Course name", f.name AS "Journal name", CONCAT(u.firstname,' ',UPPER(u.lastname)) as "Participant", */ /* include these fields if you want to check the composition of the recordset */<br />
DATE_FORMAT(FROM_UNIXTIME(c.timemodified),'%W %e %M, %Y') as "Answer Date",<br />
CASE i.typ WHEN 'label' THEN i.presentation ELSE i.name END as "Topic", /* usually labels are used as section titles, so you'd want them present in the recordset */<br />
v.value as "My Answer"<br />
<br />
FROM prefix_feedback AS f<br />
INNER JOIN prefix_course as crs on crs.id=f.course %%FILTER_COURSES:f.course%% <br />
INNER JOIN prefix_feedback_item AS i ON f.id=i.feedback<br />
INNER JOIN prefix_feedback_completed AS c on f.id=c.feedback %%FILTER_COURSEUSER:c.userid%% <br />
LEFT JOIN prefix_feedback_value AS v on v.completed=c.id AND v.item=i.id<br />
INNER JOIN prefix_user AS u on c.userid=u.id<br />
<br />
WHERE c.id = %%COURSEID%% AND u.id = %%USERID%% AND c.anonymous_response = 1 /* This clause limits the recordset to the current course and the current user and includes/ excludes the anonymous responses as needed */<br />
<br />
ORDER BY f.id, c.timemodified, i.id<br />
</code><br />
<br />
===Show all Feedbacks from all courses for all users including showing names of anonymous users===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
Shows all Feedbacks in all Courses with all multi-choice questions and answers of all users including showing the username of anonymous users. Also shows tryly anonymous users on the front page as 'Not-logged-in' users. This is a rough report, not a pretty report, and is limited to multiple-choice type questions, but is shows the answer number and the list of possible answers in raw form. I post it here as a basis for further reports, and also as away to get the identities of anonymous users if needed.<br />
<br />
<code sql><br />
SELECT <br />
c.shortname AS Course, <br />
f.name AS Feedback,<br />
# i.id AS Itemid,<br />
i.name AS Itemname,<br />
i.label AS Itemlabel,<br />
CASE <br />
WHEN f.anonymous = 1 AND u.id != 0 THEN CONCAT(u.username, ' :ANON')<br />
WHEN fc.userid = 0 THEN 'Not-logged-in'<br />
ELSE u.username<br />
END AS 'User',<br />
DATE_FORMAT(FROM_UNIXTIME(fc.timemodified),'%Y-%m-%d %H:%i') AS "Completed",<br />
v.value AS "Choice",<br />
CASE <br />
WHEN i.typ = 'multichoice' THEN<br />
IF ( SUBSTRING(i.presentation,1,6)='d>>>>>',<br />
SUBSTRING(i.presentation,7),<br />
i.presentation)<br />
ELSE i.presentation<br />
END AS "Answers",<br />
i.typ,<br />
i.dependitem,<br />
i.dependvalue<br />
<br />
FROM prefix_feedback f<br />
JOIN prefix_course c ON c.id=f.course <br />
JOIN prefix_feedback_item AS i ON f.id=i.feedback<br />
JOIN prefix_feedback_completed fc ON f.id=fc.feedback<br />
LEFT JOIN prefix_feedback_value v ON v.completed=fc.id AND v.item=i.id<br />
LEFT JOIN prefix_user AS u ON fc.userid=u.id<br />
WHERE i.typ != 'pagebreak'<br />
</code><br />
<br />
==Resource Module Reports==<br />
===List "Recently uploaded files"===<br />
see what users are uploading<br />
<code sql><br />
SELECT FROM_UNIXTIME(time,'%Y %M %D %h:%i:%s') as time ,ip,userid,url,info <br />
FROM `prefix_log` <br />
WHERE `action` LIKE 'upload' <br />
ORDER BY `prefix_log`.`time` DESC<br />
</code><br />
<br />
===List Courses that loaded a specific file: "X"===<br />
Did the Teacher (probably) uploaded course's Syllabus ?<br />
<code sql><br />
SELECT c.id, c.fullname FROM `prefix_log` as l <br />
JOIN prefix_course as c ON c.id = l.course <br />
WHERE `action` LIKE '%upload%' AND ( info LIKE '%Syllabus%' OR info LIKE '%Sylabus%' ) GROUP BY c.id<br />
</code><br />
<br />
===All resources that link to some specific external website===<br />
+ link to course<br />
+ who's the teacher<br />
+ link to external resource<br />
<code sql><br />
SELECT<br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS Course<br />
,c.shortname,r.name<br />
,(SELECT CONCAT(u.firstname,' ', u.lastname) AS Teacher<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS Teacher<br />
,concat('<a target="_new" href="%%WWWROOT%%/mod/resource/view.php?id=',r.id,'">',r.name,'</a>') AS Resource<br />
FROM prefix_resource AS r <br />
JOIN prefix_course AS c ON r.course = c.id<br />
WHERE r.reference LIKE 'http://info.oranim.ac.il/home%' <br />
</code><br />
<br />
==="Compose Web Page" RESOURCE count===<br />
<code sql><br />
SELECT course,prefix_course.fullname, COUNT(*) AS Total<br />
FROM `prefix_resource`<br />
JOIN `prefix_course` ON prefix_course.id = prefix_resource.course<br />
WHERE type='html'<br />
GROUP BY course<br />
</code><br />
<br />
===Resource count in courses===<br />
+ (First)Teacher name<br />
+ Where course is inside some specific Categories<br />
<code sql><br />
SELECT <br />
COUNT(*) AS count<br />
,r.course <br />
,c.shortname shortname<br />
,c.fullname coursename<br />
,( SELECT DISTINCT CONCAT(u.firstname,' ',u.lastname)<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_user as u ON ra.userid = u.id<br />
JOIN prefix_context AS ctx ON ctx.id = ra.contextid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = r.course AND ctx.contextlevel = 50 LIMIT 1) AS Teacher<br />
FROM prefix_resource r <br />
JOIN prefix_course c ON r.course = c.id<br />
WHERE c.category IN (10,13,28,18,26)<br />
GROUP BY r.course<br />
ORDER BY COUNT(*) DESC<br />
</code><br />
<br />
===Delete all the automated backup files===<br />
Prepare bash cli script to delete all the automated backup files on the file system. (clean up some disk space)<br />
<code sql><br />
SELECT CONCAT( 'rm -f /var/moodledatanew/filedir/', SUBSTRING( contenthash, 1, 2 ) , '/', SUBSTRING( contenthash, 3, 2 ) , '/', contenthash ) <br />
FROM `mdl_files` <br />
WHERE `filename` LIKE '%mbz%'<br />
AND filearea = 'automated'<br />
</code><br />
<br />
Find out how much disk space is used by all automated backup files:<br />
<code sql><br />
SELECT SUM(filesize)/(1024*1024*1024) FROM `mdl_files` WHERE `filename` LIKE '%mbz%' AND filearea = 'automated'<br />
</code><br />
<br />
==Forum Module Reports==<br />
===print all User's post in course Forums===<br />
%%COURSEID%% is a variable the is replace by the current CourseID you are running the sql report from. if you are using the latest block/configurable_reports ! (You can always change it to a fixed course or remove it to display all courses.)<br />
<code sql><br />
SELECT <br />
concat('<a target="_new" href="%%WWWROOT%%/mod/forum/user.php?course=',c.id,'&id=',u.id,'&mode=posts">',CONCAT(u.firstname,' ', u.lastname),'</a>') As Fullname<br />
,concat('<a target="_new" href="%%WWWROOT%%/mod/forum/view.php?f=',fd.forum,'">',f.name,'</a>') AS Forum<br />
,count(*) as Posts<br />
,(SELECT count(*) FROM prefix_forum_discussions AS ifd JOIN prefix_forum as iforum ON iforum.id = ifd.forum WHERE ifd.userid = fp.userid AND iforum.id = f.id) AS cAllDiscussion<br />
<br />
FROM prefix_forum_posts AS fp <br />
JOIN prefix_user as u ON u.id = fp.userid <br />
JOIN prefix_forum_discussions AS fd ON fp.discussion = fd.id <br />
JOIN prefix_forum AS f ON f.id = fd.forum <br />
JOIN prefix_course as c ON c.id = fd.course <br />
WHERE fd.course = %%COURSEID%% <br />
GROUP BY f.id,u.id<br />
ORDER BY u.id<br />
</code><br />
<br />
===FORUM use Count per COURSE -- not including NEWS Forum!===<br />
<code sql><br />
SELECT prefix_course.fullname, prefix_forum.course, count(*) as total FROM prefix_forum<br />
INNER JOIN prefix_course<br />
ON prefix_course.id = prefix_forum.course<br />
WHERE NOT(prefix_forum.type = 'news')<br />
GROUP BY prefix_forum.course<br />
ORDER BY total desc<br />
</code><br />
<br />
===FORUM use Count per COURSE by type -- not including NEWS Forum!===<br />
<code sql><br />
SELECT prefix_course.fullname, prefix_forum.course, prefix_forum.type, count(*) as total FROM prefix_forum<br />
INNER JOIN prefix_course<br />
ON prefix_course.id = prefix_forum.course<br />
WHERE NOT(prefix_forum.type = 'news')<br />
GROUP BY prefix_forum.course,prefix_forum.type<br />
ORDER BY total desc<br />
</code><br />
<br />
===Forum activity - system wide===<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.id,'</a>') AS CourseID<br />
,( SELECT DISTINCT CONCAT(u.firstname,' ',u.lastname)<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_user AS u ON ra.userid = u.id<br />
JOIN prefix_context AS ctx ON ctx.id = ra.contextid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id AND ctx.contextlevel = 50 LIMIT 1) AS Teacher<br />
,c.fullname as Course<br />
,f.type<br />
,(SELECT Count( ra.userid ) AS Users FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = c.id) AS Students<br />
, fd.forum, f.name,count(*) AS cPostAndDisc<br />
,(SELECT count(*) FROM prefix_forum_discussions AS ifd WHERE ifd.forum = f.id) AS cDiscussion<br />
FROM prefix_forum_posts AS fp<br />
JOIN prefix_forum_discussions AS fd ON fd.id = fp.discussion<br />
JOIN prefix_forum AS f ON f.id = fd.forum<br />
JOIN prefix_course AS c ON c.id = f.course<br />
WHERE f.type != 'news' AND c.fullname LIKE '%2013%'<br />
## WHERE 1=1 <br />
## %%FILTER_YEARS:c.fullname%%<br />
## You can enable the SEMESTER filter as well, <br />
## by uncommenting the following line:<br />
## %%FILTER_SEMESTERS:c.fullname%%<br />
<br />
GROUP BY fd.forum<br />
ORDER BY count( * ) DESC<br />
</code><br />
<br />
===Activity In Forums===<br />
Trying to figure out how much real activity we have in Forums by aggregating:<br />
Users in Course, Number of Posts, Number of Discussions, Unique student post, Unique student discussions, Number of Teachers , Number of Students, ratio between unique Student posts and the number of students in the Course...<br />
<code sql><br />
SELECT c.fullname,f.name,f.type <br />
,(SELECT count(id) FROM prefix_forum_discussions as fd WHERE f.id = fd.forum) as Discussions<br />
,(SELECT count(distinct fd.userid) FROM prefix_forum_discussions as fd WHERE fd.forum = f.id) as UniqueUsersDiscussions<br />
,(SELECT count(fp.id) FROM prefix_forum_discussions fd JOIN prefix_forum_posts as fp ON fd.id = fp.discussion WHERE f.id = fd.forum) as Posts<br />
,(SELECT count(distinct fp.userid) FROM prefix_forum_discussions fd JOIN prefix_forum_posts as fp ON fd.id = fp.discussion WHERE f.id = fd.forum) as UniqueUsersPosts<br />
,(SELECT Count( ra.userid ) AS Students<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid =5<br />
AND ctx.instanceid = c.id<br />
) AS StudentsCount<br />
,(SELECT Count( ra.userid ) AS Teachers<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid =3<br />
AND ctx.instanceid = c.id<br />
) AS 'Teacher<br/>Count'<br />
,(SELECT Count( ra.userid ) AS Users<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid IN (3,5)<br />
AND ctx.instanceid = c.id<br />
) AS UserCount<br />
, (SELECT (UniqueUsersDiscussions / StudentsCount )) as StudentDissUsage<br />
, (SELECT (UniqueUsersPosts /StudentsCount)) as StudentPostUsage<br />
FROM prefix_forum as f <br />
JOIN prefix_course as c ON f.course = c.id<br />
WHERE `type` != 'news'<br />
ORDER BY StudentPostUsage DESC<br />
</code><br />
<br />
===All Forum type:NEWS===<br />
<code sql><br />
SELECT f.id, f.name<br />
FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_forum AS f ON cm.instance = f.id<br />
WHERE m.name = 'forum'<br />
AND f.type = 'news'<br />
</code><br />
<br />
===All new forum NEWS items (discussions) from all my Courses===<br />
change "userid = 26" and "id = 26" to a new user id<br />
<code sql><br />
SELECT c.shortname,f.name,fd.name,FROM_UNIXTIME(fd.timemodified ,"%d %M %Y ") as Date<br />
FROM prefix_forum_discussions as fd <br />
JOIN prefix_forum as f ON f.id = fd.forum <br />
JOIN prefix_course as c ON c.id = f.course <br />
JOIN prefix_user_lastaccess as ul ON (c.id = ul.courseid AND ul.userid = 26)<br />
WHERE fd.timemodified > ul.timeaccess <br />
AND fd.forum IN (SELECT f.id<br />
FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_forum AS f ON cm.instance = f.id<br />
WHERE m.name = 'forum'<br />
AND f.type = 'news')<br />
AND c.id IN (SELECT c.id<br />
FROM prefix_course AS c<br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid<br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE u.id = 26) ORDER BY `fd`.`timemodified` DESC<br />
</code><br />
<br />
<br />
===News Forum - Discussions COUNT===<br />
Which is actually... How much instructions students get from their teachers<br />
<code sql><br />
SELECT c.shortname ,<br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS Course<br />
,( SELECT DISTINCT CONCAT(u.firstname,' ',u.lastname)<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_user AS u ON ra.userid = u.id<br />
JOIN prefix_context AS ctx ON ctx.id = ra.contextid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id AND ctx.contextlevel = 50 LIMIT 1) AS Teacher<br />
,concat('<a target="_new" href="%%WWWROOT%%/mod/forum/view.php?f=',fd.forum,'">',count(fd.id),'</a>') AS DiscussionsSum<br />
FROM prefix_forum_discussions AS fd<br />
INNER JOIN prefix_forum AS f ON f.id = fd.forum<br />
INNER JOIN prefix_course AS c ON c.id = f.course<br />
WHERE f.type = 'news' AND c.category IN (10,13,28,18,26)<br />
GROUP BY fd.forum<br />
ORDER BY count(fd.id) DESC<br />
</code><br />
<br />
===Cantidad de foros que han sido posteados por profesor===<br />
<br />
(Number of forums that have been posted by teacher/Google translator)<br />
<br />
Queriamos saber cuales son las acciones del profesor dentro de los foros de cada curso, por ello se hizo este informe.<br />
<br />
(We wanted to know what the teacher's actions are in the forums of each course, so this report was made. /Google translator)<br />
<code sql><br />
SELECT <br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.shortname,'</a>') AS curso,<br />
CONCAT(u.firstname ,' ',u.lastname) AS Facilitador,<br />
<br />
(SELECT COUNT( m.name ) AS COUNT FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
WHERE cm.course = c.id AND m.name LIKE '%forum%') AS foros,<br />
<br />
COUNT(*) AS Posts<br />
<br />
FROM prefix_forum_posts AS fp <br />
JOIN prefix_forum_discussions AS fd ON fp.discussion = fd.id <br />
JOIN prefix_forum AS f ON f.id = fd.forum <br />
JOIN prefix_course AS c ON c.id = fd.course<br />
JOIN prefix_user AS u ON u.id = fp.userid <br />
<br />
WHERE fp.userid =<br />
(<br />
select distinct prefix_user.id<br />
from prefix_user <br />
join prefix_role_assignments as ra on ra.userid = prefix_user.id <br />
where ra.roleid = 3 <br />
and userid = fp.userid<br />
limit 1<br />
)<br />
<br />
and c.shortname like '%2014-2-1%'<br />
GROUP BY c.id, u.id<br />
</code><br />
<br />
<br />
===List all the Posts in all the Forums that got high rating===<br />
We setup a scale that let teachers and students Rate forum post with "Important, interesting, valuable, not rated" scale<br />
And then add a link to the following report at the begining of the course "Link to all interesting posts"<br />
<code sql><br />
SELECT <br />
CONCAT('<a target="_new" href="%%WWWROOT%%/mod/forum/view.php?f=',f.id,'">',f.name,'</a>') AS 'Forum name,<br />
CONCAT('<a target="_new" href="%%WWWROOT%%/mod/forum/discuss.php?d=',fd.id,'#p',fp.id,'">',fp.subject,'</a>') AS 'Post link',<br />
SUM(r.rating) AS 'Rating'<br />
FROM mdl_rating AS r<br />
JOIN mdl_forum_posts AS fp ON fp.id = r.itemid<br />
JOIN mdl_forum_discussions AS fd ON fd.id = fp.discussion<br />
JOIN mdl_forum AS f ON f.id = fd.forum<br />
WHERE r.component = 'mod_forum' AND r.ratingarea = 'post' AND f.course = %%COURSEID%%<br />
GROUP BY r.itemid<br />
ORDER BY SUM(r.rating) DESC<br />
</code><br />
<br />
===List all the Posts in all Discussions of a single Forum===<br />
This report is used to help export all the student's posts and discussions of a single forum, by passing the context module id as a parameter to the report using "&filter_var=cmid"<br />
<code sql><br />
SELECT <br />
CONCAT('<a target="_new" href="%%WWWROOT%%/mod/forum/view.php?f=', f.id, '">', f.name, '</a>') AS 'Forum name',<br />
fd.name AS 'Discussion', <br />
CONCAT('<a target="_new" href="%%WWWROOT%%/mod/forum/discuss.php?d=', fd.id, '#p', fp.id, '">', fp.subject, '</a>') AS 'Post (link)',<br />
fp.message<br />
<br />
FROM mdl_forum_posts AS fp <br />
JOIN mdl_forum_discussions AS fd ON fd.id = fp.discussion<br />
JOIN mdl_forum AS f ON f.id = fd.forum<br />
JOIN mdl_course_modules AS cm ON cm.module = 9 AND cm.instance = f.id<br />
WHERE cm.id = %%FILTER_VAR%%<br />
ORDER BY f.id, fd.id<br />
</code><br />
<br />
==Quiz Module Reports==<br />
===Generate a list of instructors and their email addresses for those courses that has "essay questions" in their quizzes===<br />
<code sql><br />
SELECT qu.id AS quiz_id, qu.course AS course_id, qu.questions,<br />
co.fullname AS course_fullname, co.shortname AS course_shortname,<br />
qu.name AS quiz_name, FROM_UNIXTIME(qu.timeopen) AS quiz_timeopen, FROM_UNIXTIME(qu.timeclose) AS quiz_timeclose,<br />
u.firstname, u.lastname, u.email,<br />
FROM prefix_quiz qu, prefix_course co, prefix_role re, prefix_context ct, prefix_role_assignments ra, prefix_user u<br />
WHERE FROM_UNIXTIME(timeopen) > '2008-05-14' AND<br />
qu.course = co.id AND<br />
co.id = ct.instanceid AND<br />
ra.roleid = re.id AND<br />
re.name = 'Teacher' AND<br />
ra.contextid = ct.id AND<br />
ra.userid = u.id<br />
<br />
SELECT Count('x') As NumOfStudents<br />
FROM prefix_role_assignments a<br />
JOIN prefix_user u ON userid = u.id<br />
WHERE roleid = 5 AND contextid = (SELECT id FROM prefix_context WHERE instanceid = 668 AND contextlevel = 50)<br />
</code><br />
<br />
===Number of Quizes per Course===<br />
<code sql><br />
SELECT count(*)<br />
,concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS Course<br />
,concat('<a target="_new" href="%%WWWROOT%%/mod/quiz/index.php?id=',c.id,'">Link</a>') AS Quizes<br />
<br />
FROM prefix_course_modules cm<br />
JOIN prefix_course c ON c.id = cm.course<br />
JOIN prefix_modules as m ON m.id = cm.module<br />
WHERE m.name LIKE 'quiz'<br />
GROUP BY c.id<br />
</code><br />
<br />
===List all MultiAnswer (Cloze) Questions===<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/mod/quiz/attempt.php?q=', quiz.id, '">', quiz.name, '</a>') AS Quiz<br />
,question.id question_id, question.questiontext <br />
FROM prefix_question question<br />
JOIN prefix_quiz_question_instances qqi ON question.id = qqi.question<br />
JOIN prefix_quiz quiz ON qqi.quiz = quiz.id<br />
WHERE `qtype` LIKE 'multianswer'<br />
</code><br />
<br />
===List courses with MANUAL grades===<br />
Which is basically and indication to teachers using Moodle to hold offline grades inside Moodle's Gradebook,<br />
So grades could be uploaded into an administrative SIS. Use with Configurable Reports.<br />
<code sql><br />
SELECT COUNT( * )<br />
,concat('<a target="_new" href="%%WWWROOT%%/grade/edit/tree/index.php?showadvanced=1&id=',c.id,'">',c.fullname,'</a>') AS Course<br />
FROM prefix_grade_items AS gi<br />
JOIN prefix_course as c ON c.id = gi.courseid<br />
WHERE `itemtype` = 'manual'<br />
GROUP BY courseid<br />
</code><br />
===List the users that did not took the Quiz===<br />
Do not forget to change "c.id = 14" and q.name LIKE '%quiz name goes here%'<br />
<code sql><br />
SELECT<br />
user2.id AS ID,<br />
ul.timeaccess,<br />
user2.firstname AS Firstname,<br />
user2.lastname AS Lastname,<br />
user2.email AS Email,<br />
user2.username AS IDNumber,<br />
user2.institution AS Institution,<br />
<br />
IF (user2.lastaccess = 0,'never',<br />
DATE_FORMAT(FROM_UNIXTIME(user2.lastaccess),'%Y-%m-%d')) AS dLastAccess<br />
<br />
,(SELECT DATE_FORMAT(FROM_UNIXTIME(timeaccess),'%Y-%m-%d') FROM prefix_user_lastaccess WHERE userid=user2.id AND courseid=c.id) AS CourseLastAccess<br />
<br />
,(SELECT r.name<br />
FROM prefix_user_enrolments AS uenrol<br />
JOIN prefix_enrol AS e ON e.id = uenrol.enrolid<br />
JOIN prefix_role AS r ON e.id = r.id<br />
WHERE uenrol.userid=user2.id AND e.courseid = c.id) AS RoleName<br />
<br />
FROM prefix_user_enrolments AS ue<br />
JOIN prefix_enrol AS e ON e.id = ue.enrolid<br />
JOIN prefix_course AS c ON c.id = e.courseid<br />
JOIN prefix_user AS user2 ON user2 .id = ue.userid<br />
LEFT JOIN prefix_user_lastaccess AS ul ON ul.userid = user2.id<br />
WHERE c.id=14 and ue.userid NOT IN (SELECT qa.userid FROM prefix_quiz_attempts AS qa<br />
JOIN prefix_quiz AS q ON qa.quiz = q.id<br />
JOIN prefix_course AS c ON q.course = c.id<br />
WHERE c.id = 14 AND q.name LIKE '%quiz name goes here%')<br />
</code><br />
<br />
<br />
===List Questions in each Quiz===<br />
<br />
<code sql><br />
SELECT quiz.id,quiz.name, q.id, q.name<br />
FROM mdl_quiz AS quiz<br />
JOIN mdl_question AS q ON FIND_IN_SET(q.id, quiz.questions)<br />
WHERE quiz.course = %%COURSEID%%<br />
ORDER BY quiz.id ASC<br />
</code><br />
<br />
Note: this query does not work in Moodle 2.8. There is no mdl_quiz.questions field. It will need to be rewritten to use the usage/contextid organization.<br />
<br />
===Quiz activity research===<br />
This report was made to extract student full activity in quizzes for an academic research about adapting instructional design teaching methods in online learning. The students do not use the Quiz module as a standard quiz but more as Study booklets or mini courses with embedded questions and hints to assist students evaluate their progress (Similar to what you expect to find in a SCORM activity)<br />
<br />
<code sql><br />
SELECT <br />
cm.course "course_id", cm.id "moduel_id", q.id "quiz_id", q.name "quiz_name",<br />
<br />
CASE q.grademethod<br />
WHEN 1 THEN "GRADEHIGHEST"<br />
WHEN 2 THEN "GRADEAVERAGE"<br />
WHEN 3 THEN "ATTEMPTFIRST"<br />
WHEN 4 THEN "ATTEMPTLAST"<br />
END "grade method"<br />
<br />
, q.attempts "quiz_attempts_allowed", cm.groupmode "group_mode"<br />
, qa.id "attempt_id", qa.state "attempt_state", qa.sumgrades "attempt_grade", qg.grade "user_final_grade", q.grade "quiz_max_grade"<br />
,(SELECT GROUP_CONCAT(g.name) FROM mdl_groups AS g<br />
JOIN mdl_groups_members AS m ON g.id = m.groupid WHERE g.courseid = q.course AND m.userid = u.id) "user_groups",<br />
DATE_FORMAT(FROM_UNIXTIME(qa.timestart), '%d-%m-%Y %h:%k') "attempt_start",<br />
DATE_FORMAT(FROM_UNIXTIME(qa.timefinish), '%d-%m-%Y %h:%k') "attempt_finish",<br />
u.id "user_id", u.firstname, u.lastname,<br />
question.id "question_id", question.name "question_name",<br />
qas.state "question_step_state",qas.fraction "question_grade", qh.hint, question.qtype "question_type"<br />
<br />
FROM mdl_quiz as q<br />
JOIN mdl_course_modules as cm ON cm.instance = q.id and cm.module = 14 <br />
JOIN mdl_quiz_attempts qa ON q.id = qa.quiz<br />
LEFT JOIN mdl_quiz_grades as qg ON qg.quiz = q.id and qg.userid = qa.userid<br />
JOIN mdl_user as u ON u.id = qa.userid<br />
JOIN mdl_question_usages as qu ON qu.id = qa.uniqueid<br />
JOIN mdl_question_attempts as qatt ON qatt.questionusageid = qu.id<br />
JOIN mdl_question as question ON question.id = qatt.questionid<br />
JOIN mdl_question_attempt_steps as qas ON qas.questionattemptid = qatt.id<br />
LEFT JOIN mdl_question_hints as qh ON qh.questionid = q.id<br />
#WHERE q.id = "SOME QUIZ ID"<br />
WHERE cm.course = "SOME COURSE ID"<br />
</code><br />
<br />
===Quiz Usage in Courses by Date===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
This report lists the courses containing quizzes with the course start date between the two values, and provides a summary of the types of questions in the quizzes in each course and whether question randomization and answer randomization functions were used.<br />
<br />
"Multiple Choice" questions include true/false and matching question types.<br />
<br />
"Short Answer" are questions that accept a single phrase.<br />
<br />
"Other" questions include fixed numerical, calculated, essay, and various drag and drop types.<br />
<br />
"Min Quiz Age" and "Max Quiz Age" provide data about the last modified date for the quizzes in the course, compared to the course start date. The values are expressed in units of days. A negative value indicates that a quiz was edited after the start of the course. A value greater than 90 days indicates that the quiz may have been used in an earlier term (cohort) without modification.<br />
<br />
'''Note''': In Configurable Reports, the Date Filter is not applied until the "Apply" button is clicked.<br />
<br />
<code sql><br />
SELECT <br />
<br />
c.shortname AS 'Course'<br />
#, u.lastname AS 'Instructor'<br />
, COUNT(DISTINCT q.id) AS 'Quizzes'<br />
, COUNT(DISTINCT qu.id) AS 'Questions'<br />
, SUM(IF (qu.qtype = 'multichoice', 1, 0 )) + SUM(IF (qu.qtype = 'truefalse', 1, 0 )) + SUM(IF (qu.qtype = 'match', 1, 0 )) AS 'multichoice'<br />
<br />
, SUM(IF (qu.qtype = 'shortanswer', 1, 0 )) AS 'shortanswer'<br />
<br />
, COUNT( qu.id) - SUM(IF (qu.qtype = 'multichoice', 1, 0 )) - SUM(IF (qu.qtype = 'truefalse', 1, 0 )) - SUM(IF (qu.qtype = 'match', 1, 0 )) - SUM(IF (qu.qtype = 'shortanswer', 1, 0 )) AS 'Other'<br />
<br />
, (SUM(IF (qu.qtype = 'multichoice', 1, 0 )) + SUM(IF (qu.qtype = 'truefalse', 1, 0 )) + SUM(IF (qu.qtype = 'match', 1, 0 )))/COUNT( qu.id) AS 'Percent MC'<br />
<br />
#, SUM(IF (qu.qtype = 'numerical', 1, 0 )) AS 'numerical'<br />
#, SUM(IF (qu.qtype LIKE 'calc%', 1, 0 )) AS 'calculated'<br />
#, SUM(IF (qu.qtype = 'random', 1, 0 )) AS 'random'<br />
#, SUM(IF (qu.qtype = 'shortanswer', 1, 0 )) AS 'shortanswer'<br />
#, SUM(IF (qu.qtype = 'essay', 1, 0 )) AS 'essay'<br />
<br />
<br />
, IF(q.shufflequestions > 0,'Yes','No') AS 'Randomized Questions'<br />
, IF(q.shuffleanswers > 0,'Yes','No') AS 'Randomized Answers'<br />
<br />
#, FROM_UNIXTIME(c.startdate) AS 'Course Start Date'<br />
#, FROM_UNIXTIME(MIN(q.timemodified)) AS 'Last Modified'<br />
<br />
#, DATEDIFF(FROM_UNIXTIME(c.startdate),FROM_UNIXTIME(MIN(q.timemodified))) AS 'Quiz age'<br />
<br />
, MIN(DATEDIFF(FROM_UNIXTIME(c.startdate),FROM_UNIXTIME(q.timemodified))) AS 'Min Quiz Age' <br />
, MAX(DATEDIFF(FROM_UNIXTIME(c.startdate),FROM_UNIXTIME(q.timemodified))) AS 'Max Quiz Age' <br />
<br />
#, SUM(IF (DATEDIFF(FROM_UNIXTIME(c.startdate),FROM_UNIXTIME(q.timemodified)) < 90, 1,0)) AS 'new quizzes'<br />
<br />
FROM prefix_quiz AS q<br />
JOIN prefix_course AS c on c.id = q.course<br />
JOIN prefix_quiz_question_instances AS qqi ON qqi.quiz = q.id<br />
LEFT JOIN prefix_question AS qu ON qu.id = qqi.question<br />
<br />
WHERE<br />
1<br />
%%FILTER_STARTTIME:c.startdate:>%% %%FILTER_ENDTIME:c.startdate:<%%<br />
<br />
GROUP BY c.id<br />
<br />
ORDER BY c.shortname<br />
</code><br />
<br />
===Student responses (answers) to quiz questions===<br />
(Contributed by Juan F with help from Tim hunt and fellow Moodlers on the forums)<br />
A report that targets a specific quiz for all of our Biology courses, a summary of all questions and how many students get them right/wrong.<br />
<code sql><br />
SELECT<br />
concat( u.firstname, " ", u.lastname ) AS "Student Name",<br />
u.id,<br />
quiza.userid,<br />
q.course,<br />
q.name,<br />
quiza.attempt,<br />
qa.slot,<br />
que.questiontext AS 'Question',<br />
qa.rightanswer AS 'Correct Answer',<br />
qa.responsesummary AS 'Student Answer'<br />
<br />
FROM mdl_quiz_attempts quiza<br />
JOIN mdl_quiz q ON q.id=quiza.quiz<br />
JOIN mdl_question_usages qu ON qu.id = quiza.uniqueid<br />
JOIN mdl_question_attempts qa ON qa.questionusageid = qu.id<br />
JOIN mdl_question que ON que.id = qa.questionid<br />
JOIN mdl_user u ON u.id = quiza.userid<br />
<br />
WHERE q.name = "BIO 208 Post Test Assessment"<br />
AND q.course = "17926"<br />
<br />
ORDER BY quiza.userid, quiza.attempt, qa.slot<br />
</code><br />
<br />
==SCORM Activity Reports==<br />
<br />
===Lists All completed SCORM activites by Course name===<br />
This report will list all completed attempts for all SCORM activities. It is ordered first by Course name, then student's last name, then student's first name, then attempt number. Please note: the FROM_UNIXTIME command is for MySQL.<br />
<code sql><br />
SELECT u.firstname First,u.lastname Last,c.fullname Course, st.attempt Attempt,st.value Status,FROM_UNIXTIME(st.timemodified,"%m-%d-%Y") Date <br />
FROM prefix_scorm_scoes_track AS st <br />
JOIN prefix_user AS u ON st.userid=u.id<br />
JOIN prefix_scorm AS sc ON sc.id=st.scormid<br />
JOIN prefix_course AS c ON c.id=sc.course<br />
WHERE st.value='completed' <br />
ORDER BY c.fullname, u.lastname,u.firstname, st.attempt<br />
</code><br />
<br />
===Lists SCORM status for all enrolled users by Course name===<br />
This report will list the SCORM status for all users enrolled in the course. It is ordered first by Course name, then student's last name, then student's first name, then attempt number. This can be limited to individual courses by adding to the where clause the course id to report on. <br />
<code sql><br />
SELECT<br />
u.firstname AS First,<br />
u.lastname AS Last, <br />
u.idnumber AS Employee_ID, <br />
u.city AS City,<br />
uid.data AS State,<br />
u.country AS Country,<br />
g.name AS Group_name,<br />
c.fullname AS Course, <br />
st.attempt AS Attempt,<br />
st.value AS Status,<br />
FROM_UNIXTIME(st.timemodified,"%m-%d-%Y") AS Date <br />
<br />
FROM prefix_scorm_scoes_track AS st <br />
JOIN prefix_user AS u ON st.userid=u.id<br />
JOIN prefix_user_info_data AS uid ON uid.userid = u.id <br />
JOIN prefix_scorm AS sc ON sc.id=st.scormid<br />
JOIN prefix_course AS c ON c.id=sc.course<br />
JOIN prefix_groups AS g ON g.courseid = c.id<br />
JOIN prefix_groups_members AS m ON g.id = m.groupid<br />
<br />
WHERE st.element='cmi.core.lesson_status' AND m.userid=u.id<br />
<br />
UNION<br />
<br />
SELECT<br />
user2.firstname AS First,<br />
user2.lastname AS Last,<br />
user2. idnumber AS Employee_ID,<br />
user2.city AS City,<br />
uid.data AS State,<br />
user2.country AS Country,<br />
g.name AS Group_name,<br />
c.fullname AS Course,<br />
"-" AS Attempt,<br />
"not_started" AS Status,<br />
"-" AS Date<br />
<br />
FROM prefix_user_enrolments AS ue<br />
JOIN prefix_enrol AS e ON e.id = ue.enrolid<br />
JOIN prefix_course AS c ON c.id = e.courseid<br />
JOIN prefix_user AS user2 ON user2 .id = ue.userid<br />
JOIN prefix_user_info_data AS uid ON uid.userid = user2.id <br />
JOIN prefix_groups AS g ON g.courseid = c.id<br />
JOIN prefix_groups_members AS m ON g.id = m.groupid<br />
JOIN prefix_scorm AS sc ON sc.course=c.id<br />
Left Join prefix_scorm_scoes_track AS st on st.scormid=sc.id AND st.userid=user2.id<br />
<br />
WHERE st.timemodified IS NULL AND m.userid=user2.id<br />
<br />
ORDER BY Course, Last, First, Attempt<br />
<br />
</code><br />
<br />
== Badges==<br />
<br />
=== All badges issued, by User ===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
This report will show you all the badges on a site that have been issued, both site and all courses, by the username of each user issued a badge. Includes the type of criteria passed (activity, course completion, manual), date issued, date expires, and a direct link to that issued badge page so you can see all the other details for that badge.<br />
<br />
<code sql><br />
SELECT u.username, b.name AS badgename, <br />
CASE<br />
WHEN b.courseid IS NOT NULL THEN<br />
(SELECT c.shortname<br />
FROM prefix_course AS c<br />
WHERE c.id = b.courseid)<br />
WHEN b.courseid IS NULL THEN "*"<br />
END AS Context,<br />
CASE <br />
WHEN t.criteriatype = 1 AND t.method = 1 THEN "Activity Completion (All)"<br />
WHEN t.criteriatype = 1 AND t.method = 2 THEN "Activity Completion (Any)"<br />
WHEN t.criteriatype = 2 AND t.method = 2 THEN "Manual Award"<br />
WHEN t.criteriatype = 4 AND t.method = 1 THEN "Course Completion (All)"<br />
WHEN t.criteriatype = 4 AND t.method = 2 THEN "Course Completion (Any)"<br />
ELSE CONCAT ('Other: ', t.criteriatype)<br />
END AS Criteriatype,<br />
DATE_FORMAT( FROM_UNIXTIME( d.dateissued ) , '%Y-%m-%d' ) AS dateissued,<br />
DATE_FORMAT( FROM_UNIXTIME( d.dateexpire ), '%Y-%m-%d' ) AS dateexpires,<br />
CONCAT ('<a target="_new" href="%%WWWROOT%%/badges/badge.php?hash=',d.uniquehash,'">link</a>') AS Details<br />
FROM prefix_badge_issued AS d <br />
JOIN prefix_badge AS b ON d.badgeid = b.id<br />
JOIN prefix_user AS u ON d.userid = u.id<br />
JOIN prefix_badge_criteria AS t on b.id = t.badgeid <br />
WHERE t.criteriatype <> 0<br />
ORDER BY u.username<br />
</code><br />
<br />
Please note: the FROM_UNIXTIME command is for MySQL.<br />
<br />
=== All badges available in the system, with Earned count ===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
Report of all badges in the system, with badge name and description, context, course shortname if a course badge, whether it is active and available, and a count of how many users have been issued that badge.<br />
<br />
<code sql><br />
SELECT b.id, b.name, b.description,<br />
CASE<br />
WHEN b.type = 1 THEN "System"<br />
WHEN b.type = 2 THEN "Course"<br />
END AS Context, <br />
CASE<br />
WHEN b.courseid IS NOT NULL THEN <br />
(SELECT c.shortname <br />
FROM prefix_course AS c <br />
WHERE c.id = b.courseid)<br />
WHEN b.courseid IS NULL THEN "*"<br />
END AS Course, <br />
CASE<br />
WHEN b.status = 0 OR b.status = 2 THEN "No"<br />
WHEN b.status = 1 OR b.status = 3 THEN "Yes"<br />
WHEN b.status = 4 THEN "x"<br />
END AS Available,<br />
CASE<br />
WHEN b.status = 0 OR b.status = 1 THEN "0"<br />
WHEN b.status = 2 OR b.status = 3 OR b.status = 4 THEN <br />
(SELECT COUNT(*) <br />
FROM prefix_badge_issued AS d<br />
WHERE d.badgeid = b.id<br />
)<br />
END AS Earned<br />
FROM prefix_badge AS b<br />
<br />
</code><br />
<br />
=== Badges Leaderboard ===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
A simple list of usernames and how many badges they have earned overall.<br />
<br />
<code sql><br />
SELECT u.username, (SELECT COUNT(*) FROM prefix_badge_issued AS d WHERE d.userid = u.id) AS earned<br />
FROM prefix_user AS u<br />
ORDER BY earned DESC, u.username ASC<br />
</code><br />
<br />
=== Manage badges (System & Course) ===<br />
<br />
List system wide badges, course and system level badges + a link to relevant "manage badges" page.<br />
<br />
<code sql><br />
SELECT b.id, b.name, b.description <br />
,CASE <br />
WHEN b.type = 1 THEN 'System'<br />
WHEN b.type = 2 THEN 'Course'<br />
END AS Level<br />
,CONCAT('<a target="_new" href="%%WWWROOT%%/badges/index.php?type=', b.type, '&id=',<br />
c.id, '">Manage badges in: ', c.fullname, '</a>') AS Manage <br />
FROM prefix_badge AS b<br />
JOIN prefix_course AS c ON c.id = b.courseid<br />
</code><br />
<br />
==Administrator Reports==<br />
<br />
===Config changes in Export friendly form===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
The Administrative report Config changes is very useful but it would be nice to have it in a format that could be easily exported in one listing. Here is code to do that.<br />
<br />
<code sql><br />
SELECT <br />
DATE_FORMAT( FROM_UNIXTIME( g.timemodified ) , '%Y-%m-%d' ) AS date, <br />
u.username AS user, <br />
g.name AS setting, <br />
CASE <br />
WHEN g.plugin IS NULL THEN "core"<br />
ELSE g.plugin<br />
END AS plugin, <br />
g.value AS new_value, <br />
g.oldvalue AS original_value<br />
FROM prefix_config_log AS g<br />
JOIN prefix_user AS u ON g.userid = u.id<br />
ORDER BY date DESC<br />
</code><br />
<br />
===Cohorts by user===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
How to get a list of all users and which cohorts they belong to.<br />
<br />
<code sql><br />
SELECT u.firstname, u.lastname, h.idnumber, h.name<br />
FROM prefix_cohort AS h<br />
JOIN prefix_cohort_members AS hm ON h.id = hm.cohortid<br />
JOIN prefix_user AS u ON hm.userid = u.id<br />
ORDER BY u.firstname<br />
</code><br />
<br />
===Cohorts with Courses===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
List of all cohorts with name, id, visibility, and which courses they are enrolled in.<br />
<br />
<code sql><br />
SELECT<br />
# h.id,<br />
# e.customint1,<br />
h.name AS Cohort,<br />
h.idnumber AS Cohortid,<br />
CASE <br />
WHEN h.visible = 1 THEN 'Yes'<br />
ELSE '-'<br />
END AS Cohortvisible,<br />
CONCAT('<a target="_new" href="%%WWWROOT%%/course/view.php', CHAR(63),'id=',c.id,'">',c.fullname,'</a>') AS Course<br />
FROM prefix_cohort h<br />
JOIN prefix_enrol e ON h.id = e.customint1<br />
JOIN prefix_course c ON c.id = e.courseid %%FILTER_COURSES:e.courseid%% <br />
WHERE e.enrol = 'cohort' AND e.roleid = 5<br />
</code><br />
<br />
===Courses created And Active courses by Year===<br />
Active courses is counting course that have at least one Hit, And "Active_MoreThan100Hits" counts courses that have at least 100 Hits<br />
<code sql><br />
SELECT <br />
<br />
YEAR( FROM_UNIXTIME( `timecreated` ) ) AS YEAR, COUNT( * ) AS Counter<br />
<br />
, (SELECT COUNT( DISTINCT course ) <br />
FROM prefix_log AS l<br />
WHERE YEAR( FROM_UNIXTIME( l.`time` ) ) = YEAR( FROM_UNIXTIME( `timecreated` ) )<br />
) AS "Active"<br />
<br />
,(SELECT COUNT(*) FROM ( <br />
SELECT COUNT( * ),time <br />
FROM prefix_log AS l <br />
GROUP BY course <br />
HAVING COUNT(*) > 100) AS courses_log<br />
WHERE YEAR( FROM_UNIXTIME( courses_log.`time` ) ) = YEAR( FROM_UNIXTIME( `timecreated` ) )<br />
) AS "Active_MoreThan100Hits"<br />
<br />
FROM `prefix_course` <br />
GROUP BY YEAR( FROM_UNIXTIME( `timecreated` ) ) <br />
</code><br />
<br />
===Users created And Active users by Year===<br />
Active users is counting users that have at least one Hit, And "Active_MoreThan500Hits" counts users that have at least 500 Hits<br />
<code sql><br />
SELECT <br />
<br />
YEAR( FROM_UNIXTIME( `firstaccess` ) ) AS YEAR, COUNT( * ) AS Counter<br />
<br />
, (SELECT COUNT( DISTINCT userid ) <br />
FROM prefix_log AS l<br />
WHERE YEAR( FROM_UNIXTIME( l.`time` ) ) = YEAR( FROM_UNIXTIME( `firstaccess` ) )<br />
) AS "Active"<br />
<br />
,(SELECT COUNT(*) FROM ( <br />
SELECT COUNT( * ),time <br />
FROM prefix_log AS l <br />
GROUP BY userid <br />
HAVING COUNT(*) > 500) AS users_log<br />
WHERE YEAR( FROM_UNIXTIME( users_log.`time` ) ) = YEAR( FROM_UNIXTIME( `firstaccess` ) )<br />
) AS "Active_MoreThan500Hits"<br />
<br />
FROM `prefix_user` <br />
GROUP BY YEAR( FROM_UNIXTIME( `timecreated` ) ) <br />
</code><br />
<br />
===Course Aggregation Report===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
If you are considering upgrading from Moodle 2.6 to 2.8 or later, your grades may be changed. This report can help quantify and identify the courses at risk of changes.<br />
<br />
In particular, be on the lookout for any courses with the following combinations of parameters, which are known to cause changes in calculations:<br />
<br />
# mean of grades set with aggregate with subcategory.<br />
# Simple weighted mean of grades with aggregate with sub category and drop the lowest<br />
# Sum of grades drop the lowest<br />
<br />
Also review:<br />
https://tracker.moodle.org/browse/MDL-48618<br />
https://tracker.moodle.org/browse/MDL-48634<br />
https://tracker.moodle.org/browse/MDL-49257<br />
https://tracker.moodle.org/browse/MDL-50089<br />
https://tracker.moodle.org/browse/MDL-50062<br />
<br />
<code sql><br />
SELECT<br />
<br />
COUNT(c.shortname) AS 'Count of Courses'<br />
<br />
# If you want to display all the courses for each aggregation type, uncomment the next line and change GROUP BY settings<br />
#, c.shortname AS 'course name'<br />
<br />
# If you need to display grade categories for each aggregation type, uncomment the next line and change GROUP BY settings<br />
#, gc.fullname AS 'grade category name'<br />
<br />
, gc.aggregation AS 'aggregation method'<br />
<br />
#These aggregation text strings appear to be hard-coded. I couldn't find a table for them. If you have aggregation types I haven't included here, they'll be blank in your report results.<br />
, CASE gc.aggregation<br />
WHEN 0 THEN 'Mean of Grades'<br />
WHEN 2 THEN 'Median of Grades'<br />
WHEN 6 THEN 'Highest Grade'<br />
WHEN 8 THEN 'Mode of Grades'<br />
WHEN 10 THEN 'Weighted Mean of Grades'<br />
WHEN 11 THEN 'Simple Weighted Mean of Grades'<br />
WHEN 12 THEN 'Mean of Grades (with extra credits)'<br />
WHEN 13 THEN 'Sum of Grades'<br />
END AS 'aggregation name'<br />
<br />
# Note that gc.aggregatesubcats column is eliminated in 2.8 and later per MDL-47503, so comment that line on updated systems or you'll get an error<br />
, gc.keephigh AS 'keep high'<br />
, gc.droplow AS 'dr0p low'<br />
, gc.aggregateonlygraded AS 'Aggregate only graded'<br />
, gc.aggregateoutcomes AS 'aggregate outcomes'<br />
, gc.aggregatesubcats AS 'aggregate subcategories'<br />
<br />
# If you are displaying data about individual courses, you may want to know how old they are<br />
#, FROM_UNIXTIME(c.startdate) AS 'course start date'<br />
<br />
# If you are trying to use this report to check to see if final grades have changed after an upgrade, you might want these data items, but calculations can still change later when the courses are actually viewed. Also, you'll need to uncomment the necessary JOINs below<br />
#, gi.itemname AS 'grade item'<br />
#, gg.finalgrade AS 'final grade'<br />
<br />
FROM<br />
<br />
prefix_course AS c<br />
JOIN prefix_grade_categories AS gc ON gc.courseid = c.id<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
<br />
#LEFT JOIN prefix_grade_items AS gi ON gi.courseid = c.id #AND gi.categoryid=gc.id<br />
#LEFT JOIN prefix_grade_grades AS gg ON gg.itemid = gi.id AND gg.userid = u.id<br />
<br />
WHERE<br />
1<br />
#AND gc.aggregation = 13 #only the dreaded Sum of Grades aggregations<br />
#AND gc.depth = 1 # if for some reason you only want course aggregations, not subcategories<br />
<br />
<br />
GROUP BY gc.aggregation, gc.keephigh, gc.droplow, gc.aggregateonlygraded, gc.aggregateoutcomes, gc.aggregatesubcats<br />
<br />
</code><br />
<br />
=== Running Cron jobs (task_scheduled) ===<br />
<code sql><br />
SELECT classname<br />
,DATE_FORMAT(FROM_UNIXTIME(lastruntime), '%H:%i [%d]') AS 'last'<br />
,DATE_FORMAT(now(), '%H:%i') AS 'now'<br />
,DATE_FORMAT(FROM_UNIXTIME(nextruntime), '%H:%i [%d]') AS 'next'<br />
,DATE_FORMAT(FROM_UNIXTIME(UNIX_TIMESTAMP()-nextruntime), '%i') AS 'next in min'<br />
FROM mdl_task_scheduled<br />
WHERE now() > FROM_UNIXTIME(nextruntime)<br />
</code><br />
<br />
=== All Meta courses with Parent and Child course relationships ===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
This shows the list of courses with Meta course link enrollments in them ('Parent course'), and the courses which are connected to them to provide enrollments ('Child courses').<br />
<br />
<code sql><br />
SELECT <br />
c.fullname AS 'Parent course name',<br />
c.shortname AS 'Parent course shortname',<br />
en.courseid AS 'Parent course id',<br />
(SELECT fullname FROM prefix_course WHERE prefix_course.id = en.customint1) As 'Child course name',<br />
(SELECT shortname FROM prefix_course WHERE prefix_course.id = en.customint1) As 'Child course shortname',<br />
en.customint1 AS 'Child course id'<br />
FROM prefix_enrol en<br />
JOIN prefix_course c ON c.id = en.courseid<br />
WHERE en.enrol = 'meta'<br />
ORDER BY c.fullname<br />
</code><br />
<br />
== Useful sub queries ==<br />
<br />
IN this section please put any short one purpose sub queries that show how common procedures often useful as part of larger queries.<br />
<br />
=== All teachers in the course ===<br />
<br />
<br />
This snippet shows how to get teachers from a course. The contextevel for course objects is 50. And the default Teacher role is role id 3.<br />
<br />
<code sql><br />
,(SELECT GROUP_CONCAT( CONCAT( u.firstname, " ", u.lastname ) ) <br />
FROM prefix_course ic<br />
JOIN prefix_context con ON con.instanceid = ic.id<br />
JOIN prefix_role_assignments ra ON con.id = ra.contextid AND con.contextlevel = 50<br />
JOIN prefix_role r ON ra.roleid = r.id<br />
JOIN prefix_user u ON u.id = ra.userid<br />
WHERE r.id = 3 AND ic.id = c.id<br />
GROUP BY ic.id<br />
) AS TeacherNames<br />
</code><br />
<br />
=== Get custom User profile fields for a user ===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
This snippet of code shows how to connect a user with their custom profile field data. This will list all users with all custom profile fields and data. Custom profile fields have two tables, one for the definition of the profile field (user_info_field) and its settings, and a separate table to hold the data entered by users (user_info_data). <br />
<br />
<code sql><br />
SELECT u.username, uif.name, uid.data<br />
FROM prefix_user AS u<br />
JOIN prefix_user_info_data AS uid ON uid.userid = u.id<br />
JOIN prefix_user_info_field AS uif ON uid.fieldid = uif.id <br />
</code><br />
<br />
If you want to limit it to one of those fields, you can restrict it by shortname of the custom profile field, so:<br />
<br />
<code sql><br />
SELECT u.username, uif.name, uid.data<br />
FROM prefix_user AS u<br />
JOIN prefix_user_info_data AS uid ON uid.userid = u.id<br />
JOIN prefix_user_info_field AS uif ON (uid.fieldid = uif.id AND uif.shortname = 'shortname1')<br />
</code><br />
<br />
will show you only the data from the custom profile field with the shortname 'shortname1'.<br />
<br />
If you want to do this with two or more custom profile fields, you will need to have a JOIN and table alias for each with a restriction for each profile field shortname. Example:<br />
<br />
<code sql><br />
SELECT u.username, d1.data AS 'Profile One', d2.data As 'Profile Two'<br />
FROM prefix_user u<br />
JOIN prefix_user_info_data d1 ON d1.userid = u.id<br />
JOIN prefix_user_info_field f1 ON d1.fieldid = f1.id AND f1.shortname = 'shortname1'<br />
JOIN prefix_user_info_data d2 ON d2.userid = u.id<br />
JOIN prefix_user_info_field f2 ON d2.fieldid = f2.id AND f2.shortname = 'shortname2'<br />
</code><br />
<br />
==== NOTE: Alternate Method ====<br />
<br />
If you have more than a couple of fields you need to use, then this query may time out or not return data due to too many joins. The limit seems to be around 10 custom profile fields. <br />
<br />
Instead you should use an alternate method which uses Subselects for each of the profile fields. Details and sample code are in this forum discussion: https://moodle.org/mod/forum/discuss.php?d=355502#p1434854. A sample of the style is:<br />
<br />
<code sql><br />
SELECT u.username<br />
<br />
,(SELECT d1.data FROM prefix_user_info_data d1<br />
JOIN prefix_user_info_field f1 ON d1.fieldid = f1.id AND f1.shortname = 'shortname1'<br />
WHERE d1.userid = u.id<br />
) AS thefirstfield<br />
<br />
,(SELECT d1.data FROM prefix_user_info_data d1<br />
JOIN prefix_user_info_field f1 ON d1.fieldid = f1.id AND f1.shortname = 'shortname2'<br />
WHERE d1.userid = u.id<br />
) AS thesecondfield<br />
<br />
FROM prefix_user u<br />
</code><br />
<br />
=== How to use Configurable Reports Date Time Filters===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
In the Configurable Reports block, you can set the Time and Date filter to allow you to pick your report Start date/time and End date/time interactively. This will work on any column in a table that is a timestamp.<br />
<br />
Here is a simple example:<br />
<br />
<code sql><br />
SELECT u.username, <br />
DATE_FORMAT(FROM_UNIXTIME(u.firstaccess),'%Y-%m-%d %H:%i') AS 'FirstAccess',<br />
DATE_FORMAT(FROM_UNIXTIME(u.lastaccess),'%Y-%m-%d %H:%i') AS 'LastAccess' <br />
FROM prefix_user u<br />
<br />
WHERE 1=1<br />
%%FILTER_STARTTIME:u.firstaccess:>%% <br />
%%FILTER_ENDTIME:u.lastaccess:<%% <br />
</code><br />
<br />
1) You will need to replace name of the table and column for the filter to use the time and date column you need for your query. In the example above, it filters on the firstaccess and lastaccess columns in the user table. If you were doing a report on course completion, you might put the timecompleted column, and so forth.<br />
<br />
2) You MUST then add the Start / End date filter on the Filters tab of the Report. If you don't, the report will still run, probably, but the filter will be ignored.<br />
<br />
Note: the WHERE 1=1 statement is a peculiarity of the filters in Config reports: if you don't have a WHERE statement in your query already, then you must add this dummy WHERE to keep the statement valid. If you already have a WHERE statement in your code, simply add the %%FILTER%% placeholders after it (and before any GROUP or ORDER BY statements.)<br />
<br />
==See also==<br />
* [https://github.com/jleyva/moodle-configurable_reports_repository Configurable Reports Repository on GitHub]<br />
* [https://moodleschema.zoola.io/index.html Moodle DB schema explorer] - searching and filtering tables, fields and external key connections between tables.<br />
<br />
[[Category:Contributed code]]<br />
<br />
[[es:Reportes específicos hechos por usuarios]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=ad-hoc_contributed_reports&diff=133234ad-hoc contributed reports2019-03-07T08:58:35Z<p>Fox: /* Module activity (Hits) between dates */ Updated for new (since Moodle 2.7) log table</p>
<hr />
<div>{{Sitewide reports}}<br />
==User and Role Report==<br />
<br />
===Count number of distinct learners and teachers enrolled per category (including all its sub categories)===<br />
<code sql>SELECT COUNT(DISTINCT lra.userid) AS learners, COUNT(DISTINCT tra.userid) as teachers<br />
FROM prefix_course AS c #, mdl_course_categories AS cats<br />
LEFT JOIN prefix_context AS ctx ON c.id = ctx.instanceid<br />
JOIN prefix_role_assignments AS lra ON lra.contextid = ctx.id<br />
JOIN prefix_role_assignments AS tra ON tra.contextid = ctx.id<br />
JOIN prefix_course_categories AS cats ON c.category = cats.id<br />
WHERE c.category = cats.id<br />
AND (<br />
cats.path LIKE '%/CATEGORYID/%' #Replace CATEGORYID with the category id you want to count (eg: 80)<br />
OR cats.path LIKE '%/CATEGORYID'<br />
)<br />
AND lra.roleid=5<br />
AND tra.roleid=3</code><br />
<br />
===Detailed ACTIONs for each ROLE (TEACHER, NON-EDITING TEACHER and STUDENT)===<br />
<code sql><br />
SELECT r.name, l.action, COUNT( l.userid ) AS counter<br />
FROM prefix_log AS l<br />
JOIN prefix_context AS context ON context.instanceid = l.course AND context.contextlevel = 50<br />
JOIN prefix_role_assignments AS ra ON l.userid = ra.userid AND ra.contextid = context.id<br />
JOIN prefix_role AS r ON ra.roleid = r.id<br />
WHERE ra.roleid IN ( 3, 4, 5 ) <br />
GROUP BY roleid, l.action<br />
</code><br />
<br />
===Student (user) COUNT in each Course===<br />
Including (optional) filter by: year (if included in course fullname).<br />
<code sql><br />
SELECT CONCAT('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',course.id,'">',course.fullname,'</a>') AS Course<br />
,CONCAT('<a target="_new" href="%%WWWROOT%%/user/index.php?contextid=',context.id,'">Show users</a>') AS Users<br />
, COUNT(course.id) AS Students<br />
FROM prefix_role_assignments AS asg<br />
JOIN prefix_context AS context ON asg.contextid = context.id AND context.contextlevel = 50<br />
JOIN prefix_user AS user ON user.id = asg.userid<br />
JOIN prefix_course AS course ON context.instanceid = course.id<br />
WHERE asg.roleid = 5 <br />
# AND course.fullname LIKE '%2013%'<br />
GROUP BY course.id<br />
ORDER BY COUNT(course.id) DESC<br />
</code><br />
<br />
=== Enrolment count in each Course ===<br />
<br />
Shows the total number of enroled users of all roles in each course. Sorted by course name.<br />
<br />
<code sql><br />
SELECT c.fullname, COUNT(ue.id) AS Enroled<br />
FROM prefix_course AS c <br />
JOIN prefix_enrol AS en ON en.courseid = c.id<br />
JOIN prefix_user_enrolments AS ue ON ue.enrolid = en.id<br />
GROUP BY c.id<br />
ORDER BY c.fullname<br />
</code><br />
<br />
===LIST of all site USERS by COURSE enrollment (Moodle 2.x)===<br />
<br />
<code sql><br />
SELECT<br />
user2.firstname AS Firstname,<br />
user2.lastname AS Lastname,<br />
user2.email AS Email,<br />
user2.city AS City,<br />
course.fullname AS Course<br />
,(SELECT shortname FROM prefix_role WHERE id=en.roleid) as Role<br />
,(SELECT name FROM prefix_role WHERE id=en.roleid) as RoleName<br />
<br />
FROM prefix_course as course <br />
JOIN prefix_enrol AS en ON en.courseid = course.id<br />
JOIN prefix_user_enrolments AS ue ON ue.enrolid = en.id<br />
JOIN prefix_user AS user2 ON ue.userid = user2.id<br />
</code><br />
<br />
===Enrolled users,which did not login into the Course, even once (Moodle 2)===<br />
Designed forMoodle 2 table structure and uses special plugin filter : %%FILTER_SEARCHTEXT:table.field%%<br />
<br />
<code sql><br />
SELECT<br />
user2.id as ID,<br />
ul.timeaccess,<br />
user2.firstname AS Firstname,<br />
user2.lastname AS Lastname,<br />
user2.email AS Email,<br />
user2.city AS City,<br />
user2.idnumber AS IDNumber,<br />
user2.phone1 AS Phone,<br />
user2.institution AS Institution,<br />
<br />
IF (user2.lastaccess = 0,'never',<br />
DATE_FORMAT(FROM_UNIXTIME(user2.lastaccess),'%Y-%m-%d')) AS dLastAccess<br />
<br />
,(SELECT DATE_FORMAT(FROM_UNIXTIME(timeaccess),'%Y-%m-%d') FROM prefix_user_lastaccess WHERE userid=user2.id and courseid=c.id) as CourseLastAccess<br />
<br />
,(SELECT r.name<br />
FROM prefix_user_enrolments AS uenrol<br />
JOIN prefix_enrol AS e ON e.id = uenrol.enrolid<br />
JOIN prefix_role AS r ON e.id = r.id<br />
WHERE uenrol.userid=user2.id and e.courseid = c.id) AS RoleName<br />
<br />
FROM prefix_user_enrolments as ue<br />
JOIN prefix_enrol as e on e.id = ue.enrolid<br />
JOIN prefix_course as c ON c.id = e.courseid<br />
JOIN prefix_user as user2 ON user2 .id = ue.userid<br />
LEFT JOIN prefix_user_lastaccess as ul on ul.userid = user2.id<br />
WHERE c.id=16 AND ul.timeaccess IS NULL<br />
%%FILTER_SEARCHTEXT:user2.firstname%%<br />
</code><br />
<br />
===Role assignments on categories===<br />
<code sql><br />
SELECT <br />
concat('<a target="_new" href="%%WWWROOT%%/course/category.php?id=',cc.id,'">',cc.id,'</a>') AS id,<br />
concat('<a target="_new" href="%%WWWROOT%%/course/category.php?id=',cc.id,'">',cc.name,'</a>') AS category,<br />
cc.depth, cc.path, r.name AS role,<br />
concat('<a target="_new" href="%%WWWROOT%%/user/view.php?id=',usr.id,'">',usr.lastname,'</a>') AS name,<br />
usr.firstname, usr.username, usr.email<br />
FROM prefix_course_categories cc<br />
INNER JOIN prefix_context cx ON cc.id = cx.instanceid<br />
AND cx.contextlevel = '40'<br />
INNER JOIN prefix_role_assignments ra ON cx.id = ra.contextid<br />
INNER JOIN prefix_role r ON ra.roleid = r.id<br />
INNER JOIN prefix_user usr ON ra.userid = usr.id<br />
ORDER BY cc.depth, cc.path, usr.lastname, usr.firstname, r.name, cc.name<br />
</code><br />
<br />
===Permissions Overides on Categories===<br />
(By: [http://moodle.org/mod/forum/discuss.php?d=153059#p712834 Séverin Terrier] )<br />
<code sql><br />
SELECT rc.id, ct.instanceid, ccat.name, rc.roleid, rc.capability, rc.permission, <br />
DATE_FORMAT( FROM_UNIXTIME( rc.timemodified ) , '%Y-%m-%d' ) AS timemodified, rc.modifierid, ct.instanceid, ct.path, ct.depth<br />
FROM `prefix_role_capabilities` AS rc<br />
INNER JOIN `prefix_context` AS ct ON rc.contextid = ct.id<br />
INNER JOIN `prefix_course_categories` AS ccat ON ccat.id = ct.instanceid<br />
AND `contextlevel` =40<br />
</code><br />
<br />
===Lists "Totally Opened Courses" (visible, opened to guests, with no password)===<br />
(By: [http://moodle.org/mod/forum/discuss.php?d=153059#p712837 Séverin Terrier] )<br />
<code sql><br />
SELECT<br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.id,'</a>') AS id,<br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.shortname,'</a>') AS 'Course',<br />
concat('<a target="_new" href="%%WWWROOT%%/enrol/instances.php?id=',c.id,'">Méthodes inscription</a>') AS 'Enrollment plugins',<br />
e.sortorder<br />
FROM prefix_enrol AS e, prefix_course AS c<br />
WHERE e.enrol='guest' AND e.status=0 AND e.password='' AND c.id=e.courseid AND c.visible=1<br />
</code><br />
<br />
===Lists "loggedin users" from the last 120 days===<br />
<code sql><br />
SELECT id,username,FROM_UNIXTIME(`lastlogin`) as days <br />
FROM `prefix_user` <br />
WHERE DATEDIFF( NOW(),FROM_UNIXTIME(`lastlogin`) ) < 120<br />
</code><br />
<br />
''and user count for that same population:''<br />
<code sql><br />
SELECT COUNT(id) as Users FROM `prefix_user` <br />
WHERE DATEDIFF( NOW(),FROM_UNIXTIME(`lastlogin`) ) < 120<br />
</code><br />
<br />
==== Users loggedin within the last 7 days ====<br />
<code sql><br />
SELECT<br />
l.* FROM mdl_logstore_standard_log l<br />
WHERE<br />
l.eventname = '\\core\\event\\user_loggedin'<br />
AND FROM_UNIXTIME(l.timecreated, '%Y-%m-%d') >= DATE_SUB(NOW(), INTERVAL 7 DAY)<br />
<br />
SELECT l.eventname FROM mdl_logstore_standard_log l<br />
GROUP BY l.eventname<br />
</code><br />
<br />
===Lists the users who have only logged into the site once===<br />
<code sql><br />
SELECT id, username, firstname, lastname, idnumber<br />
FROM prefix_user<br />
WHERE prefix_user.deleted = 0<br />
AND prefix_user.lastlogin = 0 <br />
AND prefix_user.lastaccess > 0<br />
</code><br />
<br />
===Students in all courses of some institute===<br />
What is the status (deleted or not) of all Students (roleid = 5) in all courses of some Institute<br />
<code sql><br />
SELECT c.id, c.fullname, u.firstname, u.lastname, u.deleted<br />
FROM prefix_course AS c<br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid<br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE ra.roleid =5<br />
AND ctx.instanceid = c.id<br />
AND u.institution = 'please enter school name here'<br />
</code><br />
<br />
===Full User info (for deleted users)===<br />
Including extra custom profile fields (from prefix_user_info_data)<br />
<code sql><br />
SELECT * <br />
FROM prefix_user as u <br />
JOIN prefix_user_info_data as uid ON uid.userid = u.id <br />
JOIN prefix_user_info_field as uif ON (uid.fieldid = uif.id AND uif.shortname = 'class')<br />
WHERE `deleted` = "1" and `institution`="your school name" and `department` = "your department" and `data` = "class level and number"<br />
</code><br />
<br />
===User's courses===<br />
change "u.id = 2" with a new user id<br />
<code sql><br />
SELECT u.firstname, u.lastname, c.id, c.fullname<br />
FROM prefix_course AS c<br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid<br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE u.id = 2<br />
</code><br />
<br />
===List Users with extra info (email) in current course===<br />
blocks/configurable_reports replaces %%COURSEID%% with course id.<br />
<code sql><br />
SELECT u.firstname, u.lastname, u.email<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS context ON context.id = ra.contextid AND context.contextlevel = 50<br />
JOIN prefix_course AS c ON c.id = context.instanceid AND c.id = %%COURSEID%%<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
</code><br />
<br />
===List Students with enrollment and completion dates in current course===<br />
This is meant to be a "global" report in Configurable Reports containing the following:<br />
firstname, lastname, idnumber, institution, department, email, student enrolment date, student completion date<br />
Note: for PGSQL, use to_timestamp() instead of FROM_UNIXTIME()<br />
Contributed by Elizabeth Dalton, Moodle HQ<br />
<br />
<code sql><br />
SELECT <br />
u.firstname<br />
, u.lastname<br />
, u.idnumber<br />
, u.institution<br />
, u.department<br />
, u.email<br />
, FROM_UNIXTIME(cc.timeenrolled)<br />
, FROM_UNIXTIME(cc.timecompleted)<br />
<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS context ON context.id = ra.contextid AND context.contextlevel = 50<br />
JOIN prefix_course AS c ON c.id = context.instanceid AND c.id = %%COURSEID%%<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
JOIN prefix_course_completions AS cc ON cc.course = c.id AND cc.userid = u.id<br />
</code><br />
<br />
===Special Roles===<br />
<code sql><br />
SELECT ra.roleid,r.name<br />
,concat('<a target="_new" href="%%WWWROOT%%/course/user.php?id=1&user=',ra.userid,'">',u.firstname ,' ',u.lastname,'</a>') AS Username<br />
,concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS Course<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_role AS r ON r.id = ra.roleid<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
JOIN prefix_context AS ctx ON (ctx.id = ra.contextid AND ctx.contextlevel = 50)<br />
JOIN prefix_course AS c ON ctx.instanceid = c.id<br />
WHERE ra.roleid > 6<br />
</code><br />
<br />
===Courses without Teachers===<br />
Actually, shows the number of Teachers in a course.<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') as Course<br />
,(SELECT Count( ra.userid ) AS Users FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id) AS Teachers<br />
FROM prefix_course AS c<br />
ORDER BY Teachers ASC<br />
</code><br />
<br />
===List of users who have been enrolled for more than 4 weeks===<br />
For Moodle 2.2 , by Isuru Madushanka Weerarathna <br />
<code sql><br />
SELECT uenr.userid As User, IF(enr.courseid=uenr.courseid ,'Y','N') As Enrolled, <br />
IF(DATEDIFF(NOW(), FROM_UNIXTIME(uenr.timecreated))>=28,'Y','N') As EnrolledMoreThan4Weeks<br />
FROM prefix_enrol As enr, prefix_user_enrolments AS uenr<br />
WHERE enr.id = uenr.enrolid AND enr.status = uenr.status<br />
</code><br />
<br />
=== List of users with language===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
An issue with systems that do not have their default language set up properly is the need to do a mass change for all users to a localization. A common case is changing default English to American English. <br />
<br />
This will show you the language setting for all users:<br />
<code sql><br />
SELECT username, lang from prefix_user <br />
</code><br />
<br />
NOTE: UPDATE commands require the ability to alter the database directly via tools like Adminer or PHPMyAdmin or other db tools.<br />
<br />
This code will change the setting from 'en' to 'en_us' for all users:<br />
<br />
<code sql><br />
UPDATE prefix_user SET lang = 'en_us' WHERE lang = 'en'<br />
</code><br />
<br />
To do this for only users who have a particular country set, use this as an example:<br />
<code sql><br />
UPDATE prefix_user SET lang = 'en_us' WHERE country = 'US' AND lang = 'en'<br />
</code><br />
<br />
=== List of users with Authentication ===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
Sometimes you need to do mass changes of authentication methods. A common case is changing default manual to LDAP. <br />
<br />
This will show you the Authentication setting for all users:<br />
<code sql><br />
SELECT username, auth from prefix_user <br />
</code><br />
<br />
NOTE: UPDATE commands require the ability to alter the database directly via tools like Adminer or PHPMyAdmin or other db tools. <br />
<br />
This code will change the setting from 'manual' to 'ldap' for all users except for the first two accounts which are Guest and Admin. (WARNING: it is bad practice to change your admin account from manual to an external method as failure of that external method will lock you out of Moodle as admin.)<br />
<br />
<code sql><br />
UPDATE prefix_user SET auth = 'ldap' WHERE auth = 'manual' AND id > 2<br />
</code><br />
<br />
=== Compare role capability and permissions ===<br />
<code sql><br />
SELECT DISTINCT mrc.capability <br />
,(SELECT rc.permission FROM `mdl_role_capabilities` AS rc WHERE rc.capability = mrc.capability <br />
AND rc.roleid = '1' AND rc.contextid = '1') AS Manager<br />
,(SELECT rc.permission FROM `mdl_role_capabilities` AS rc WHERE rc.capability = mrc.capability <br />
AND rc.roleid = '2' AND rc.contextid = '1') AS CourseCreator<br />
,(SELECT rc.permission FROM `mdl_role_capabilities` AS rc WHERE rc.capability = mrc.capability <br />
AND rc.roleid = '3' AND rc.contextid = '1') AS Teacher<br />
,(SELECT rc.permission FROM `mdl_role_capabilities` AS rc WHERE rc.capability = mrc.capability <br />
AND rc.roleid = '4' AND rc.contextid = '1') AS AssistantTeacher<br />
,(SELECT rc.permission FROM `mdl_role_capabilities` AS rc WHERE rc.capability = mrc.capability <br />
AND rc.roleid = '5' AND rc.contextid = '1') AS Student<br />
,(SELECT rc.permission FROM `mdl_role_capabilities` AS rc WHERE rc.capability = mrc.capability <br />
AND rc.roleid = '6' AND rc.contextid = '1') AS Guest<br />
<br />
FROM `mdl_role_capabilities` AS mrc<br />
</code><br />
<br />
=== User's accumulative time spent in course ===<br />
A sum up of the time delta between logstore_standard_log user's records, considering the a 2 hour session limit.<br />
<br />
Uses: current user's id %%USERID%% and current course's id %%COURSEID%% <br />
<br />
And also using a date filter (which can be ignored) <br />
<br />
The extra "User" field is used as a dummy field for the Line chart Series field, in which I use X=id, Series=Type, Y=delta.<br />
<br />
<code sql><br />
SELECT <br />
l.id, <br />
l.timecreated, <br />
DATE_FORMAT(FROM_UNIXTIME(l.timecreated),'%d-%m-%Y') AS dTime,<br />
@prevtime := (SELECT max(timecreated) FROM mdl_logstore_standard_log <br />
WHERE userid = %%USERID%% and id < l.id ORDER BY id ASC LIMIT 1) AS prev_time,<br />
IF (l.timecreated - @prevtime < 7200, @delta := @delta + (l.timecreated-@prevtime),0) AS sumtime,<br />
l.timecreated-@prevtime AS delta,<br />
"User" as type<br />
<br />
FROM prefix_logstore_standard_log as l, <br />
(SELECT @delta := 0) AS s_init <br />
# Change UserID<br />
WHERE l.userid = %%USERID%% AND l.courseid = %%COURSEID%%<br />
%%FILTER_STARTTIME:l.timecreated:>%% %%FILTER_ENDTIME:l.timecreated:<%% <br />
</code><br />
<br />
=== Low-Participation Student Report ===<br />
Contributed by Elizabeth Dalton, Granite State College / Moodle HQ<br />
<br />
This report returns a list of students who are enrolled in courses filtered by a short-name text marker (in this case "OL-") in the specified category, but have very low participation in the course during the specified time period (fewer than 2 "Edits" to Activity Modules, indicating few active contributions to the course). The number of "Edits" is provided for each student for the time period specified.<br />
<br />
An "Edit" is defined as course activity other than viewing content. Click the "Logs" link to review the student activity. The Logs offer the option to review "View" activity as well as "Edit" activity.<br />
<br />
Only "visible" courses are included in this report. The report may be downloaded as an Excel spreadsheet.<br />
<br />
Don't forget to set up Filters: "Start / End date filter" and "Filter categories" on the Filters tab in Configurable reports.<br />
<br />
<code sql><br />
SELECT u.lastname AS Last, u.firstname AS First, u.idnumber AS IDnumber, u.email AS email, c.shortname AS CourseID, count(l.id) AS Edits, CONCAT('<a target="_new" href="https://learn.granite.edu/report/log/index.php',CHAR(63),'chooselog=1&showusers=1&showcourses=0&id=',c.id,'&user=',u.id,'&date=0&modid=&modaction=-view&logformat=showashtml','">','Logs','</a>') AS Link<br />
<br />
FROM prefix_user AS u<br />
JOIN prefix_role_assignments AS ra ON u.id = ra.userid<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
<br />
LEFT JOIN prefix_log AS l ON l.userid = u.id AND l.course = c.id AND l.action NOT LIKE "view%" %%FILTER_STARTTIME:l.TIME:>%% %%FILTER_ENDTIME:l.TIME:<%%<br />
<br />
WHERE ra.roleid =5<br />
AND ctx.instanceid = c.id<br />
AND c.visible=1<br />
# This prefix filter allows the exclusion of non-online courses at the original institution. Alter this to fit your institution, or remove it.<br />
AND c.shortname LIKE '%OL-%'<br />
%%FILTER_CATEGORIES:c.category%%<br />
<br />
GROUP BY u.idnumber<br />
<br />
HAVING Edits < 2<br />
</code><br />
<br />
=== Messages of All Users in a Specific Course ===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
NOTE: This query will probably not work at all in 3.5 now due to the changes in the structure of the Messages database. - RT<br />
<br />
This query shows the personal messages between users in a specific course, given the course id number. Properly speaking, personal messages pertain only to users and are not part of courses, but by filtering enrollments for roles in a course, you can show this. <br />
<br />
This report as is shows only the messages between Teachers and Students, as the WHERE statement contains and AND ((...))) section that restrict this report to ONLY messages between Teachers (role id = 3) and Students (role id =5). Remove that part of the statement if you wish to see _all_ messages between all users, e.g. teachers to teachers, student to student. <br />
<br />
Also, if you have created custom roles, you can replace the default id numbers with custom ones to further enhance the report.<br />
<br />
<code sql><br />
SELECT <br />
u.username AS 'From',<br />
CONCAT(u.firstname ,' ',u.lastname) AS 'From Name',<br />
u2.username AS 'To',<br />
CONCAT(u2.firstname ,' ',u2.lastname) AS 'To Name',<br />
DATE_FORMAT(FROM_UNIXTIME(me.timecreated), '%Y-%m-%d %H:%i') AS 'When',<br />
me.subject AS 'Subject', <br />
me.smallmessage AS 'Message'<br />
FROM prefix_message me<br />
JOIN prefix_role_assignments AS ra ON ra.userid = me.useridfrom AND ra.roleid IN (3,4,5) <br />
JOIN prefix_role_assignments AS ra2 ON ra2.userid = me.useridto AND ra2.roleid IN (3,4,5) <br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id AND ra2.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
JOIN prefix_user u ON u.id = me.useridfrom<br />
JOIN prefix_user u2 ON u2.id = me.useridto<br />
WHERE c.id=## <br />
AND ((ra.roleid = 3 AND ra2.roleid = 5) OR (ra.roleid = 5 AND ra2.roleid = 3)) <br />
ORDER BY me.useridfrom, me.useridto, me.timecreated<br />
</code><br />
<br />
==Log Activity Reports==<br />
===Count all Active Users by ROLE in a course category (including all of its sub-categories)===<br />
<code sql><br />
SELECT COUNT(DISTINCT l.userid) as active<br />
FROM mdl_course as c<br />
JOIN mdl_context AS ctx ON ctx.instanceid=c.id<br />
JOIN mdl_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN mdl_user_lastaccess as l ON ra.userid = l.userid<br />
JOIN mdl_course_categories AS cats ON c.category = cats.id<br />
WHERE c.category=cats.id AND (<br />
cats.path LIKE '%/80/%'<br />
OR cats.path LIKE '%/80'<br />
) <br />
AND ra.roleid=3 AND ctx.contextlevel=50 #ra.roleid= TEACHER 3, NON-EDITING TEACHER 4, STUDENT 5<br />
AND l.timeaccess > (unix_timestamp() - ((60*60*24)*NO_OF_DAYS)) #NO_OF_DAYS change to number<br />
</code><br />
===Detailed "VIEW" ACTION for each ROLE (TEACHER,NONE-EDITING TEACHER and STUDENT)===<br />
<code sql><br />
SELECT l.action, count( l.userid ) as counter , r.name<br />
FROM `prefix_log` as l<br />
JOIN `prefix_role_assignments` AS ra on l.userid = ra.userid<br />
JOIN `prefix_role` AS r ON ra.roleid = r.id<br />
WHERE (ra.roleid IN (3,4,5)) AND (l.action LIKE '%view%' )<br />
GROUP BY roleid,l.action<br />
order by r.name,counter desc<br />
</code><br />
<br />
===Total Activity of Roles:"Teacher" and "None-Editing Teacher" by Dates and by Hours===<br />
The output columns of this report table can be used as base for a Pivot-Table<br />
which will show the amount of '''activity''' per '''hour''' per '''days''' in 3D graph view.<br />
<br />
<code sql><br />
SELECT DATE_FORMAT( FROM_UNIXTIME( l.time ) , '%Y-%m-%d' ) AS grptimed ,<br />
DATE_FORMAT( FROM_UNIXTIME( l.time ) , '%k' ) AS grptimeh , count( l.userid ) AS counter <br />
FROM `prefix_log` AS l<br />
JOIN prefix_user AS u ON u.id = l.userid<br />
JOIN prefix_role_assignments AS ra ON l.userid = ra.userid<br />
JOIN prefix_role AS r ON r.id = ra.roleid<br />
WHERE ra.roleid IN (3,4)<br />
GROUP BY grptimed,grptimeh<br />
ORDER BY grptimed,grptimeh<br />
</code><br />
<br />
===How many LOGINs per user and user's Activity===<br />
+ link username to a user activity graph report<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/user.php?id=1&user=',u.id,'&mode=alllogs">',u.firstname ,' ',u.lastname,'</a>') as Username<br />
,count(*) as logins<br />
,(SELECT count(*) FROM prefix_log WHERE userid = l.userid GROUP BY userid) as Activity <br />
FROM prefix_log as l JOIN prefix_user as u ON l.userid = u.id <br />
WHERE `action` LIKE '%login%' group by userid<br />
ORDER BY Activity DESC<br />
</code><br />
===Distinct user logins per month===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
The following will show you the months of the current calendar year with the total number of distinct, unique user logins per month. Change the year in the WHERE clause to the year you need.<br />
<br />
<code sql><br />
SELECT <br />
COUNT(DISTINCT l.userid) AS 'DistinctUserLogins', <br />
DATE_FORMAT(FROM_UNIXTIME(l.timecreated), '%M') AS 'Month'<br />
FROM prefix_logstore_standard_log l<br />
WHERE l.action = 'loggedin' AND YEAR(FROM_UNIXTIME(l.timecreated)) = '2017' <br />
GROUP BY MONTH(FROM_UNIXTIME(l.timecreated))<br />
</code><br />
<br />
===Total activity per course, per unique user on the last 24h===<br />
<code sql><br />
SELECT<br />
COUNT(DISTINCT userid) AS countUsers<br />
, COUNT(l.courseid) AS countVisits<br />
, CONCAT('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">', c.fullname, '</a>') AS Course<br />
<br />
FROM mdl_logstore_standard_log AS l<br />
JOIN mdl_course AS c ON c.id = l.courseid<br />
WHERE l.courseid > 0<br />
AND FROM_UNIXTIME(l.timecreated) >= DATE_SUB(NOW(), INTERVAL 1 DAY)<br />
AND c.fullname LIKE '%תשעו%'<br />
GROUP BY l.courseid<br />
ORDER BY countVisits DESC<br />
</code><br />
<br />
===Weekly Instructor Online Participation===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
Displays participation of instructors in all courses per week of a term, including pre-term and post-term edits. An edit is defined as a change to the course, such as a discussion post, the grading of an assignment, or the uploading of file attachments, as well as alterations to course content.<br />
<br />
* To specify a subject and/or course number, use % as a wildcard, e.g. ARTS% or ARTS501%<br />
* To match part of a last name, use %, e.g. Smi% will match "Smith", "Smile", etc.<br />
<br />
At our institution, we include filters on the course name or category to constrain by terms. These are very specific to how course names and categories are constructed at our institution, so I've removed those elements from this code. Also, our terms are 12 weeks long. You would want to insert additional "SUM" lines for longer terms, or remove lines for shorter terms.<br />
<br />
'''Note''': This report can take a long time to run. While it can be run in Configurable Reports on demand, it may be more appropriate to implement it in the Ad Hoc Queries plugin as a scheduled report.<br />
<br />
'''Note''': This version uses legacy (pre-2.7) logs. See below for post-2.7 Standard Logs version.<br />
<br />
<code sql><br />
SELECT <br />
c.shortname AS CourseID<br />
, cc.name AS Category<br />
, CONCAT(u.firstname ,' ',u.lastname) AS Instructor<br />
<br />
, (SELECT COUNT( ra2.userid ) AS Users2 FROM prefix_role_assignments AS ra2<br />
JOIN prefix_context AS ctx2 ON ra2.contextid = ctx2.id<br />
WHERE ra2.roleid = 5 AND ctx2.instanceid = c.id) AS Students<br />
<br />
, c.startdate AS Course_Start_Date<br />
<br />
, c.visible AS Visible<br />
<br />
, COUNT(l.id) AS Edits<br />
<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time)) - WEEK(FROM_UNIXTIME(c.startdate))<0,1,0)) AS BeforeTerm<br />
<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=0,1,0)) AS Week1<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=1,1,0)) AS Week2<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=2,1,0)) AS Week3<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=3,1,0)) AS Week4<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=4,1,0)) AS Week5<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=5,1,0)) AS Week6<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=6,1,0)) AS Week7<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=7,1,0)) AS Week8<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=8,1,0)) AS Week9<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=9,1,0)) AS Week10<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=10,1,0)) AS Week11<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))=11,1,0)) AS Week12<br />
<br />
, SUM(IF(WEEK(FROM_UNIXTIME(l.time))-WEEK(FROM_UNIXTIME(c.startdate))>=12,1,0)) AS AfterTerm<br />
<br />
, CONCAT('<a target="_new" href="%%WWWROOT%%/report/log/index.php',CHAR(63),'chooselog=1&showusers=1&showcourses=0&id=',c.id,'&user=',u.id,'&date=0&modid=&modaction=&logformat=showashtml','">','Logs','</a>') AS Link<br />
<br />
FROM prefix_user AS u<br />
JOIN prefix_role_assignments AS ra ON u.id = ra.userid<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
JOIN prefix_course_categories as cc ON c.category = cc.id<br />
<br />
LEFT JOIN prefix_log AS l ON l.userid = u.id AND l.course = c.id AND l.action NOT LIKE "view%"<br />
<br />
WHERE ra.roleid =3<br />
AND ctx.instanceid = c.id<br />
AND c.shortname LIKE :course<br />
AND u.lastname LIKE :last_name<br />
<br />
GROUP BY u.idnumber, c.id<br />
HAVING students > 0<br />
ORDER BY c.shortname<br />
</code><br />
<br />
'''Note''': Post-2.7 log version:<br />
<br />
<code sql><br />
SELECT <br />
c.shortname AS CourseID<br />
, cc.name AS Category<br />
, CONCAT(u.firstname ,' ',u.lastname) AS Instructor<br />
<br />
, (SELECT COUNT( ra2.userid ) AS Users2 FROM prefix_role_assignments AS ra2<br />
JOIN prefix_context AS ctx2 ON ra2.contextid = ctx2.id<br />
WHERE ra2.roleid = 5 AND ctx2.instanceid = c.id) AS Students<br />
<br />
, FROM_UNIXTIME(c.startdate) AS Course_Start_Date<br />
<br />
, c.visible AS Visible<br />
<br />
, COUNT(DISTINCT l.id) AS Edits<br />
<br />
, COUNT(DISTINCT IF((l.timecreated-c.startdate)<0,l.id,NULL)) AS 'Before Term'<br />
<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=0,l.id,NULL)) AS 'Week 1'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=1,l.id,NULL)) AS 'Week 2'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=2,l.id,NULL)) AS 'Week 3'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=3,l.id,NULL)) AS 'Week 4'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=4,l.id,NULL)) AS 'Week 5'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=5,l.id,NULL)) AS 'Week 6'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=6,l.id,NULL)) AS 'Week 7'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=7,l.id,NULL)) AS 'Week 8'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=8,l.id,NULL)) AS 'Week 9'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=9,l.id,NULL)) AS 'Week 10'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=10,l.id,NULL)) AS 'Week 11'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=11,l.id,NULL)) AS 'Week 12'<br />
<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))>=12,l.id,NULL)) AS 'After Term'<br />
<br />
, CONCAT('<a target="_new" href="%%WWWROOT%%/report/log/index.php',CHAR(63),'chooselog=1&showusers=1&showcourses=0&id=',c.id,'&user=',u.id,'&date=0&modid=&modaction=&logformat=showashtml','">','Logs','</a>') AS Link<br />
<br />
FROM prefix_user AS u<br />
LEFT JOIN prefix_role_assignments AS ra ON u.id = ra.userid<br />
LEFT JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
LEFT JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
LEFT JOIN prefix_course_categories as cc ON c.category = cc.id<br />
<br />
LEFT JOIN prefix_logstore_standard_log AS l ON l.userid = u.id AND l.courseid = c.id AND l.crud IN ('c','u')<br />
<br />
WHERE ra.roleid =3<br />
AND ctx.instanceid = c.id<br />
AND c.shortname LIKE '%OL-%'<br />
AND cc.idnumber LIKE '%current%'<br />
<br />
GROUP BY u.idnumber, c.id<br />
#HAVING students > 0<br />
ORDER BY RIGHT(c.shortname,2), c.shortname<br />
</code><br />
<br />
===Weekly Student Online Participation===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
Displays participation of students in the current course by week, including pre-term and post-term edits. An edit is defined as a change to the course, such as a discussion post, the submission of an assignment, or the completion of a quiz, as well as alterations to course content such as database entries (if permitted).<br />
<br />
Links to three other reports are also provided:<br />
<br />
* Logs: complete log entries for the student in the course, organized by date<br />
* Activity Outline: the "Outline Report" from the User Activity Reports, summarizing the student's activity in the course, organized by course content<br />
* Consolidated Activity Report: the "Complete Report" from the User Activity Reports, detailing the student's activity in the course, organized by course content (includes text of forum posts)<br />
<br />
'''Note''': This should be defined as a "Global" report (visible from within all courses). At our institution, our terms are 12 weeks long. You would want to insert additional "SUM" lines for longer terms, or remove lines for shorter terms. We pull advisor names into student user profiles as part of our configuration. These lines are present in the code below, but are commented out, as they are very specific to your Moodle configuration.<br />
<br />
'''Note''': This version of the report uses legacy (pre-2.7) logs. See below for a post-2.7 Standard Logs version.<br />
<br />
<code sql><br />
SELECT <br />
u.lastname AS 'Last Name'<br />
, u.firstname AS 'First Name'<br />
, COUNT(l.id) AS 'Edits'<br />
<br />
, SUM(IF((l.time-c.startdate)/7<0,1,0)) AS 'Before Term'<br />
<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=0,1,0)) AS 'Week 1'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=1,1,0)) AS 'Week 2'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=2,1,0)) AS 'Week 3'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=3,1,0)) AS 'Week 4'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=4,1,0)) AS 'Week 5'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=5,1,0)) AS 'Week 6'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=6,1,0)) AS 'Week 7'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=7,1,0)) AS 'Week 8'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=8,1,0)) AS 'Week 9'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=9,1,0)) AS 'Week 10'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=10,1,0)) AS 'Week 11'<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))=11,1,0)) AS 'Week 12'<br />
<br />
, SUM(IF(FLOOR((l.time - c.startdate)/(60*60*24*7))>=15,1,0)) AS 'After Term'<br />
<br />
, CONCAT('<a target="_blank" href="%%WWWROOT%%/report/log/index.php',CHAR(63),'chooselog=1&showusers=1&showcourses=0&id=',c.id,'&user=',u.id,'&date=0&modid=&modaction=&logformat=showashtml','">','Logs','</a>') AS 'Logs'<br />
<br />
, CONCAT('<a target="_blank" href="%%WWWROOT%%/report/outline/user.php',CHAR(63),'id=',u.id,'&course=',c.id,'&mode=outline">','Outline','</a>') AS 'Activity Outline'<br />
<br />
, CONCAT('<a target="_blank" href="%%WWWROOT%%/report/outline/user.php',CHAR(63),'id=',u.id,'&course=',c.id,'&mode=complete">','Activity','</a>') AS 'Consolidated Activity'<br />
<br />
FROM prefix_user AS u<br />
JOIN prefix_role_assignments AS ra ON u.id = ra.userid<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
JOIN prefix_course_categories as cc ON c.category = cc.id<br />
<br />
LEFT JOIN prefix_log AS l ON l.userid = u.id AND l.course = c.id AND l.action NOT LIKE "view%"<br />
<br />
WHERE ra.roleid =5<br />
AND ctx.instanceid = c.id<br />
<br />
AND c.id = %%COURSEID%%<br />
<br />
GROUP BY u.idnumber<br />
<br />
ORDER BY u.lastname, u.firstname<br />
</code><br />
<br />
'''Note''': Post-2.7 (Standard Logs) version<br />
<br />
<code sql><br />
SELECT <br />
u.lastname AS 'Last Name'<br />
, u.firstname AS 'First Name'<br />
, COUNT(l.id) AS 'Edits'<br />
<br />
, COUNT(DISTINCT IF((l.timecreated-c.startdate)<0,l.id,NULL)) AS 'Before Term'<br />
<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=0,l.id,NULL)) AS 'Week 1'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=1,l.id,NULL)) AS 'Week 2'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=2,l.id,NULL)) AS 'Week 3'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=3,l.id,NULL)) AS 'Week 4'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=4,l.id,NULL)) AS 'Week 5'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=5,l.id,NULL)) AS 'Week 6'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=6,l.id,NULL)) AS 'Week 7'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=7,l.id,NULL)) AS 'Week 8'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=8,l.id,NULL)) AS 'Week 9'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=9,l.id,NULL)) AS 'Week 10'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=10,l.id,NULL)) AS 'Week 11'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=11,l.id,NULL)) AS 'Week 12'<br />
<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))>=12,l.id,NULL)) AS 'After Term'<br />
<br />
# Our institution stores academic advisor names and emails in custom profile fields<br />
#, CONCAT('<a href="mailto:',uce.data,'">',uid.data, '</a>') AS 'Academic Advisor'<br />
<br />
, CONCAT('<a target="_blank" href="%%WWWROOT%%/report/log/index.php',CHAR(63),'chooselog=1&showusers=1&showcourses=0&id=',c.id,'&user=',u.id,'&date=0&modid=&modaction=&logformat=showashtml','">','Logs','</a>') AS 'Logs'<br />
<br />
, CONCAT('<a target="_blank" href="%%WWWROOT%%/report/outline/user.php',CHAR(63),'id=',u.id,'&course=',c.id,'&mode=outline">','Outline','</a>') AS 'Activity Outline'<br />
<br />
, CONCAT('<a target="_blank" href="%%WWWROOT%%/report/outline/user.php',CHAR(63),'id=',u.id,'&course=',c.id,'&mode=complete">','Activity','</a>') AS 'Consolidated Activity'<br />
<br />
, CONCAT('<a target="_blank" href="%%WWWROOT%%/mod/forum/user.php',CHAR(63),'id=',u.id,'&course=',c.id,'">','Posts','</a>') AS 'Posts'<br />
<br />
FROM prefix_user AS u<br />
JOIN prefix_role_assignments AS ra ON u.id = ra.userid<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
JOIN prefix_course_categories as cc ON c.category = cc.id<br />
<br />
# student academic coach - you can include custom profile field data with these methods<br />
# LEFT JOIN prefix_user_info_data as uid ON u.id = uid.userid AND uid.fieldid = '2'<br />
# student academic coach email<br />
# LEFT JOIN prefix_user_info_data as uce on u.id = uce.userid AND uce.fieldid = '6'<br />
<br />
LEFT JOIN prefix_logstore_standard_log AS l ON l.userid = u.id AND l.courseid = c.id AND l.crud IN ('c','u')<br />
<br />
WHERE ra.roleid =5<br />
AND ctx.instanceid = c.id<br />
<br />
AND c.id = %%COURSEID%%<br />
<br />
GROUP BY u.idnumber<br />
<br />
ORDER BY u.lastname, u.firstname<br />
</code><br />
<br />
===My Weekly Online Participation===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
Displays participation of the '''current user''' in the '''current course''' by week, including pre-term and post-term submissions/edits. A submission/edit is defined as a change to the course, such as a discussion post, the submission of an assignment, or the completion of a quiz, as well as alterations to course content such as database entries or new course activities or resources (if permitted).<br />
<br />
This report uses Standard Logs (post 2.7).<br />
<br />
<code sql><br />
SELECT <br />
<br />
l.component AS 'activity'<br />
<br />
, COUNT(DISTINCT IF((l.timecreated-c.startdate)<0,l.id,NULL)) AS 'Before Term'<br />
<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=0,l.id,NULL)) AS 'Week 1'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=1,l.id,NULL)) AS 'Week 2'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=2,l.id,NULL)) AS 'Week 3'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=3,l.id,NULL)) AS 'Week 4'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=4,l.id,NULL)) AS 'Week 5'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=5,l.id,NULL)) AS 'Week 6'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=6,l.id,NULL)) AS 'Week 7'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=7,l.id,NULL)) AS 'Week 8'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=8,l.id,NULL)) AS 'Week 9'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=9,l.id,NULL)) AS 'Week 10'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=10,l.id,NULL)) AS 'Week 11'<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))=11,l.id,NULL)) AS 'Week 12'<br />
<br />
, COUNT(DISTINCT IF(FLOOR((l.timecreated - c.startdate)/(60*60*24*7))>=12,l.id,NULL)) AS 'After Term'<br />
<br />
, COUNT(l.id) AS 'Total'<br />
<br />
FROM prefix_user AS u<br />
JOIN prefix_role_assignments AS ra ON u.id = ra.userid<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
JOIN prefix_course_categories as cc ON c.category = cc.id<br />
<br />
LEFT JOIN prefix_logstore_standard_log AS l ON l.userid = u.id AND l.courseid = c.id AND l.crud IN ('c','u')<br />
<br />
WHERE 1<br />
AND ctx.instanceid = c.id<br />
<br />
AND c.id = %%COURSEID%%<br />
AND u.id = %%USERID%%<br />
<br />
GROUP BY l.component<br />
<br />
ORDER BY l.component<br />
</code><br />
<br />
===Faculty/Student Interactions===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
Returns a count of instructor and other-student responses to student activity for the specified time period. This report can help indicate whether students' comments are being responded to, as well as summarizing post activity by students during the specified time.<br />
<br />
'''Note''': This version of the report uses legacy (pre-2.7) logs. See below for the post-2.7 Standard Logs version.<br />
<br />
'''Note''': This should be defined as a "Global" report (visible from within all courses). <br />
<br />
'''Note''': This report can take a long time to run. <br />
<br />
<br />
<code sql><br />
SELECT <br />
<br />
# Identify student<br />
CONCAT('<a target="_blank" href="%%WWWROOT%%/message/index.php?id=' , allstu.id , '">' , allstu.firstname , ' ' , allstu.lastname , '</a>' ) AS 'Student - click to send message'<br />
<br />
, IF((COUNT(DISTINCT IF(fps.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fps.id,NULL) )>0) OR (COUNT(DISTINCT IF(asb.timemodified > (UNIX_TIMESTAMP() - (7*24*60*60)),asb.id,NULL))>0) OR (SELECT COUNT(DISTINCT mfs.id) FROM prefix_message AS mfs WHERE mfs.useridfrom = allstu.id AND mfs.useridto = instr.id AND mfs.timecreated > (UNIX_TIMESTAMP() - (7*24*60*60))),'YES','NO') AS 'Student Participated This week'<br />
<br />
, IF((COUNT(DISTINCT IF(fpi.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpi.id,NULL) )>0) OR (COUNT(DISTINCT IF(asg.timemodified > (UNIX_TIMESTAMP() - (7*24*60*60)),asg.id,NULL))>0) OR (SELECT COUNT(DISTINCT mts.id) FROM prefix_message AS mts WHERE mts.useridfrom = instr.id AND mts.useridto = allstu.id AND mts.timecreated > (UNIX_TIMESTAMP() - (7*24*60*60))),'YES','NO') AS 'Student Contacted This week'<br />
<br />
## Only posts within last 7 days<br />
<br />
# Count posts by student<br />
, COUNT(DISTINCT IF(fps.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fps.id,NULL)) AS 'Forum Stu Posts - 7 days'<br />
<br />
# Count replies to student posts by instructors<br />
, COUNT(DISTINCT IF(fpi.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpi.id,NULL) ) AS 'Forum Instr Replies - 7 days'<br />
<br />
# using link back to student posts on replies, get unique student IDs responded<br />
, COUNT(DISTINCT IF(fpsr.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpsr.id,NULL)) - COUNT(DISTINCT IF(fpi.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpi.id,NULL) ) AS 'Forum Stu Replies - 7 days'<br />
<br />
# all replies<br />
, COUNT(DISTINCT IF(fpsr.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpsr.id,NULL)) AS 'Forum All Replies - 7 days'<br />
<br />
# add in count of graded assignments - 7 days<br />
, COUNT(DISTINCT IF(asb.timemodified > (UNIX_TIMESTAMP() - (7*24*60*60)),asb.id,NULL)) AS 'Assign Submit - 7 days'<br />
, COUNT(DISTINCT IF(asg.timemodified > (UNIX_TIMESTAMP() - (7*24*60*60)),asg.id,NULL)) AS 'Assign Grades - 7 days'<br />
<br />
# Messages between students and instructors - 7 days<br />
, (SELECT COUNT(DISTINCT mfs.id) FROM prefix_message AS mfs WHERE mfs.useridfrom = allstu.id AND mfs.useridto = instr.id AND mfs.timecreated > (UNIX_TIMESTAMP() - (7*24*60*60))) AS 'Msg Stu to Instr - 7 days'<br />
, (SELECT COUNT(DISTINCT mts.id) FROM prefix_message AS mts WHERE mts.useridfrom = instr.id AND mts.useridto = allstu.id AND mts.timecreated > (UNIX_TIMESTAMP() - (7*24*60*60))) AS 'Msg Instr to Stu - 7 days'<br />
<br />
## All posts in course so far<br />
# Count posts by student<br />
, COUNT(DISTINCT fps.id) AS 'Forum Stu Posts - to date'<br />
<br />
# Count replies to student posts by instructors<br />
, COUNT(DISTINCT fpi.id) AS 'Forum Instr Replies - to date'<br />
<br />
# using link back to student posts on replies, get unique student IDs responded<br />
, COUNT(DISTINCT fpsr.id) - COUNT(DISTINCT fpi.id) AS 'Forum Stu Replies - to date'<br />
<br />
# all replies<br />
, COUNT(DISTINCT fpsr.id) AS 'Forum All Replies - to date'<br />
<br />
# add in count of graded assignments - whole course<br />
, COUNT(DISTINCT asb.id) AS 'Assign Submit - to date'<br />
, COUNT(DISTINCT asg.id) AS 'Assign Grades - to date'<br />
<br />
# Messages between students and instructors - to date<br />
, (SELECT COUNT(DISTINCT mfs.id) FROM prefix_message AS mfs WHERE mfs.useridfrom = allstu.id AND mfs.useridto = instr.id ) AS 'Msg Stu to Instr - to date'<br />
, (SELECT COUNT(DISTINCT mts.id) FROM prefix_message AS mts WHERE mts.useridfrom = instr.id AND mts.useridto = allstu.id) AS 'Msg Instr to Stu - to date'<br />
<br />
## JOINS<br />
<br />
# Start by getting all the students in the course<br />
FROM prefix_user AS allstu <br />
JOIN prefix_role_assignments AS ras ON allstu.id = ras.userid AND ras.roleid = 5<br />
JOIN prefix_context AS ctx ON ras.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
JOIN prefix_course_categories as cc ON c.category = cc.id<br />
<br />
# Now we get the forums and forum discussions from this course only<br />
LEFT JOIN prefix_forum AS frm ON frm.course = c.id AND c.id = %%COURSEID%%<br />
LEFT JOIN prefix_forum_discussions AS fd ON fd.course = %%COURSEID%% AND fd.forum = frm.id<br />
<br />
# These are forum discussion posts just by students within specified time<br />
LEFT JOIN prefix_forum_posts AS fps ON fps.userid = allstu.id AND fps.discussion = fd.id<br />
<br />
# Separately, we connect the instructors of the courses<br />
# We can use the context we have already gotten for the students<br />
LEFT JOIN prefix_role_assignments AS rai ON rai.contextid = ctx.id<br />
LEFT JOIN prefix_user AS instr ON instr.id = rai.userid AND rai.roleid =3<br />
<br />
# Now we will connect to posts by instructors that are replies to student posts<br />
# This is a left join, because we don't want to eliminate any students from the list<br />
LEFT JOIN prefix_forum_posts AS fpi ON fpi.discussion = fd.id AND fpi.userid = instr.id AND fpi.parent = fps.id<br />
<br />
# To get identities of only those students who were replied to:<br />
# Connect from instr replies back up to parent posts by students again<br />
# This has to be a LEFT JOIN, we know these posts exist but don't eliminate non-responded students<br />
LEFT JOIN prefix_forum_posts AS fpir ON fpir.id = fpi.parent<br />
<br />
# We also want to know if students are replying to one another<br />
# These are posts that are replies to student posts<br />
# Again, a left join<br />
LEFT JOIN prefix_forum_posts AS fpsr ON fpsr.discussion = fd.id AND fpsr.parent = fps.id<br />
<br />
# get the activity modules<br />
LEFT JOIN prefix_course_modules AS cm ON c.id = cm.course<br />
<br />
# get the assignments<br />
LEFT JOIN prefix_assign AS a ON cm.instance = a.id<br />
LEFT JOIN prefix_assign_submission AS asb ON a.id = asb.assignment AND asb.userid=allstu.id <br />
LEFT JOIN prefix_assign_grades AS asg ON asg.assignment = a.id AND asg.userid = allstu.id AND asg.assignment = asb.assignment <br />
<br />
# We care about messages that involve both the instructor and students of this course<br />
# messages from instructor to students:<br />
# LEFT JOIN prefix_message AS mts ON mts.useridfrom = instr.id AND mts.useridto = allstu.id<br />
# LEFT JOIN prefix_message AS mfs ON mfs.useridfrom = instr.id AND mfs.useridto = allstu.id<br />
<br />
WHERE <br />
c.id = %%COURSEID%% <br />
<br />
# GROUP BY c.shortname , allstu.id<br />
GROUP BY allstu.id<br />
<br />
ORDER BY allstu.lastname<br />
</code><br />
<br />
'''Note''': Post-2.7 Standard Logs version<br />
<br />
<code sql><br />
SELECT <br />
<br />
# Identify student<br />
CONCAT('<a target="_blank" href="%%WWWROOT%%/message/index.php?id=' , allstu.id , '">' , allstu.firstname , ' ' , allstu.lastname , '</a>' ) AS 'Student - click to send message'<br />
<br />
, IF((COUNT(DISTINCT IF(fps.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fps.id,NULL) )>0) OR (COUNT(DISTINCT IF(asb.timemodified > (UNIX_TIMESTAMP() - (7*24*60*60)),asb.id,NULL))>0) OR (SELECT COUNT(DISTINCT mfs.id) FROM prefix_message AS mfs WHERE mfs.useridfrom = allstu.id AND mfs.useridto = instr.id AND mfs.timecreated > (UNIX_TIMESTAMP() - (7*24*60*60))),'YES','NO') AS 'Student Participated This week'<br />
<br />
, IF((COUNT(DISTINCT IF(fpi.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpi.id,NULL) )>0) OR (COUNT(DISTINCT IF(asg.timemodified > (UNIX_TIMESTAMP() - (7*24*60*60)),asg.id,NULL))>0) OR (SELECT COUNT(DISTINCT mts.id) FROM prefix_message AS mts WHERE mts.useridfrom = instr.id AND mts.useridto = allstu.id AND mts.timecreated > (UNIX_TIMESTAMP() - (7*24*60*60))),'YES','NO') AS 'Student Contacted This week'<br />
<br />
## Only posts within last 7 days<br />
<br />
# Count posts by student<br />
, COUNT(DISTINCT IF(fps.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fps.id,NULL)) AS 'Forum Stu Posts - 7 days'<br />
<br />
# Count replies to student posts by instructors<br />
, COUNT(DISTINCT IF(fpi.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpi.id,NULL) ) AS 'Forum Instr Replies - 7 days'<br />
<br />
# using link back to student posts on replies, get unique student IDs responded<br />
, COUNT(DISTINCT IF(fpsr.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpsr.id,NULL)) - COUNT(DISTINCT IF(fpi.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpi.id,NULL) ) AS 'Forum Stu Replies - 7 days'<br />
<br />
# all replies<br />
, COUNT(DISTINCT IF(fpsr.created > (UNIX_TIMESTAMP() - (7*24*60*60)),fpsr.id,NULL)) AS 'Forum All Replies - 7 days'<br />
<br />
# add in count of graded assignments - 7 days<br />
, COUNT(DISTINCT IF(asb.timemodified > (UNIX_TIMESTAMP() - (7*24*60*60)),asb.id,NULL)) AS 'Assign Submit - 7 days'<br />
, COUNT(DISTINCT IF(asg.timemodified > (UNIX_TIMESTAMP() - (7*24*60*60)),asg.id,NULL)) AS 'Assign Grades - 7 days'<br />
<br />
# Messages between students and instructors - 7 days<br />
, (SELECT COUNT(DISTINCT mfs.id) FROM prefix_message AS mfs WHERE mfs.useridfrom = allstu.id AND mfs.useridto = instr.id AND mfs.timecreated > (UNIX_TIMESTAMP() - (7*24*60*60))) AS 'Msg Stu to Instr - 7 days'<br />
, (SELECT COUNT(DISTINCT mts.id) FROM prefix_message AS mts WHERE mts.useridfrom = instr.id AND mts.useridto = allstu.id AND mts.timecreated > (UNIX_TIMESTAMP() - (7*24*60*60))) AS 'Msg Instr to Stu - 7 days'<br />
<br />
## All posts in course so far<br />
# Count posts by student<br />
, COUNT(DISTINCT fps.id) AS 'Forum Stu Posts - to date'<br />
<br />
# Count replies to student posts by instructors<br />
, COUNT(DISTINCT fpi.id) AS 'Forum Instr Replies - to date'<br />
<br />
# using link back to student posts on replies, get unique student IDs responded<br />
, COUNT(DISTINCT fpsr.id) - COUNT(DISTINCT fpi.id) AS 'Forum Stu Replies - to date'<br />
<br />
# all replies<br />
, COUNT(DISTINCT fpsr.id) AS 'Forum All Replies - to date'<br />
<br />
# add in count of graded assignments - whole course<br />
, COUNT(DISTINCT asb.id) AS 'Assign Submit - to date'<br />
, COUNT(DISTINCT asg.id) AS 'Assign Grades - to date'<br />
<br />
# Messages between students and instructors - to date<br />
, (SELECT COUNT(DISTINCT mfs.id) FROM prefix_message AS mfs WHERE mfs.useridfrom = allstu.id AND mfs.useridto = instr.id ) AS 'Msg Stu to Instr - to date'<br />
, (SELECT COUNT(DISTINCT mts.id) FROM prefix_message AS mts WHERE mts.useridfrom = instr.id AND mts.useridto = allstu.id) AS 'Msg Instr to Stu - to date'<br />
<br />
## JOINS<br />
<br />
# Start by getting all the students in the course<br />
FROM prefix_user AS allstu <br />
JOIN prefix_role_assignments AS ras ON allstu.id = ras.userid AND ras.roleid = 5<br />
JOIN prefix_context AS ctx ON ras.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
JOIN prefix_course_categories as cc ON c.category = cc.id<br />
<br />
# Now we get the forums and forum discussions from this course only<br />
JOIN prefix_forum AS frm ON frm.course = c.id AND c.id = %%COURSEID%%<br />
JOIN prefix_forum_discussions AS fd ON fd.course = %%COURSEID%% AND fd.forum = frm.id<br />
<br />
# These are forum discussion posts just by students within specified time<br />
LEFT JOIN prefix_forum_posts AS fps ON fps.userid = allstu.id AND fps.discussion = fd.id<br />
<br />
# Separately, we connect the instructors of the courses<br />
# We can use the context we have already gotten for the students<br />
JOIN prefix_role_assignments AS rai ON rai.contextid = ctx.id<br />
JOIN prefix_user AS instr ON instr.id = rai.userid AND rai.roleid =3<br />
<br />
# Now we will connect to posts by instructors that are replies to student posts<br />
# This is a left join, because we don't want to eliminate any students from the list<br />
LEFT JOIN prefix_forum_posts AS fpi ON fpi.discussion = fd.id AND fpi.userid = instr.id AND fpi.parent = fps.id<br />
<br />
# To get identities of only those students who were replied to:<br />
# Connect from instr replies back up to parent posts by students again<br />
# This has to be a LEFT JOIN, we know these posts exist but don't eliminate non-responded students<br />
LEFT JOIN prefix_forum_posts AS fpir ON fpir.id = fpi.parent<br />
<br />
# We also want to know if students are replying to one another<br />
# These are posts that are replies to student posts<br />
# Again, a left join<br />
LEFT JOIN prefix_forum_posts AS fpsr ON fpsr.discussion = fd.id AND fpsr.parent = fps.id<br />
<br />
# get the activity modules<br />
JOIN prefix_course_modules AS cm ON c.id = cm.course<br />
<br />
# get the assignments<br />
JOIN prefix_assign AS a ON cm.instance = a.id<br />
LEFT JOIN prefix_assign_submission AS asb ON a.id = asb.assignment AND asb.userid=allstu.id <br />
LEFT JOIN prefix_assign_grades AS asg ON asg.assignment = a.id AND asg.userid = allstu.id AND asg.assignment = asb.assignment <br />
<br />
WHERE <br />
c.id = %%COURSEID%% <br />
<br />
# GROUP BY c.shortname , allstu.id<br />
GROUP BY allstu.id<br />
<br />
ORDER BY allstu.lastname<br />
</code><br />
<br />
===Student Resource Usage===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
Displays usage by students of all activities and resources in the current course by activity. Only activities and sections which are visible in the course are included. This version requires the new "Standard Logs" from Moodle 2.7+.<br />
<br />
'''Note''': This should be defined as a "Global" report (visible from within all courses). <br />
<br />
<code sql><br />
SELECT <br />
cs.section AS 'Week'<br />
, cs.name AS 'Section Name'<br />
, m.name AS 'item type'<br />
<br />
, CONCAT(<br />
COALESCE(a.name, ''), <br />
COALESCE(b.name,''), <br />
COALESCE(cert.name,''), <br />
COALESCE(chat.name,''), <br />
COALESCE(choice.name,''), <br />
COALESCE(data.name,''), <br />
COALESCE(feedback.name,''), <br />
COALESCE(folder.name,''), <br />
COALESCE(forum.name,''), <br />
COALESCE(glossary.name,''), <br />
COALESCE(imscp.name,''), <br />
COALESCE(lesson.name,''), <br />
COALESCE(p.name,''),<br />
COALESCE(questionnaire.name,''), <br />
COALESCE(quiz.name,''), <br />
COALESCE(cr.name,''), <br />
COALESCE(scorm.name,''), <br />
COALESCE(survey.name,''), <br />
COALESCE(url.name,''), <br />
COALESCE(wiki.name,''), <br />
COALESCE(workshop.name,''), <br />
COALESCE(kalvidassign.name,''), <br />
COALESCE(attendance.name,''), <br />
COALESCE(checklist.name,''), <br />
COALESCE(flashcard.name,''), <br />
COALESCE(lti.name,''), <br />
COALESCE(oublog.name,''), <br />
COALESCE(ouwiki.name,''), <br />
COALESCE(subpage.name,''), <br />
COALESCE(journal.name,''), <br />
COALESCE(lightboxgallery.name,''), <br />
COALESCE(elluminate.name,''), <br />
COALESCE(adaptivequiz.name,''), <br />
COALESCE(hotpot.name,''), <br />
COALESCE(wiziq.name,''), <br />
COALESCE(turnitintooltwo.name,''), <br />
COALESCE(kvr.name,'')<br />
) AS 'item name'<br />
<br />
<br />
, SUM(IF(l.crud IN ('r'),1,0)) AS 'total views'<br />
, SUM(IF(l.crud IN ('c','u'),1,0)) AS 'total submissions'<br />
, COUNT(DISTINCT IF(l.crud IN ('r'),u.id,NULL)) AS 'count of students who viewed'<br />
, COUNT(DISTINCT IF(l.crud IN ('c','u'),u.id,NULL)) AS 'count of students who submitted'<br />
<br />
FROM prefix_user AS u<br />
JOIN prefix_role_assignments AS ra ON u.id = ra.userid<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_course AS c ON c.id = ctx.instanceid<br />
JOIN prefix_course_categories as cc ON c.category = cc.id<br />
<br />
JOIN prefix_course_sections AS cs ON cs.course = c.id AND cs.section <= 14 #AND cs.section > 0<br />
LEFT JOIN prefix_course_modules AS cm ON cm.course = c.id AND cm.section = cs.id<br />
JOIN prefix_modules AS m ON m.id = cm.module AND m.name NOT LIKE 'label'<br />
<br />
LEFT JOIN prefix_assign AS a ON a.id = cm.instance AND m.name = 'assign'<br />
LEFT JOIN prefix_book AS b ON b.id = cm.instance AND m.name = 'book'<br />
LEFT JOIN prefix_certificate AS cert ON cert.id = cm.instance AND m.name = 'certificate'<br />
LEFT JOIN prefix_chat AS chat ON chat.id = cm.instance AND m.name = 'chat'<br />
LEFT JOIN prefix_choice AS choice ON choice.id = cm.instance AND m.name = 'choice'<br />
LEFT JOIN prefix_data AS data ON data.id = cm.instance AND m.name = 'data'<br />
LEFT JOIN prefix_feedback AS feedback ON feedback.id = cm.instance AND m.name = 'feedback'<br />
LEFT JOIN prefix_folder AS folder ON folder.id = cm.instance AND m.name = 'folder'<br />
LEFT JOIN prefix_forum AS forum ON forum.id = cm.instance AND m.name = 'forum'<br />
LEFT JOIN prefix_glossary AS glossary ON glossary.id = cm.instance AND m.name = 'glossary'<br />
LEFT JOIN prefix_imscp AS imscp ON imscp.id = cm.instance AND m.name = 'imscp'<br />
LEFT JOIN prefix_lesson AS lesson ON lesson.id = cm.instance AND m.name = 'lesson'<br />
LEFT JOIN prefix_page AS p ON p.id = cm.instance AND m.name = 'page'<br />
LEFT JOIN prefix_questionnaire AS questionnaire ON questionnaire.id = cm.instance AND m.name = 'questionnaire'<br />
LEFT JOIN prefix_quiz AS quiz ON quiz.id = cm.instance AND m.name = 'quiz'<br />
LEFT JOIN prefix_resource AS cr ON cr.id = cm.instance AND m.name = 'resource'<br />
LEFT JOIN prefix_scorm AS scorm ON scorm.id = cm.instance AND m.name = 'scorm'<br />
LEFT JOIN prefix_survey AS survey ON survey.id = cm.instance AND m.name = 'survey'<br />
LEFT JOIN prefix_url AS url ON url.id = cm.instance AND m.name = 'url'<br />
LEFT JOIN prefix_wiki AS wiki ON wiki.id = cm.instance AND m.name = 'wiki'<br />
LEFT JOIN prefix_workshop AS workshop ON workshop.id = cm.instance AND m.name = 'workshop'<br />
LEFT JOIN prefix_kalvidassign AS kalvidassign ON kalvidassign.id = cm.instance AND m.name = 'kalvidassign'<br />
LEFT JOIN prefix_kalvidres AS kvr ON kvr.id = cm.instance AND m.name = 'kalvidres'<br />
LEFT JOIN prefix_attendance AS attendance ON attendance.id = cm.instance AND m.name = 'attendance'<br />
LEFT JOIN prefix_checklist AS checklist ON checklist.id = cm.instance AND m.name = 'checklist'<br />
LEFT JOIN prefix_flashcard AS flashcard ON flashcard.id = cm.instance AND m.name = 'flashcard'<br />
LEFT JOIN prefix_lti AS lti ON lti.id = cm.instance AND m.name = 'lti'<br />
LEFT JOIN prefix_oublog AS oublog ON oublog.id = cm.instance AND m.name = 'oublog'<br />
LEFT JOIN prefix_ouwiki AS ouwiki ON ouwiki.id = cm.instance AND m.name = 'ouwiki'<br />
LEFT JOIN prefix_subpage AS subpage ON subpage.id = cm.instance AND m.name = 'subpage'<br />
LEFT JOIN prefix_journal AS journal ON journal.id = cm.instance AND m.name = 'journal'<br />
LEFT JOIN prefix_lightboxgallery AS lightboxgallery ON lightboxgallery.id = cm.instance AND m.name = 'lightboxgallery'<br />
LEFT JOIN prefix_elluminate AS elluminate ON elluminate.id = cm.instance AND m.name = 'elluminate'<br />
LEFT JOIN prefix_adaptivequiz AS adaptivequiz ON adaptivequiz.id = cm.instance AND m.name = 'adaptivequiz'<br />
LEFT JOIN prefix_hotpot AS hotpot ON hotpot.id = cm.instance AND m.name = 'hotpot'<br />
LEFT JOIN prefix_wiziq AS wiziq ON wiziq.id = cm.instance AND m.name = 'wiziq'<br />
LEFT JOIN prefix_turnitintooltwo AS turnitintooltwo ON turnitintooltwo.id = cm.instance AND m.name = 'turnitintooltwo'<br />
<br />
LEFT JOIN prefix_logstore_standard_log AS l ON l.userid = u.id AND l.courseid = c.id<br />
<br />
<br />
WHERE ra.roleid =5<br />
AND ctx.instanceid = c.id<br />
AND cs.visible = 1<br />
AND cm.visible = 1<br />
<br />
AND c.id = %%COURSEID%%<br />
<br />
GROUP BY cm.id<br />
<br />
ORDER BY cs.section<br />
</code><br />
<br />
===Module activity (Hits) between dates===<br />
<code sql><br />
SELECT module, COUNT( * ) <br />
FROM prefix_logstore_standard_log AS l<br />
WHERE (FROM_UNIXTIME( l.`timecreated` ) BETWEEN '2018-10-01 00:00:00' AND '2019-09-31 00:00:00')<br />
GROUP BY module<br />
</code><br />
<br />
===Module activity (Instances and Hits) for each academic year===<br />
<code sql><br />
SELECT name<br />
<br />
,(SELECT COUNT(*) <br />
FROM mdl_log AS l<br />
WHERE (FROM_UNIXTIME(l.`time`) BETWEEN '2010-10-01 00:00:00' AND '2011-09-31 00:00:00')<br />
AND l.module = m.name AND l.action = 'add'<br />
) AS "Added 2010"<br />
<br />
,(SELECT COUNT(*) <br />
FROM mdl_log AS l<br />
WHERE (FROM_UNIXTIME(l.`time`) BETWEEN '2010-10-01 00:00:00' AND '2011-09-31 00:00:00')<br />
AND l.module = m.name<br />
) AS "Used 2010"<br />
<br />
,(SELECT COUNT(*) <br />
FROM mdl_log AS l<br />
WHERE (FROM_UNIXTIME(l.`time`) BETWEEN '2011-10-01 00:00:00' AND '2012-09-31 00:00:00')<br />
AND l.module = m.name AND l.action = 'add'<br />
) AS "Added 2011"<br />
<br />
,(SELECT COUNT(*) <br />
FROM mdl_log AS l<br />
WHERE (FROM_UNIXTIME(l.`time`) BETWEEN '2011-10-01 00:00:00' AND '2012-09-31 00:00:00')<br />
AND l.module = m.name<br />
) AS "Used 2011"<br />
<br />
<br />
,(SELECT COUNT(*) <br />
FROM mdl_log AS l<br />
WHERE (FROM_UNIXTIME(l.`time`) BETWEEN '2012-10-01 00:00:00' AND '2013-09-31 00:00:00')<br />
AND l.module = m.name AND l.action = 'add'<br />
) AS "Added 2012"<br />
<br />
,(SELECT COUNT(*) <br />
FROM mdl_log AS l<br />
WHERE (FROM_UNIXTIME(l.`time`) BETWEEN '2012-10-01 00:00:00' AND '2013-09-31 00:00:00')<br />
AND l.module = m.name<br />
) AS "Used 2012"<br />
<br />
FROM mdl_modules AS m<br />
</code><br />
<br />
===Unique user sessions per day and month + graph===<br />
The "graph" column is used when displaying a graph (which needs at least three columns to pick from)<br />
<code sql><br />
SELECT COUNT(DISTINCT userid) AS "Unique User Logins"<br />
,DATE_FORMAT(FROM_UNIXTIME(timecreated), "%y /%m / %d") AS "Year / Month / Day", "Graph" <br />
FROM `mdl_logstore_standard_log` <br />
WHERE action LIKE 'loggedin'<br />
#AND timecreated > UNIX_TIMESTAMP('2015-01-01 00:00:00') # optional start date<br />
#AND timecreated <= UNIX_TIMESTAMP('2015-01-31 23:59:00') # optional end date<br />
GROUP BY MONTH(FROM_UNIXTIME(timecreated)), DAY(FROM_UNIXTIME(timecreated))<br />
ORDER BY MONTH(FROM_UNIXTIME(timecreated)), DAY(FROM_UNIXTIME(timecreated))<br />
</code><br />
<br />
And...<br />
<br />
Counting user's global and unique hits per day + counting individual usage of specific activities and resources (on that day),<br />
<br />
And since I am using phpMyAdmin's "Display Graph" feature (at the bottom of the query's output page), I have scaled down the "User Hits" by 10 to fit the graph. that's it.<br />
<code sql><br />
SELECT DATE_FORMAT(FROM_UNIXTIME(timecreated), "%y-%m-%d") AS "Datez"<br />
,COUNT(DISTINCT userid) AS "Unique Users"<br />
,ROUND(COUNT(*)/10) "User Hits (K)"<br />
,SUM(IF(component='mod_quiz',1,0)) "Quizzes"<br />
,SUM(IF(component='mod_forum' or component='mod_forumng',1,0)) "Forums"<br />
,SUM(IF(component='mod_assign',1,0)) "Assignments"<br />
,SUM(IF(component='mod_oublog',1,0)) "Blogs"<br />
,SUM(IF(component='mod_resource',1,0)) "Files (Resource)"<br />
,SUM(IF(component='mod_url',1,0)) "Links (Resource)"<br />
,SUM(IF(component='mod_page',1,0)) "Pages (Resource)"<br />
<br />
FROM `mdl_logstore_standard_log` <br />
WHERE 1=1<br />
AND timecreated > UNIX_TIMESTAMP('2015-03-01 00:00:00') # optional START DATE<br />
AND timecreated <= UNIX_TIMESTAMP('2015-05-31 23:59:00') # optional END DATE<br />
GROUP BY MONTH(FROM_UNIXTIME(timecreated)), DAY(FROM_UNIXTIME(timecreated))<br />
ORDER BY MONTH(FROM_UNIXTIME(timecreated)), DAY(FROM_UNIXTIME(timecreated))<br />
</code><br />
<br />
===System wide, daily unique user hits for the last 7 days===<br />
<code sql><br />
SELECT<br />
DATE_FORMAT(FROM_UNIXTIME(l.timecreated), '%m%d') 'Day'<br />
,COUNT(DISTINCT l.userid) AS 'Distinct Users Hits'<br />
,COUNT( l.userid) AS 'Users Hits'<br />
<br />
FROM mdl_logstore_standard_log AS l<br />
WHERE l.courseid > 1<br />
AND FROM_UNIXTIME(l.timecreated) >= DATE_SUB(NOW(), INTERVAL 7 DAY)<br />
GROUP BY DAY(FROM_UNIXTIME(timecreated))<br />
</code><br />
<br />
===User detailed activity in course modules===<br />
Considering only several modules: url, resource, forum, quiz, questionnaire.<br />
<br />
<code sql><br />
SELECT u.id, ra.roleid,<br />
CONCAT(u.lastname, ' ', u.firstname) AS 'Student'<br />
,COUNT(l.id) AS 'Actions'<br />
,l.component "Module type"<br />
,l.objectid "Module ID"<br />
,CASE <br />
WHEN l.component = 'mod_url' THEN (SELECT u.name FROM mdl_url AS u WHERE u.id = l.objectid )<br />
WHEN l.component = 'mod_resource' THEN (SELECT r.name FROM mdl_resource AS r WHERE r.id = l.objectid )<br />
WHEN l.component = 'mod_forum' THEN (SELECT f.name FROM mdl_forum AS f WHERE f.id = l.objectid )<br />
WHEN l.component = 'mod_quiz' THEN (SELECT q.name FROM mdl_quiz AS q WHERE q.id = l.objectid )<br />
WHEN l.component = 'mod_questionnaire' THEN (SELECT q.name FROM mdl_questionnaire AS q WHERE q.id = l.objectid )<br />
END AS 'Module name'<br />
<br />
,(SELECT GROUP_CONCAT(g.name) FROM mdl_groups AS g<br />
JOIN mdl_groups_members AS m ON g.id = m.groupid WHERE g.courseid = l.courseid AND m.userid = u.id) "user_groups"<br />
<br />
,(SELECT s.name <br />
FROM mdl_course_modules AS cm <br />
JOIN mdl_course_sections AS s ON s.course = cm.course AND s.id = cm.section <br />
WHERE cm.id = l.contextinstanceid) AS "Section name"<br />
<br />
FROM mdl_logstore_standard_log AS l <br />
JOIN mdl_user AS u ON u.id = l.userid<br />
JOIN mdl_role_assignments AS ra ON ra.userid = l.userid <br />
AND ra.contextid = (SELECT id FROM mdl_context WHERE instanceid = l.courseid AND contextlevel = 50) <br />
WHERE l.courseid = %%COURSEID%%<br />
AND l.component IN ('mod_url', 'mod_resource', 'mod_forum', 'mod_quiz', 'mod_questionnaire') <br />
%%FILTER_STARTTIME:l.timecreated:>%% %%FILTER_ENDTIME:l.timecreated:<%%<br />
<br />
GROUP BY u.id, l.component<br />
ORDER BY u.lastname, u.firstname<br />
</code><br />
<br />
===What teachers and courses considered active?===<br />
This report display several calculations and parameters that help the Online academic training team find teachers that might need more support getting their courses more supporting of online learning pedagogical methodologies. <br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',<br />
course.id,'">',course.fullname,'</a>') AS Course <br />
<br />
#,course.shortname<br />
<br />
,CASE <br />
WHEN course.fullname LIKE '%2012%' THEN '2012'<br />
WHEN course.fullname LIKE '%2013%' THEN '2013' <br />
WHEN course.fullname LIKE '%2014%' THEN '2014'<br />
WHEN course.fullname LIKE '%2015%' THEN '2015'<br />
END AS Year<br />
<br />
,CASE <br />
WHEN course.fullname LIKE '%semester a%' THEN 'Spring semester'<br />
WHEN course.fullname LIKE '%semester b%' THEN 'Fall semester'<br />
WHEN course.fullname LIKE '%semester s%' THEN 'Summer semester'<br />
END AS Semester<br />
<br />
,IF(course.startdate>0, DATE_FORMAT(FROM_UNIXTIME(startdate), '%d-%m-%Y'), 'no date') AS "Course Start Date" <br />
<br />
,(SELECT COUNT( ra.userid ) AS Users<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = course.id<br />
) AS Students<br />
<br />
,(SELECT COUNT( ra.userid ) AS Users<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 4 AND ctx.instanceid = course.id<br />
) AS "Assistant teacher"<br />
<br />
,(SELECT COUNT( ra.userid ) AS Users<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 3 AND ctx.instanceid = course.id<br />
) AS Teachers<br />
<br />
# Uncomment to use the new Moodle 2.8+ logstore<br />
#,(SELECT COUNT(*) FROM mdl_logstore_standard_log AS l WHERE l.courseid = course.id) AS Hits<br />
<br />
#,(SELECT COUNT(*)<br />
#FROM mdl_logstore_standard_log AS l<br />
#JOIN mdl_role_assignments AS ra ON ra.userid= l.userid AND ra.roleid = 5 AND ra.contextid = (SELECT id FROM mdl_context WHERE instanceid = l.courseid AND contextlevel = 50) <br />
#WHERE l.courseid = course.id ) AS "Student HITs"<br />
<br />
#,(SELECT COUNT(*)<br />
#FROM mdl_logstore_standard_log AS l<br />
#JOIN mdl_role_assignments AS ra ON ra.userid= l.userid AND ra.roleid = 3 AND ra.contextid = (SELECT id FROM mdl_context WHERE instanceid = l.courseid AND contextlevel = 50) <br />
#WHERE l.courseid = course.id ) AS "Teacher HITs"<br />
<br />
,(SELECT COUNT(*) FROM mdl_log AS l WHERE l.course = course.id) AS Hits<br />
<br />
,(SELECT COUNT(*)<br />
FROM mdl_log AS l<br />
JOIN mdl_context AS con ON con.instanceid= l.course AND con.contextlevel=50<br />
JOIN mdl_role_assignments AS ra ON ra.contextid= con.id AND ra.userid= l.userid AND ra.roleid = 5 <br />
WHERE l.course = course.id) AS "Students HITs"<br />
<br />
,(SELECT COUNT(*)<br />
FROM mdl_log AS l<br />
JOIN mdl_context AS con ON con.instanceid= l.course AND con.contextlevel=50<br />
JOIN mdl_role_assignments AS ra ON ra.contextid= con.id AND ra.userid= l.userid AND ra.roleid = 3 <br />
WHERE l.course = course.id) AS "Teachers HITs"<br />
<br />
,(SELECT GROUP_CONCAT( CONCAT( u.firstname, " ", u.lastname ) ) <br />
FROM prefix_course c<br />
JOIN prefix_context con ON con.instanceid = c.id<br />
JOIN prefix_role_assignments ra ON con.id = ra.contextid AND con.contextlevel = 50<br />
JOIN prefix_role r ON ra.roleid = r.id<br />
JOIN prefix_user u ON u.id = ra.userid<br />
WHERE r.id = 3 AND c.id = course.id<br />
GROUP BY c.id<br />
) AS Teachers<br />
<br />
,(SELECT COUNT(*) FROM prefix_course_modules cm WHERE cm.course = course.id) Modules<br />
<br />
,(SELECT COUNT(DISTINCT cm.module) FROM prefix_course_modules cm <br />
WHERE cm.course = course.id) UniqueModules<br />
<br />
,(SELECT GROUP_CONCAT(DISTINCT m.name) <br />
FROM prefix_course_modules cm <br />
JOIN mdl_modules as m ON m.id = cm.module<br />
WHERE cm.course = course.id) UniqueModuleNames<br />
<br />
,(SELECT COUNT(*) FROM mdl_course_modules cm JOIN mdl_modules as m ON m.id = cm.module <br />
WHERE cm.course = course.id AND m.name IN ( 'ouwiki', 'wiki') ) "Num Wikis"<br />
<br />
,(SELECT COUNT(*) FROM mdl_course_modules cm JOIN mdl_modules as m ON m.id = cm.module <br />
WHERE cm.course = course.id AND m.name IN ( 'oublog') ) "Num Blogs"<br />
<br />
,(SELECT COUNT(*) FROM mdl_course_modules cm JOIN mdl_modules as m ON m.id = cm.module <br />
WHERE cm.course = course.id AND m.name IN ( 'forum', 'forumng') ) "Num Forums"<br />
<br />
,(SELECT COUNT(*) FROM prefix_course_modules cm JOIN mdl_modules as m ON m.id = cm.module <br />
WHERE cm.course = course.id AND m.name IN ('resource', 'folder', 'url', 'tab', 'file', 'book', 'page') ) Resources<br />
<br />
,(SELECT COUNT(*) FROM prefix_course_modules cm JOIN mdl_modules as m ON m.id = cm.module <br />
WHERE cm.course = course.id AND m.name IN ('forum', 'forumng', 'oublog', 'page', 'file', 'url', 'wiki' , 'ouwiki') ) "Basic Activities"<br />
<br />
,(SELECT COUNT(*) FROM prefix_course_modules cm JOIN mdl_modules as m ON m.id = cm.module <br />
WHERE cm.course = course.id AND m.name IN ('advmindmap', 'assign', 'attendance', 'book', 'choice', 'folder', 'tab', 'glossary', 'questionnaire', 'quiz', 'label' ) ) "Avarage Activities"<br />
<br />
,(SELECT COUNT(*) FROM prefix_course_modules cm JOIN mdl_modules as m ON m.id = cm.module <br />
WHERE cm.course = course.id AND m.name IN ('elluminate', 'game', 'workshop') ) "Advanced Activities"<br />
<br />
FROM prefix_course AS course<br />
<br />
#WHERE course.shortname LIKE '%2015%'<br />
#WHERE 1=1<br />
#%%FILTER_SEARCHTEXT:course.shortname:~%%<br />
<br />
WHERE course.fullname LIKE '%2015%' <br />
<br />
HAVING Modules > 2<br />
ORDER BY UniqueModules DESC<br />
</code><br />
<br />
===Weekly attendance report===<br />
This report display weekly report in format HH:M:SS This MySQL query works together with AttendaceRegister module, and gather Log information from Attendanceregister_log table. <br />
<code sql><br />
SELECT u.username, SEC_TO_TIME (SUM(arsess.duration)) AS weekly_online_attendance, FROM_UNIXTIME (arsess.logout) AS Last_Logout<br />
FROM prefix_attendanceregister_session AS arsess<br />
JOIN prefix_user AS u ON arsess.userid = u.id<br />
<br />
WHERE (((arsess.logout) BETWEEN UNIX_TIMESTAMP(DATE_SUB(CURDATE(), INTERVAL 7 DAY)) AND UNIX_TIMESTAMP(CURDATE())))<br />
<br />
GROUP BY arsess.userid<br />
</code><br />
<br />
===How many distinct users connected to Moodle using the app by month===<br />
https://moodle.org/mod/forum/discuss.php?d=336086#p1354194 by <br />
Iñigo Zendegi Urzelai<br />
<code sql><br />
SELECT <br />
to_char(to_timestamp("timecreated"),'YYYY') as year, <br />
to_char(to_timestamp("timecreated"),'MM') as month, <br />
count(distinct userid) as distinct_users<br />
<br />
FROM mdl_logstore_standard_log m<br />
WHERE m.origin='ws'<br />
GROUP BY to_char(to_timestamp("timecreated"),'YYYY'), to_char(to_timestamp("timecreated"),'MM') <br />
ORDER BY to_char(to_timestamp("timecreated"),'YYYY'), to_char(to_timestamp("timecreated"),'MM');<br />
</code><br />
<br />
==Course Reports==<br />
===Most Active courses===<br />
<code sql><br />
SELECT count(l.userid) AS Views<br />
FROM `mdl_logstore_standard_log` l, `mdl_user` u, `mdl_role_assignments` r<br />
WHERE l.courseid=35<br />
AND l.userid = u.id<br />
AND (l.timecreated > UNIX_TIMESTAMP('2015-01-01 00:00:00') AND l.timecreated <= UNIX_TIMESTAMP('2015-01-31 23:59:59'))AND r.contextid= (<br />
SELECT id<br />
FROM mdl_context<br />
WHERE contextlevel=50 AND instanceid=l.courseid<br />
)<br />
AND r.roleid=5<br />
AND r.userid = u.id<br />
</code><br />
<br />
===Active courses, advanced===<br />
Including: Teacher's name, link to the course, All types of log activities, special YEAR generated field, Activities and Resource count, enrolled Student count<br />
<code sql><br />
SELECT COUNT(l.id) hits, concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS Course <br />
<br />
,(SELECT CONCAT(u.firstname,' ', u.lastname) AS Teacher<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS Teacher<br />
<br />
,CASE <br />
WHEN c.fullname LIKE '%תשע' THEN 'תשע'<br />
WHEN c.fullname LIKE '%תשעא' THEN 'תשעא'<br />
WHEN c.fullname LIKE '%תשעב' THEN 'תשעב'<br />
END AS Year<br />
<br />
,(SELECT count(*) FROM prefix_course_modules cm WHERE cm.course = l.course) Modules<br />
<br />
,(SELECT Count( ra.userid ) AS Users FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = c.id) AS Students<br />
<br />
FROM prefix_log l <br />
INNER JOIN prefix_course c ON l.course = c.id<br />
GROUP BY c.id<br />
#The following line restricts the courses returned to those having more than 2 modules. Adjust based on your needs.<br />
HAVING Modules > 2<br />
ORDER BY Year DESC, hits DESC<br />
</code><br />
<br />
=== Least active or probably empty courses===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
It is difficult to know sometimes when a course is actually empty or was never really in use. Other than the simple case where the course was created and never touched again, in which case the course timecreated and timemodified will be the same, many courses created as shells for teachers or other users may be used once or a few times and have few or no test users enrollments in them. This query helps you see the range of such courses, showing you how many days if any it was used after initial creation, and how many user are enrolled. It denotes a course never ever modified by "-1" instead of "0" so you can sort those to the top. By default it limits this to courses used within 60 days of creation, and to courses with 3 or less enrollments (for example, teacher and assistant and test student account only.) You can easily adjust these numbers. The query includes a link to the course as well. <br />
<br />
<code sql><br />
SELECT<br />
c.fullname,<br />
CONCAT('<a target="_blank" href="%%WWWROOT%%/course/view.php',CHAR(63),'id=',c.id,'">',c.shortname,'</a>') AS 'CourseLink',<br />
DATE_FORMAT(FROM_UNIXTIME(c.timecreated), '%Y-%m-%d %H:%i') AS 'Timecreated',<br />
DATE_FORMAT(FROM_UNIXTIME(c.timemodified), '%Y-%m-%d %H:%i') AS 'Timemodified',<br />
CASE<br />
WHEN c.timecreated = c.timemodified THEN '-1'<br />
ELSE DATEDIFF(FROM_UNIXTIME(c.timemodified),FROM_UNIXTIME(c.timecreated))<br />
END AS 'DateDifference',<br />
COUNT(ue.id) AS Enroled<br />
FROM prefix_course AS c<br />
JOIN prefix_enrol AS en ON en.courseid = c.id<br />
LEFT JOIN prefix_user_enrolments AS ue ON ue.enrolid = en.id<br />
WHERE DATEDIFF(FROM_UNIXTIME(c.timemodified),FROM_UNIXTIME(c.timecreated) ) < 60<br />
GROUP BY c.id<br />
HAVING COUNT(ue.id) <= 3<br />
ORDER BY c.fullname<br />
</code><br />
<br />
===Count unique teachers with courses that use at least X module (Moodle19)===<br />
You can remove the outer "SELECT COUNT(*) FROM (...) AS ActiveTeachers" SQL query and get the list of the Teachers and Courses.<br />
<code sql><br />
SELECT COUNT(*)<br />
FROM (SELECT c.id AS CourseID, c.fullname AS Course, ra.roleid AS RoleID, CONCAT(u.firstname, ' ', u.lastname) AS Teacher<br />
,(SELECT COUNT(*) FROM prefix_course_modules cm WHERE cm.course = c.id) AS Modules<br />
FROM prefix_course AS c<br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid AND ctx.contextlevel = 50 <br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE ra.roleid = 3 <br />
GROUP BY u.id<br />
HAVING Modules > 5) AS ActiveTeachers<br />
</code><br />
<br />
===RESOURCE count for each COURSE===<br />
<code sql><br />
SELECT COUNT(l.id) count, l.course, c.fullname coursename<br />
FROM prefix_resource l INNER JOIN prefix_course c on l.course = c.id<br />
GROUP BY course<br />
ORDER BY count DESC<br />
</code><br />
<br />
===Common resource types count for each Category (Moodle19)===<br />
Including sub-categories in total count.<br />
<code sql><br />
SELECT mcc.id AS mccid, CONCAT( LPAD( '', mcc.depth, '.' ) , mcc.name ) AS Category<br />
,(SELECT COUNT( * ) <br />
FROM prefix_resource AS r<br />
JOIN prefix_course AS c ON c.id = r.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%', mccid, '%' ) AND r.TYPE = 'file' AND r.reference LIKE 'http://%'<br />
) AS Links<br />
<br />
,(SELECT COUNT( * ) <br />
FROM prefix_resource AS r<br />
JOIN prefix_course AS c ON c.id = r.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%', mccid, '%' ) AND r.TYPE = 'file' AND r.reference NOT LIKE 'http://%'<br />
) AS Files<br />
<br />
,(SELECT COUNT( * ) <br />
FROM prefix_resource AS r<br />
JOIN prefix_course AS c ON c.id = r.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%', mccid, '%' ) AND r.TYPE = 'directory' <br />
) AS Folders<br />
<br />
,(SELECT COUNT( * ) <br />
FROM prefix_resource AS r<br />
JOIN prefix_course AS c ON c.id = r.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%', mccid, '%' ) AND r.TYPE = 'html' <br />
) AS Pages<br />
<br />
,(SELECT COUNT(*) <br />
FROM stats_log_context_role_course <br />
WHERE roleid = 5 AND module = 'resource' AND category = mcc.id<br />
) AS Hits<br />
<br />
FROM prefix_course_categories AS mcc<br />
ORDER BY mcc.path<br />
</code><br />
Where "stats_log_context_role_course" (in the above SQL query) is a VIEW generated by:<br />
<code sql><br />
CREATE VIEW stats_log_context_role_course AS<br />
SELECT l.course, c.category, cc.path, l.module, l.action, ra.userid, ra.roleid<br />
FROM prefix_log AS l<br />
JOIN prefix_context AS context ON context.instanceid = l.course AND context.contextlevel = 50<br />
JOIN prefix_role_assignments AS ra ON ra.userid = l.userid AND ra.contextid = context.id<br />
JOIN prefix_course AS c ON c.id = l.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
</code><br />
<br />
Same query but for Moodle2+<br />
<code sql><br />
SELECT mcc.id AS mccid, CONCAT( LPAD( '', mcc.depth, '.' ) , mcc.name ) AS Category,<br />
mcc.path,<br />
<br />
(SELECT COUNT(*) <br />
FROM prefix_url AS u<br />
JOIN prefix_course AS c ON c.id = u.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%/', mccid, '%' )<br />
) AS URLs,<br />
<br />
(SELECT COUNT(*) <br />
FROM prefix_folder AS f<br />
JOIN prefix_course AS c ON c.id = f.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%/', mccid, '%' )<br />
) AS FOLDERs,<br />
<br />
(SELECT COUNT(*) <br />
FROM prefix_page AS p<br />
JOIN prefix_course AS c ON c.id = p.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%/', mccid, '%' )<br />
) AS PAGEs,<br />
<br />
(SELECT COUNT(*) <br />
FROM prefix_book AS b<br />
JOIN prefix_course AS c ON c.id = b.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%/', mccid, '%' )<br />
) AS BOOKs,<br />
<br />
(SELECT COUNT(*) <br />
FROM prefix_label AS l<br />
JOIN prefix_course AS c ON c.id = l.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%/', mccid, '%' )<br />
) AS LABELs,<br />
<br />
(SELECT COUNT(*) <br />
FROM prefix_tab AS t<br />
JOIN prefix_course AS c ON c.id = t.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
WHERE cc.path LIKE CONCAT( '%/', mccid, '%' )<br />
) AS TABs<br />
<br />
FROM prefix_course_categories AS mcc<br />
ORDER BY mcc.path<br />
</code><br />
<br />
===Detailed Resource COUNT by Teacher in each course===<br />
<br />
Including (optional) filter by: year, semester and course id.<br />
<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS CourseID<br />
, c.id<br />
,( SELECT DISTINCT CONCAT(u.firstname,' ',u.lastname)<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_user AS u ON ra.userid = u.id<br />
JOIN prefix_context AS ctx ON ctx.id = ra.contextid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id AND ctx.contextlevel = 50 LIMIT 1) AS Teacher<br />
<br />
, (CASE <br />
WHEN c.fullname LIKE '%תשעב%' THEN '2012' <br />
WHEN c.fullname LIKE '%תשעא%' THEN '2011'<br />
END ) as Year<br />
, (CASE <br />
WHEN c.fullname LIKE '%סמסטר א%' THEN 'Semester A' <br />
WHEN c.fullname LIKE '%סמסטר ב%' THEN 'Semester B'<br />
WHEN c.fullname LIKE '%סמסטר ק%' THEN 'Semester C'<br />
END ) as Semester<br />
,COUNT(c.id) AS Total<br />
,(SELECT count(*) FROM prefix_course_modules AS cm WHERE cm.course = c.id AND cm.module= 20) AS TABs<br />
,(SELECT count(*) FROM prefix_course_modules AS cm WHERE cm.course = c.id AND cm.module= 33) AS BOOKs<br />
<br />
FROM `prefix_resource` as r <br />
JOIN `prefix_course` AS c on c.id = r.course<br />
#WHERE type= 'file' and reference NOT LIKE 'http://%' <br />
<br />
#WHERE 1=1<br />
#%%FILTER_YEARS:c.fullname%%<br />
#AND c.fullname LIKE '%2013%'<br />
<br />
GROUP BY course<br />
ORDER BY COUNT(c.id) DESC<br />
</code><br />
<br />
===Courses that are defined as using GROUPs===<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/group/index.php?id=',c.id,'">',c.fullname,'</a>') AS Course<br />
,(SELECT count(*) FROM prefix_course_modules cm WHERE cm.course = c.id) Modules<br />
,(SELECT count(*) FROM prefix_groups g WHERE g.courseid = c.id) Groups<br />
FROM `prefix_course` AS c<br />
WHERE groupmode > 0<br />
</code><br />
<br />
===Courses with Groups===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
List of all courses with Groups in them (groupmode > 0). You can also use groupmode=1 to list just Separate type groups or groupmode=2 to list Visible type groups.<br />
<br />
<code sql><br />
SELECT c.shortname, g.name, c.groupmode<br />
FROM prefix_course AS c<br />
JOIN prefix_groups AS g ON c.id = g.courseid<br />
WHERE c.groupmode > 0<br />
</code><br />
<br />
===Users enrolled in a course with groups but not assigned a group ===<br />
<br />
Displays by course all enrolled users that have not been assigned a group in courses that have groups. NOTE: This needs to be optimized.<br />
<br />
<code sql><br />
SELECT DISTINCT<br />
user2.firstname AS Firstname,<br />
user2.lastname AS Lastname,<br />
user2.email AS Email,<br />
user2.city AS City,<br />
course.fullname AS Course<br />
,(SELECT shortname FROM prefix_role WHERE id=en.roleid) AS ROLE<br />
,(SELECT name FROM prefix_role WHERE id=en.roleid) AS RoleName<br />
<br />
FROM prefix_course AS course <br />
JOIN prefix_enrol AS en ON en.courseid = course.id<br />
JOIN prefix_user_enrolments AS ue ON ue.enrolid = en.id<br />
JOIN prefix_user AS user2 ON ue.userid = user2.id<br />
JOIN prefix_groups AS g ON g.courseid = course.id<br />
<br />
WHERE ue.enrolid NOT IN (select userid from prefix_groups_members WHERE g.id=groupid)<br />
<br />
ORDER BY Course, Lastname<br />
</code><br />
<br />
===Groups in course with member list===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
List the groups in a course (replace the # by the course id number) with the members of each group.<br />
<br />
<code sql><br />
SELECT c.shortname, g.name AS Groupname, u.username<br />
FROM prefix_course AS c<br />
JOIN prefix_groups AS g ON g.courseid = c.id<br />
JOIN prefix_groups_members AS m ON g.id = m.groupid<br />
JOIN prefix_user AS u ON m.userid = u.id<br />
WHERE c.id = #<br />
</code><br />
<br />
Note: if you are using Configurable Reports block and want to perform this query on the current course you are in, then you can use a WHERE clause like this:<br />
<code sql><br />
WHERE c.id = %%COURSEID%%<br />
</code><br />
<br />
===Group Export===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
There's a [[Import_groups|group import]] function, but no export. Use this to give you a report with the proper column order and headings to export to a csv file you can then import into another course to replicate the groups. This is a simple version with just the main fields: groupname, description, enrolment key.<br />
<br />
<code sql><br />
SELECT g.name AS groupname, g.description, g.enrolmentkey<br />
FROM prefix_groups AS g <br />
JOIN prefix_course as c ON g.courseid = c.id<br />
WHERE c.id = #<br />
</code><br />
Note: if you are using Configurable Reports block and want to perform this query on the current course you are in, then you can use a WHERE clause like this:<br />
<code sql><br />
WHERE c.id = %%COURSEID%%<br />
</code><br />
<br />
===List all Courses in and below a certain category===<br />
Use this SQL code to retrieve all courses that exist in or under a set category.<br />
<br />
$s should be the id of the category you want to know about...<br />
<code sql><br />
SELECT prefix_course. * , prefix_course_categories. *<br />
FROM prefix_course, prefix_course_categories<br />
WHERE prefix_course.category = prefix_course_categories.id<br />
AND (<br />
prefix_course_categories.path LIKE '%/$s/%'<br />
OR prefix_course_categories.path LIKE '%/$s'<br />
)<br />
</code><br />
<br />
===List all Categories in one level below a certain category===<br />
Use this PHP code to retrieve a list of all categories below a certain category.<br />
<br />
$s should be the id of the top level category you are interested in.<br />
<code php><br />
<?php<br />
<br />
require_once('./config.php');<br />
<br />
$parent_id = $s;<br />
<br />
$categories= array();<br />
<br />
$categories = get_categories($parent_id);<br />
<br />
echo '<ol>';<br />
foreach ($categories as $category)<br />
{<br />
echo '<li><a href="'.$CFG->wwwroot.'/course/category.php?id='.$category->id.'">'.$category->name.'</a></li>';<br />
}<br />
echo '</ol>';<br />
<br />
?><br />
</code><br />
<br />
===Blog activity per Course (not including VIEW)===<br />
Filter activity logging to some specific Course Categories!<br />
+ link course name to actual course (for quick reference)<br />
(you can change %blog% to %wiki% to filter down all wiki activity or any other module you wish)<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',cm.course,'">',c.fullname,'</a>') as CourseID<br />
,m.name ,count(cm.id) as counter <br />
,(SELECT Count( ra.userid ) AS Users<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5<br />
AND ctx.instanceid = c.id<br />
) AS Students<br />
, ( SELECT count(id) FROM prefix_log WHERE `module` LIKE '%blog%' AND course = c.id AND action NOT LIKE '%view%' ) as BlogActivity<br />
FROM `prefix_course_modules` as cm JOIN prefix_modules as m ON cm.module=m.id JOIN prefix_course as c ON cm.course = c.id <br />
WHERE m.name LIKE '%blog%' AND c.category IN ( 8,13,15)<br />
GROUP BY cm.course,cm.module order by counter desc<br />
</code><br />
<br />
===Student's posts content in all course blogs (oublog)===<br />
<code sql><br />
SELECT <br />
b.name <br />
,op.title<br />
,op.message<br />
,( SELECT CONCAT(u.firstname, ' ',u.lastname) FROM prefix_user AS u WHERE u.id = oi.userid) AS "Username"<br />
<br />
FROM prefix_oublog_posts AS op<br />
JOIN prefix_oublog_instances AS oi ON oi.id = op.oubloginstancesid <br />
JOIN prefix_oublog as b ON b.id = oi.oublogid<br />
JOIN prefix_course AS c ON b.course = c.id<br />
<br />
WHERE c.id = %%COURSEID%%<br />
</code><br />
<br />
===All Courses which uploaded a Syllabus file===<br />
+ under specific Category<br />
+ show first Teacher in that course<br />
+ link Course's fullname to actual course<br />
<code sql><br />
SELECT<br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') as Course<br />
,c.shortname,r.name<br />
,(SELECT CONCAT(u.firstname,' ', u.lastname) as Teacher<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user as u ON u.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) as Teacher<br />
FROM prefix_resource as r <br />
JOIN prefix_course as c ON r.course = c.id<br />
WHERE ( r.name LIKE '%סילבוס%' OR r.name LIKE '%סילאבוס%' OR r.name LIKE '%syllabus%' OR r.name LIKE '%תכנית הקורס%' ) <br />
AND c.category IN (10,18,26,13,28)<br />
</code><br />
<br />
===Site-wide completed SCORM activities by Course name===<br />
This report will list all completed attempts for all SCORM activities. It is ordered first by Course name, then student's last name, then student's first name, then attempt number. Please note: the FROM_UNIXTIME command is for MySQL.<br />
<code sql><br />
SELECT u.firstname First,u.lastname Last,c.fullname Course, st.attempt Attempt,st.value Status,FROM_UNIXTIME(st.timemodified,"%m-%d-%Y") Date <br />
FROM prefix_scorm_scoes_track AS st <br />
JOIN prefix_user AS u ON st.userid=u.id<br />
JOIN prefix_scorm AS sc ON sc.id=st.scormid<br />
JOIN prefix_course AS c ON c.id=sc.course<br />
WHERE st.value='completed' <br />
ORDER BY c.fullname, u.lastname,u.firstname, st.attempt<br />
</code><br />
===All users enrolled in a course without a role===<br />
Identifies All users that are enrolled in a course but are not assigned a role.<br />
<code sql><br />
SELECT<br />
user.firstname AS Firstname,<br />
user.lastname AS Lastname,<br />
user.idnumber Employee_ID,<br />
course.fullname AS Course<br />
<br />
FROM prefix_course AS course <br />
JOIN prefix_enrol AS en ON en.courseid = course.id<br />
JOIN prefix_user_enrolments AS ue ON ue.enrolid = en.id<br />
JOIN prefix_user as user ON user.id = ue.userid<br />
<br />
WHERE user.id NOT IN (<br />
SELECT u.id<br />
FROM prefix_course AS c<br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid<br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN prefix_role AS r ON r.id = ra.roleid<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE c.id=course.id<br />
)<br />
ORDER BY Course, Lastname, Firstname<br />
<br />
</code><br />
<br />
===List course resources accumulative file size and count===<br />
This is the main (first) report, which has a link (alias) to a second report (the following on this page) which list each file in the course.<br />
<code sql><br />
SELECT c.id "CourseID", context.id "ContextID"<br />
,CONCAT('<a target="_new" href="%%WWWROOT%%/course/view.php?id=', c.id, '">', c.fullname ,'</a>') AS "Course Name"<br />
, COUNT(*) "Course Files" , ROUND( SUM( f.filesize ) /1048576 ) AS file_size_MB<br />
,CONCAT('<a target="_new" href="%%WWWROOT%%/blocks/configurable_reports/viewreport.php?alias=coursefiles&courseid=1&filter_courses=', c.id, '">List files</a>') AS "List Files"<br />
<br />
FROM mdl_files AS f<br />
JOIN mdl_context AS context ON context.id = f.contextid<br />
JOIN mdl_course AS c ON c.id = (<br />
SELECT instanceid<br />
FROM mdl_context<br />
WHERE id = SUBSTRING_INDEX( SUBSTRING_INDEX( context.path, '/' , -2 ) , '/', 1 ) )<br />
WHERE filesize >0<br />
GROUP BY c.id<br />
</code><br />
<br />
With this report, you will have to define "alias" report property to "coursefiles" for it to be able to be called from the above report.<br />
And also setup (add) a FILTER_COURSES filter. <br />
<code sql><br />
SELECT <br />
id ,CONCAT('<a target="_new" href="%%WWWROOT%%/pluginfile.php/', contextid, '/', component, '/', filearea, '/', itemid, '/', filename, '">', filename,'</a>') AS "File"<br />
,filesize, mimetype ,author, license, timecreated, component, filearea, filepath<br />
<br />
FROM mdl_files AS f<br />
WHERE filesize >0<br />
AND f.contextid<br />
IN ( SELECT id<br />
FROM mdl_context<br />
WHERE path <br />
LIKE ( SELECT CONCAT('%/',id,'/%')<br />
AS contextquery<br />
FROM mdl_context<br />
WHERE 1=1<br />
%%FILTER_COURSES:instanceid%%<br />
AND contextlevel = 50<br />
)<br />
)<br />
</code><br />
<br />
===Which courses has redundant topics===<br />
This report list several "active topics" calculations, per course. which should give an administrator some indications for which topics/sections/weeks are filled with resources and activities and which ones are empty and not used (usually, at the end of the course).<br />
<br />
The following, second SQL query, could be used to "trim" down those redundant course topics/sections/weeks by updating the course format's numsection (Number of sections) setting. (It's a per course format setting!)<br />
<br />
<code sql><br />
SELECT id, format,<br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">', c.fullname,'</a>') AS Course <br />
<br />
,(SELECT value FROM `mdl_course_format_options` WHERE `courseid` = c.id AND `format` = c.format AND `name` = 'numsections' ) AS "numsections"<br />
,(SELECT COUNT(*) FROM `mdl_course_sections` WHERE `course` = c.id AND `sequence` != '' ) AS "Non empty sections count"<br />
,(SELECT COUNT(*) FROM `mdl_course_sections` WHERE `course` = c.id ) AS "Total section count"<br />
,(SELECT COUNT(*) FROM `mdl_course_sections` WHERE `course` = c.id AND sequence IS NOT NULL) AS "Non NULL sections count"<br />
,(SELECT COUNT(*) FROM `mdl_course_sections` WHERE `course` = c.id AND name != '') AS "Non empty section Name count"<br />
,(SELECT COUNT(*) FROM mdl_course_modules cm WHERE cm.course = c.id) "Modules count"<br />
<br />
FROM mdl_course AS c<br />
</code><br />
<br />
The following SQL REPLACE query is used for "fixing" (updating) the "numsections" of a specific course format "onetopics" (you can always change it, or discard it to use this SQL REPLACE on all course formats) <br />
<code sql><br />
REPLACE INTO `mdl_course_format_options` (`id`, `courseid`, `format`, `sectionid`, `name`, `value`) <br />
SELECT NULL, c.id, 'onetopic', '0', 'numsections', (SELECT COUNT(*) FROM `mdl_course_sections` WHERE `course` = c.id AND name != '')<br />
FROM `mdl_course` c where format = 'onetopic'<br />
</code><br />
<br />
===Hidden Courses with Students Enrolled===<br />
Contributed by Eric Strom<br />
<br />
This query identifies courses with student enrollment that are currently hidden from students. Includes the defined course start date, count of students and instructors, and a clickable email link of instructor (first found record if more than one).<br />
<br />
<code sql><br />
SELECT c.visible AS Visible, <br />
DATE(FROM_UNIXTIME(c.startdate)) AS StartDate, <br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php',CHAR(63),'id=',<br />
c.id,'">',c.idnumber,'</a>') AS Course_ID,<br />
<br />
(SELECT COUNT( ra.userid ) FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = c.id) AS Students,<br />
<br />
(SELECT COUNT( ra.userid ) FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id) AS Instructors,<br />
<br />
(SELECT DISTINCT concat('<a href="mailto:',u.email,'">',u.email,'</a>')<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_user AS u ON ra.userid = u.id<br />
JOIN prefix_context AS ctx ON ctx.id = ra.contextid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id AND ctx.contextlevel = 50 LIMIT 1) AS 'Instructor_Email', <br />
<br />
now() AS Report_Timestamp<br />
<br />
FROM prefix_course AS c <br />
WHERE c.visible = 0 AND (SELECT COUNT( ra.userid ) FROM prefix_role_assignments AS ra JOIN prefix_context AS ctx ON ra.contextid = ctx.id WHERE ra.roleid = 5 AND ctx.instanceid = c.id) > 0<br />
ORDER BY StartDate, Instructor_Email, Course_ID<br />
</code><br />
<br />
<br />
==Course Design Reports==<br />
<br />
These are reports which summarize course design aspects, such as activity and resource modules per section, types of activities used, etc.<br />
<br />
===Course Content/Week===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
This report assumes that the first 14 sections in a course, not including the "0" or "Welcome" section, correspond to weeks (with "Subsections" given numbers much higher in the sequence). Of those sections, each is checked to count the number of:<br />
<br />
Forums<br />
Graded Activities (may include Forums)<br />
Resources (not including a Label)<br />
<br />
Totals of each of these types of content elements per section are provided.<br />
<br />
'''Note''': Only visible resources and activities are counted.<br />
'''Note''': this is a "Global" report. Run it within a course to see a summary of the contents of that course.<br />
<br />
<code sql><br />
SELECT<br />
<br />
cs.section AS 'Week'<br />
, cs.name AS 'Section Name'<br />
<br />
, COUNT(DISTINCT IF((gi.id IS NULL) AND (m.name NOT LIKE 'label'),cm.id,NULL)) AS 'Ungraded Resources'<br />
<br />
, COUNT(DISTINCT IF(m.name LIKE 'forum', cm.id, NULL)) AS 'Forums'<br />
<br />
, COUNT(DISTINCT IF(gi.id, cm.id, NULL)) AS 'Graded Activities'<br />
<br />
FROM prefix_course AS c<br />
JOIN prefix_course_sections AS cs ON cs.course = c.id AND cs.section <= 14 AND cs.section > 0<br />
LEFT JOIN prefix_course_modules AS cm ON cm.course = c.id AND cm.section = cs.id <br />
JOIN prefix_modules AS m ON m.id = cm.module<br />
LEFT JOIN prefix_grade_items AS gi ON gi.courseid = c.id AND gi.itemmodule = m.name AND gi.iteminstance = cm.instance<br />
<br />
WHERE <br />
cs.visible = 1<br />
AND cm.visible = 1<br />
AND c.id = %%COURSEID%%<br />
<br />
GROUP BY cs.section<br />
ORDER BY cs.section<br />
<br />
</code><br />
<br />
===Assignments and Weights===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
Returns a list of grade book categories for the current course, grade book weightings, the first type of assignment included in the category, a count of different assignment types for each category, and a count of assignments for each category.<br />
<br />
Categories with weights of 0 are not included in this report.<br />
<br />
Only visible activities are included in this report.<br />
<br />
'''Note''': This is designed to be a "Global" report in Configurable Reports.<br />
<code sql><br />
SELECT<br />
<br />
IF(gc.parent IS NOT NULL, gc.fullname, 'None') AS 'Grade Book Category'<br />
, IF(gc.parent IS NOT NULL, ROUND(gic.aggregationcoef, 2), ROUND(SUM(DISTINCT gi.aggregationcoef), 2)+ROUND(SUM(DISTINCT mgi.aggregationcoef), 2)) AS 'Category weight'<br />
<br />
, CONCAT_WS(', ',GROUP_CONCAT(DISTINCT gi.itemmodule SEPARATOR ', '), IF(mgi.id, 'manual',NULL)) AS 'Activity Types'<br />
, COUNT(DISTINCT gi.itemmodule) + IF(mgi.id,1,0) AS 'Different Activity Types'<br />
, CONCAT_WS('<br>', GROUP_CONCAT(DISTINCT gi.itemname ORDER BY gi.itemname SEPARATOR '<br>'), GROUP_CONCAT(DISTINCT mgi.itemname ORDER BY mgi.itemname SEPARATOR '<br>')) AS 'Activity Names'<br />
, COUNT(DISTINCT IF(gi.id, cm.id, NULL)) + COUNT(DISTINCT mgi.id) AS 'Activity Count'<br />
<br />
FROM prefix_course AS c<br />
<br />
#get grade categories<br />
LEFT JOIN prefix_grade_categories AS gc ON gc.courseid = c.id <br />
# back from categories to grade items to get aggregations and weights<br />
JOIN prefix_grade_items AS gic ON gic.courseid = c.id AND gic.itemtype = 'category' AND gic.aggregationcoef != 0 AND (LOCATE(gic.iteminstance, gc.path) OR (gc.parent IS NULL))<br />
<br />
# attach activities to course<br />
JOIN prefix_course_modules AS cm ON cm.course = c.id <br />
# attach grade items to activities<br />
LEFT JOIN prefix_grade_items AS gi ON gi.courseid = c.id AND gi.iteminstance = cm.instance AND gi.itemtype = 'mod' AND gi.categoryid = gc.id AND gi.hidden != 1<br />
<br />
# attach manual grade items to course-- they don't have modules<br />
LEFT JOIN prefix_grade_items AS mgi ON mgi.courseid = c.id and mgi.itemtype = 'manual' AND mgi.categoryid = gc.id<br />
<br />
WHERE <br />
cm.visible = 1<br />
AND c.id = %%COURSEID%%<br />
<br />
GROUP BY gc.id<br />
ORDER BY gc.id<br />
<br />
</code><br />
<br />
===Pre-Term Course Review===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
Provides an overview of the readiness of ONLINE, HYBRID, and BLENDED courses in the Staging category and all subcategories. Links to each course are provided. Other details:<br />
<br />
# "Required blocks" include Instructor Block (mooprofile), Activities, and the Research block.<br />
# "Instructor Details" block is not the "Instructor" block (mooprofile) automatically provided by the system. It is an optional block that can be edited by the instructor. If not edited to remove boilerplate text, it should be hidden.<br />
# All courses should be in the "Collapsed Topics" format with the "Weeks" structure.<br />
# "Weeks defined in course settings" is taken from our SIS when the course shells are created, but can be edited by faculty. "# of weeks named and visible" should usually match or exceed this value.<br />
# We recommend that each week contain at least one forum, at least one graded activity, and at least one ungraded resource.<br />
# "Syllabus updated" date is for the first attached file found with the text "syllabus" in the name. The "Days ago" calculation is included for convenience.<br />
<br />
'''Note''': At our institution, we construct categories each term, and insert a text string "staging" in the Category ID for pre-term courses during the preparation or "staging" phase of course development. We remove this text string (and change it to "production") when courses go live at the start of the new term.<br />
<br />
<code sql><br />
SELECT CONCAT('<a target="_blank" href="%%WWWROOT%%/course/view.php',CHAR(63),'id=',c.id,'">',c.shortname,'</a>') AS Course<br />
<br />
#,RIGHT(c.idnumber,2) AS Type # Specific to GSC "Instructional Method" storage<br />
<br />
#, substring_index(substr(c.shortname FROM locate('.',c.shortname)+1),'-',1) AS Section # Specific to GSC<br />
<br />
,(SELECT CONCAT('<a target="_blank" href="%%WWWROOT%%/user/view.php',CHAR(63),'id=',u.id,'">',u.lastname,', ', u.firstname,'</a>')<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS 'Instructor' <br />
<br />
,(SELECT IF((u2.description IS NULL) OR (u2.description LIKE ''),'NO', 'YES')<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u2 ON u2.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS 'Profile Has Bio'<br />
<br />
,(SELECT IF(u3.picture > 0,'YES','NO')<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u3 ON u3.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS 'Profile Has Picture'<br />
<br />
, IF(((bpi.visible IS NULL) OR (bpi.visible !=0)) AND ((bpm.visible IS NULL) OR (bpm.visible !=0)) AND ((bpa.visible IS NULL) OR (bpa.visible !=0)) AND ((bpr.visible IS NULL) OR (bpr.visible !=0)),'YES','NO') AS 'Required blocks visible'<br />
#, IF((bpm.visible IS NULL) OR (bpm.visible !=0),'YES','NO') AS 'Messages block visible'<br />
#, IF((bpa.visible IS NULL) OR (bpa.visible !=0),'YES','NO') AS 'activities block visible'<br />
#, IF((bpr.visible IS NULL) OR (bpr.visible !=0),'YES','NO') AS 'research block visible'<br />
<br />
#, IF(SUM(IF(bi.configdata LIKE 'Tzo4OiJzdGRDbGFzcyI6Mzp7czo1OiJ0aXRsZSI7czoxODoiSW5zdHJ1Y3RvciBEZXRhaWxzI%',1,0)) AND (bip.visible !=0),'YES','') AS 'Instructor Details Block visible' # This is a hack based on UUencoded string data from the title of HTML "Instructor Details" block<br />
<br />
#, IF(bi.configdata LIKE '%ZGl0IHRoaXMgYmxvY2s%','NO','') AS 'Instructor Details Block Updated' # HTML block has string 'dit this block'<br />
<br />
#, IF(COUNT(bi.id) - SUM(IF(bi.configdata LIKE 'Tzo4OiJzdGRDbGFzcyI6Mzp7czo1OiJ0aXRsZSI7czoxODoiSW5zdHJ1Y3RvciBEZXRhaWxzI%',1,0)),'YES','') AS 'possible extra instructor blocks' #looking for any HTML block with "instructor" in the title<br />
<br />
, IF(c.format='topcoll','YES', c.format) AS 'Collapsed Topics course format' # change this if you want to test for a different format<br />
, IF(cfo.value = 2, 'YES','NO') AS 'weeks structure'<br />
<br />
, cfw.value AS 'weeks defined in course settings'<br />
<br />
, COUNT(DISTINCT IF(((cs.name IS NOT NULL) AND (cs.visible = 1) AND (cs.section != '0') AND (cs.sequence IS NOT NULL)),cs.id,NULL)) AS '# of weeks named & visible (includes orphans)'<br />
<br />
, COUNT(DISTINCT IF(m.name LIKE 'forum', cm.id, NULL)) AS 'Forums'<br />
, COUNT(DISTINCT IF(m.name LIKE 'forum' ,cs.id , NULL)) AS 'Weeks with Forum'<br />
<br />
, COUNT(DISTINCT IF(gi.id, cm.id, NULL)) AS 'Activities'<br />
, COUNT(DISTINCT IF(gi.id, cs.id, NULL)) AS 'Weeks with Activities'<br />
, COUNT(DISTINCT mgi.id) AS 'Manual Grade Items'<br />
<br />
, COUNT(DISTINCT IF((gi.id IS NULL) AND (m.name NOT IN ('forum','label')),cm.id,NULL)) AS 'Resources'<br />
, COUNT(DISTINCT IF((gi.id IS NULL) AND (m.name NOT IN ('forum','label')), cs.id, NULL)) AS 'Weeks with Resources'<br />
<br />
# Here are some other things you could check for per course<br />
#,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm JOIN prefix_modules AS m ON cm.module = m.id WHERE cm.course = c.id AND m.name LIKE '%forum%') AS Forums<br />
<br />
#,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm JOIN prefix_modules AS m ON cm.module = m.id WHERE cm.course = c.id AND m.name LIKE '%quiz%') AS Quizzes<br />
<br />
#,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm JOIN prefix_modules AS m ON cm.module = m.id WHERE cm.course = c.id AND m.name LIKE '%assign%') AS Assignments<br />
<br />
#,(SELECT COUNT(prefix_resource.id) FROM prefix_resource JOIN prefix_course ON prefix_course.id = prefix_resource.course WHERE c.id = prefix_resource.course) AS Files<br />
<br />
#,(SELECT COUNT(prefix_url.id) FROM prefix_url JOIN prefix_course ON prefix_course.id = prefix_url.course WHERE c.id = prefix_url.course) AS Links<br />
<br />
,(SELECT FROM_UNIXTIME(MAX(prefix_resource.timemodified))<br />
FROM prefix_resource<br />
JOIN prefix_course ON prefix_course.id = prefix_resource.course WHERE c.id = prefix_resource.course AND prefix_resource.name LIKE '%syllabus%') AS SyllabusDate<br />
<br />
,(SELECT TO_DAYS(NOW())-TO_DAYS(FROM_UNIXTIME(MAX(prefix_resource.timemodified)))<br />
FROM prefix_resource<br />
JOIN prefix_course ON prefix_course.id = prefix_resource.course WHERE c.id = prefix_resource.course AND prefix_resource.name LIKE '%syllabus%') AS DaysAgo<br />
<br />
, IF(COUNT(DISTINCT IF(f.type LIKE 'news', f.id,NULL)),'YES','NO' ) AS 'Announcement Forum Visible'<br />
<br />
, IF(COUNT(DISTINCT IF(f.type LIKE 'news', fd.id,NULL)),'YES','NO' ) AS 'Announcement posted'<br />
<br />
FROM prefix_course AS c<br />
LEFT JOIN prefix_course_categories as cc ON c.category = cc.id<br />
LEFT JOIN prefix_context AS ctxx ON c.id = ctxx.instanceid <br />
<br />
LEFT JOIN prefix_block_positions AS bpi ON bpi.contextid = ctxx.id AND bpi.blockinstanceid = '43692' # mooprofile<br />
LEFT JOIN prefix_block_positions AS bpm ON bpm.contextid = ctxx.id AND bpm.blockinstanceid = '43962' # messages<br />
LEFT JOIN prefix_block_positions AS bpa ON bpa.contextid = ctxx.id AND bpa.blockinstanceid = '43963' # activities<br />
LEFT JOIN prefix_block_positions AS bpr ON bpr.contextid = ctxx.id AND bpr.blockinstanceid = '38368' # html research help<br />
<br />
LEFT JOIN prefix_course_sections AS cs ON cs.course = c.id AND cs.visible = 1 AND cs.sequence IS NOT NULL<br />
LEFT JOIN prefix_course_modules AS cm ON cm.course = c.id AND cm.section = cs.id <br />
LEFT JOIN prefix_modules AS m ON m.id = cm.module<br />
LEFT JOIN prefix_grade_items AS gi ON gi.courseid = c.id AND gi.itemmodule = m.name AND gi.iteminstance = cm.instance<br />
<br />
LEFT JOIN prefix_forum AS f ON f.course = c.id AND cm.instance = f.id AND cm.visible = 1<br />
LEFT JOIN prefix_forum_discussions AS fd ON fd.forum = f.id<br />
<br />
# attach manual grade items to course-- they don't have modules<br />
LEFT JOIN prefix_grade_items AS mgi ON mgi.courseid = c.id and mgi.itemtype = 'manual'<br />
<br />
LEFT JOIN prefix_course_format_options AS cfo ON cfo.courseid = c.id AND cfo.name = 'layoutstructure'<br />
LEFT JOIN prefix_course_format_options AS cfw ON cfw.courseid = c.id AND cfw.name = 'numsections'<br />
<br />
LEFT JOIN prefix_block_instances AS bi ON bi.parentcontextid = ctxx.id AND bi.blockname = 'html' AND (bi.configdata LIKE '%SW5zdHJ1Y3Rvc%' or bi.configdata LIKE '%bnN0cnVjdG9y%')<br />
LEFT JOIN prefix_block_positions AS bip ON bip.blockinstanceid = bi.id<br />
<br />
WHERE RIGHT(c.idnumber,2) IN ('OL', 'BL', 'HY') <br />
# AND substring(cc.path,2,2) IN ('26') # Staging<br />
#AND substring(cc.path,2,3) IN ('158') # UG<br />
AND cc.idnumber LIKE '%staging%'<br />
AND ctxx.contextlevel = 50<br />
<br />
GROUP BY c.shortname<br />
</code><br />
<br />
===Module instances + Module HITs by role teacher and student in course===<br />
<code sql><br />
SELECT <br />
m.name AS "Module name"<br />
, COUNT(*) AS "Module count"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_log AS l <br />
WHERE l.course = cm.course AND l.module = m.name ) AS "Hits"<br />
<br />
,(SELECT COUNT(*)<br />
FROM prefix_log AS l<br />
JOIN prefix_context AS con ON con.instanceid= l.course AND con.contextlevel=50<br />
JOIN prefix_role_assignments AS ra ON ra.contextid= con.id AND ra.userid= l.userid AND ra.roleid = 5 <br />
WHERE l.course = cm.course AND l.module = m.name) AS "Students HITs"<br />
<br />
,(SELECT COUNT(*)<br />
FROM prefix_log AS l<br />
JOIN prefix_context AS con ON con.instanceid= l.course AND con.contextlevel=50<br />
JOIN prefix_role_assignments AS ra ON ra.contextid= con.id AND ra.userid= l.userid AND ra.roleid = 3 <br />
WHERE l.course = cm.course AND l.module = m.name) AS "Teachers HITs"<br />
<br />
FROM mdl_course_modules AS cm<br />
JOIN mdl_modules AS m on m.id = cm.module<br />
WHERE cm.course = '%%COURSEID%%'<br />
GROUP BY cm.module<br />
</code><br />
<br />
===Course Syllabus===<br />
Contributed by Elizabeth Dalton, Granite State College / Moodle HQ<br />
<br />
This report requires ELIS. It runs from within a course and constructs a course syllabus based on content in the course and in the ELIS entries related to the course (Class Instance, Course Description, and Program). It is a proof-of-concept of an automated syllabus production tool. Fields such as "Course Policies" and "Teaching Philosophy" are added to the Class Instance records, and instructors enter them there. The Instructor Bio is pulled from the User Profile of all users with the Teacher role in the course.<br />
<br />
<code sql><br />
SELECT <br />
<br />
c.fullname AS 'fullname'<br />
, ec.idnumber AS 'elis-id'<br />
, DATE_FORMAT(FROM_UNIXTIME(ec.startdate), '%b %e, %Y') AS 'start'<br />
, DATE_FORMAT(FROM_UNIXTIME(ec.enddate), '%b %e, %Y') AS 'end'<br />
, ecd.name AS 'longname'<br />
, ecd.code AS 'coursecode'<br />
, ecd.credits AS 'coursecredits'<br />
, ecd.syllabus AS 'description'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'learning-outcomes'<br />
WHERE ctxecd.id = eft.contextid) AS 'outcomes'<br />
<br />
,(SELECT CONCAT('<a target="_blank" href="%%WWWROOT%%/user/view.php',CHAR(63),'id=',u.id,'">',u.firstname,' ', u.lastname,'</a> ', u.email)<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS 'Instructor' <br />
<br />
, (SELECT efc.data<br />
FROM prefix_local_eliscore_fld_data_char AS efc<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = efc.fieldid AND ef.shortname = 'term-code'<br />
WHERE ctxci.id = efc.contextid) AS 'termcode'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'prerequisites'<br />
WHERE ctxecd.id = eft.contextid) AS 'prerequisites'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'textbooks'<br />
WHERE ctxci.id = eft.contextid) AS 'textbooks'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'other-class-materials'<br />
WHERE ctxci.id = eft.contextid) AS 'other-class-materials'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'course-policies'<br />
WHERE ctxci.id = eft.contextid) AS 'course-policies'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'teaching-philosophy'<br />
WHERE ctxci.id = eft.contextid) AS 'teaching-philosophy'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'course-methods'<br />
WHERE ctxci.id = eft.contextid) AS 'course-methods'<br />
<br />
,(SELECT u2.description<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u2 ON u2.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS 'Bio'<br />
<br />
,(SELECT<br />
<br />
GROUP_CONCAT(DISTINCT CONCAT(<br />
<br />
'<tr><td style="border: solid #000 .5px">',IF(gc.parent IS NOT NULL, gc.fullname, 'None')<br />
, ' </td><td style="border: solid #000 .5px"> '<br />
,IF(gc.parent IS NOT NULL, ROUND(gic.aggregationcoef, 2), ROUND( gi.aggregationcoef, 2)+ROUND(mgi.aggregationcoef, 2))<br />
<br />
) SEPARATOR '</td></tr>')<br />
#get grade categories<br />
FROM prefix_grade_categories AS gc <br />
# back from categories to grade items to get aggregations and weights<br />
LEFT JOIN prefix_grade_items AS gic ON gic.courseid = gc.courseid AND gic.itemtype = 'category' AND gic.aggregationcoef != 0 AND (LOCATE(gic.iteminstance, gc.path) OR (gc.parent IS NULL))<br />
# attach grade items to activities<br />
LEFT JOIN prefix_grade_items AS gi ON gi.courseid = gc.courseid AND gi.itemtype = 'mod' AND gi.categoryid = gc.id AND gi.hidden != 1<br />
# attach manual grade items to course-- they don't have modules<br />
LEFT JOIN prefix_grade_items AS mgi ON mgi.courseid = gc.courseid and mgi.itemtype = 'manual' AND mgi.categoryid = gc.id<br />
WHERE gc.courseid = c.id ) AS 'grade categories'<br />
<br />
, '<table width = "50%" >' AS 'table start'<br />
, '<table width = "100%" >' AS 'table start 2'<br />
, '</table>' AS 'table end'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'activities-schedule'<br />
WHERE ctxci.id = eft.contextid) AS 'activities'<br />
<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'schedule'<br />
WHERE ctxci.id = eft.contextid) AS 'schedule'<br />
<br />
, (SELECT eft.data<br />
FROM prefix_local_eliscore_fld_data_text AS eft<br />
JOIN prefix_local_eliscore_field AS ef ON ef.id = eft.fieldid AND ef.shortname = 'grading-scale'<br />
WHERE ctxepm.id = eft.contextid) AS 'gradescale'<br />
<br />
FROM<br />
prefix_course AS c <br />
<br />
# connect moodle course to ELIS class instance<br />
LEFT JOIN prefix_local_elisprogram_cls_mdl AS ecm ON ecm.moodlecourseid = c.id<br />
LEFT JOIN prefix_local_elisprogram_cls AS ec ON ec.id = ecm.classid<br />
# class instance context<br />
LEFT JOIN prefix_context AS ctxci ON ctxci.instanceid = ec.id AND ctxci.contextlevel = '14'<br />
<br />
# connect ELIS class instance to ELIS course description<br />
LEFT JOIN prefix_local_elisprogram_crs AS ecd ON ecd.id = ec.courseid<br />
# course description context<br />
LEFT JOIN prefix_context AS ctxecd ON ctxecd.instanceid = ecd.id AND ctxecd.contextlevel = '13'<br />
<br />
#connect ELIS program to ELIS Course Description<br />
LEFT JOIN prefix_local_elisprogram_pgm_crs AS epc ON epc.courseid = ecd.id<br />
LEFT JOIN prefix_local_elisprogram_pgm AS epm ON epm.id = epc.curriculumid<br />
# course program context<br />
LEFT JOIN prefix_context AS ctxepm ON ctxepm.instanceid = epm.id AND ctxepm.contextlevel = '11'<br />
<br />
WHERE<br />
<br />
c.id = %%COURSEID%%<br />
</code><br />
<br />
===Course Activities Helper===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
This report provides a list of the graded activities in a course.<br />
* '''Note''': Only graded activities are displayed.<br />
* '''Note''': This is a "Global" report. Run it within a course to see a summary of the contents of that course.<br />
* '''Note''': This report assumes that course sections each last one week.<br />
<br />
<code sql><br />
# 303 Course Activities Helper<br />
<br />
SELECT <br />
<br />
gi.itemmodule AS 'activity type'<br />
# cs.section AS 'section number'<br />
<br />
# Calculation assumes each section lasts one week<br />
, CONCAT(DATE_FORMAT(FROM_UNIXTIME(c.startdate + (7*24*60*60* (cs.section-1))), '%b %e, %Y'),' - <br>',DATE_FORMAT(FROM_UNIXTIME(c.startdate + (7*24*60*60* (cs.section))), '%b %e, %Y')) AS 'Date'<br />
<br />
, gi.itemname AS 'activity name'<br />
<br />
#, (SELECT asg.intro FROM prefix_assign AS asg WHERE asg.id = cm.instance) AS 'intro'<br />
<br />
#, (SELECT f.intro FROM prefix_forum AS f WHERE f.id = cm.instance) AS 'f intro'<br />
<br />
, CASE gi.itemmodule <br />
WHEN 'assign' THEN (SELECT asg.intro FROM prefix_assign AS asg WHERE asg.id = gi.iteminstance) <br />
WHEN 'forum' THEN (SELECT f.intro FROM prefix_forum AS f WHERE f.id = gi.iteminstance) <br />
WHEN 'quiz' THEN (SELECT q.intro FROM prefix_quiz AS q WHERE q.id = gi.iteminstance) <br />
END AS 'test case'<br />
<br />
#, (SELECT GROUP_CONCAT(CONCAT(' - ',gi.itemname) SEPARATOR '<BR>') FROM prefix_grade_items AS gi JOIN prefix_course_modules AS cm ON gi.iteminstance = cm.instance WHERE gi.gradetype = 1 AND gi.hidden != 1 AND gi.courseid = c.id AND cm.course = c.id AND cm.section = cs.id ) AS 'activities'<br />
<br />
<br />
FROM<br />
prefix_course AS c <br />
<br />
#get grade sections<br />
LEFT JOIN prefix_course_sections AS cs ON cs.course = c.id AND cs.section > 0 AND cs.section <=14<br />
LEFT JOIN prefix_course_modules AS cm ON cm.course = c.id AND cm.section = cs.id<br />
<br />
#LEFT JOIN prefix_assign AS asg ON asg.id = cm.instance<br />
<br />
JOIN prefix_grade_items AS gi ON gi.iteminstance = cm.instance AND gi.gradetype = 1 AND gi.hidden != 1 AND gi.courseid = c.id AND cm.course = c.id AND cm.section = cs.id<br />
<br />
WHERE<br />
c.id = %%COURSEID%%<br />
AND cs.visible = 1<br />
<br />
ORDER BY gi.itemmodule, cs.section<br />
</code><br />
<br />
==Grade and Course Completion Reports==<br />
===Site-Wide Grade Report with All Items===<br />
Shows grades for all course items along with course totals for each student. Works with ad-hoc reports or Configurable Reports<br />
<code sql><br />
SELECT u.firstname AS 'First' , u.lastname AS 'Last', <br />
u.firstname + ' ' + u.lastname AS 'Display Name', <br />
c.fullname AS 'Course', <br />
cc.name AS 'Category',<br />
<br />
CASE <br />
WHEN gi.itemtype = 'course' <br />
THEN c.fullname + ' Course Total'<br />
ELSE gi.itemname<br />
END AS 'Item Name',<br />
<br />
ROUND(gg.finalgrade,2) AS Grade,<br />
DATEADD(ss,gg.timemodified,'1970-01-01') AS Time<br />
<br />
FROM prefix_course AS c<br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid<br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
JOIN prefix_grade_grades AS gg ON gg.userid = u.id<br />
JOIN prefix_grade_items AS gi ON gi.id = gg.itemid<br />
JOIN prefix_course_categories as cc ON cc.id = c.category<br />
<br />
WHERE gi.courseid = c.id <br />
ORDER BY lastname<br />
</code><br />
For MySQL users, you'll need to use the MySQL DATE_ADD function instead of DATEADD. Replace the line:<br />
<code><br />
DATEADD(ss,gg.timemodified,'1970-01-01') AS Time<br />
</code><br />
with:<br />
<code><br />
FROM_UNIXTIME(gg.timemodified) AS Time<br />
</code><br />
And:<br />
<code><br />
u.firstname + ' ' + u.lastname AS 'Display Name', <br />
</code><br />
with:<br />
<code><br />
CONCAT(u.firstname,' ',u.lastname) AS 'Display Name', <br />
</code><br />
<br />
===Site-Wide Grade Report with Just Course Totals===<br />
A second site-wide grade report for all students that just shows course totals. Works with ad-hoc reports or Configurable Reports<br />
<code sql><br />
SELECT u.firstname AS 'First' , u.lastname AS 'Last', u.firstname + ' ' + u.lastname AS 'Display Name', <br />
cc.name AS 'Category',<br />
CASE <br />
WHEN gi.itemtype = 'course' <br />
THEN c.fullname + ' Course Total'<br />
ELSE gi.itemname<br />
END AS 'Item Name',<br />
<br />
ROUND(gg.finalgrade,2) AS Grade,<br />
DATEADD(ss,gg.timemodified,'1970-01-01') AS Time<br />
<br />
FROM prefix_course AS c<br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid<br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
JOIN prefix_grade_grades AS gg ON gg.userid = u.id<br />
JOIN prefix_grade_items AS gi ON gi.id = gg.itemid<br />
JOIN prefix_course_categories as cc ON cc.id = c.category<br />
<br />
WHERE gi.courseid = c.id AND gi.itemtype = 'course'<br />
<br />
ORDER BY lastname<br />
</code><br />
<br />
For MySQL users:<br />
<code sql><br />
SELECT u.firstname AS 'First' , u.lastname AS 'Last', CONCAT(u.firstname , ' ' , u.lastname) AS 'Display Name', <br />
c.fullname AS 'Course', <br />
cc.name AS 'Category',<br />
CASE <br />
WHEN gi.itemtype = 'course' <br />
THEN CONCAT(c.fullname, ' - Total')<br />
ELSE gi.itemname<br />
END AS 'Item Name',<br />
<br />
ROUND(gg.finalgrade,2) AS Grade,<br />
FROM_UNIXTIME(gg.timemodified) AS TIME<br />
<br />
FROM prefix_course AS c<br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid<br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
JOIN prefix_grade_grades AS gg ON gg.userid = u.id<br />
JOIN prefix_grade_items AS gi ON gi.id = gg.itemid<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
<br />
WHERE gi.courseid = c.id AND gi.itemtype = 'course'<br />
ORDER BY lastname<br />
</code><br />
<br />
===Learner report by Learner with grades===<br />
Which Learners in which course and what are the grades<br />
<code sql><br />
SELECT u.firstname AS 'Name' , u.lastname AS 'Surname', c.fullname AS 'Course', cc.name AS 'Category', <br />
CASE WHEN gi.itemtype = 'Course' <br />
THEN c.fullname + ' Course Total' <br />
ELSE gi.itemname <br />
END AS 'Item Name', ROUND(gg.finalgrade,2) AS Score,ROUND(gg.rawgrademax,2) AS Max, ROUND(gg.finalgrade / gg.rawgrademax * 100 ,2) as Percentage,<br />
<br />
if (ROUND(gg.finalgrade / gg.rawgrademax * 100 ,2) > 79,'Yes' , 'No') as Pass<br />
<br />
FROM prefix_course AS c <br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid <br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id <br />
JOIN prefix_user AS u ON u.id = ra.userid <br />
JOIN prefix_grade_grades AS gg ON gg.userid = u.id <br />
JOIN prefix_grade_items AS gi ON gi.id = gg.itemid <br />
JOIN prefix_course_categories AS cc ON cc.id = c.category <br />
WHERE gi.courseid = c.id and gi.itemname != 'Attendance'<br />
ORDER BY `Name` ASC<br />
</code><br />
<br />
===User Course Completion===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
A very simple report with a list of course completion status by username. Completions are noted by date, blank otherwise. <br />
<br />
<code sql><br />
SELECT <br />
u.username, <br />
c.shortname, <br />
DATE_FORMAT(FROM_UNIXTIME(p.timecompleted),'%Y-%m-%d') AS completed<br />
FROM prefix_course_completions AS p<br />
JOIN prefix_course AS c ON p.course = c.id<br />
JOIN prefix_user AS u ON p.userid = u.id<br />
WHERE c.enablecompletion = 1<br />
ORDER BY u.username<br />
</code><br />
<br />
===User Course Completion with Criteria===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
A report with course completions by username, with Aggregation method, Criteria types, and Criteria detail where available.<br />
<br />
<code sql><br />
SELECT u.username AS user, <br />
c.shortname AS course,<br />
DATE_FORMAT(FROM_UNIXTIME(t.timecompleted),'%Y-%m-%d') AS completed,<br />
CASE<br />
WHEN (SELECT a.method FROM prefix_course_completion_aggr_methd AS a WHERE (a.course = c.id AND a.criteriatype IS NULL) = 1) THEN "Any"<br />
ELSE "All"<br />
END AS aggregation,<br />
CASE <br />
WHEN p.criteriatype = 1 THEN "Self"<br />
WHEN p.criteriatype = 2 THEN "By Date"<br />
WHEN p.criteriatype = 3 THEN "Unenrol Status"<br />
WHEN p.criteriatype = 4 THEN "Activity"<br />
WHEN p.criteriatype = 5 THEN "Duration"<br />
WHEN p.criteriatype = 6 THEN "Course Grade"<br />
WHEN p.criteriatype = 7 THEN "Approve by Role"<br />
WHEN p.criteriatype = 8 THEN "Previous Course"<br />
END AS criteriatype,<br />
CASE <br />
WHEN p.criteriatype = 1 THEN "*"<br />
WHEN p.criteriatype = 2 THEN DATE_FORMAT(FROM_UNIXTIME(p.timeend),'%Y-%m-%d')<br />
WHEN p.criteriatype = 3 THEN t.unenroled<br />
WHEN p.criteriatype = 4 THEN <br />
CONCAT('<a target="_new" href="%%WWWROOT%%/mod/',p.module,'/view.php?id=',p.moduleinstance,'">',p.module,'</a>')<br />
WHEN p.criteriatype = 5 THEN p.enrolperiod<br />
WHEN p.criteriatype = 6 THEN CONCAT('Needed: ',ROUND(p.gradepass,2),' Achieved: ',ROUND(t.gradefinal,2)) <br />
WHEN p.criteriatype = 7 THEN p.role<br />
WHEN p.criteriatype = 8 THEN (SELECT pc.shortname FROM prefix_course AS pc WHERE pc.id = p.courseinstance)<br />
END AS criteriadetail <br />
FROM prefix_course_completion_crit_compl AS t<br />
JOIN prefix_user AS u ON t.userid = u.id<br />
JOIN prefix_course AS c ON t.course = c.id<br />
JOIN prefix_course_completion_criteria AS p ON t.criteriaid = p.id<br />
<br />
</code><br />
<br />
===Courses with Completion Enabled and their settings===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
List of all courses with completion enabled and their Aggregation setting, Criteria types, and Criteria details.<br />
<br />
<code sql><br />
<br />
SELECT c.shortname AS Course, <br />
CASE<br />
WHEN (SELECT a.method FROM prefix_course_completion_aggr_methd AS a WHERE (a.course = t.course AND a.criteriatype IS NULL)) = 2 THEN "All"<br />
ELSE "Any"<br />
END AS Course_Aggregation,<br />
CASE<br />
WHEN t.criteriatype = 1 THEN "Self completion"<br />
WHEN t.criteriatype = 2 THEN "Date done by" <br />
WHEN t.criteriatype = 3 THEN "Unenrolement" <br />
WHEN t.criteriatype = 4 THEN "Activity completion" <br />
WHEN t.criteriatype = 5 THEN "Duration in days" <br />
WHEN t.criteriatype = 6 THEN "Final grade" <br />
WHEN t.criteriatype = 7 THEN "Approve by role" <br />
WHEN t.criteriatype = 8 THEN "Previous course"<br />
END AS Criteria_type,<br />
CASE<br />
WHEN t.criteriatype = 1 THEN "On"<br />
WHEN t.criteriatype = 2 THEN DATE_FORMAT(FROM_UNIXTIME(t.timeend),'%Y-%m-%d')<br />
WHEN t.criteriatype = 3 THEN "On"<br />
WHEN t.criteriatype = 4 THEN<br />
CONCAT('<a target="_new" href="%%WWWROOT%%/mod/',t.module,'/view.php?id=',t.moduleinstance,'">',t.module,'</a>')<br />
WHEN t.criteriatype = 5 THEN ROUND(t.enrolperiod/86400)<br />
WHEN t.criteriatype = 6 THEN ROUND(t.gradepass,2)<br />
WHEN t.criteriatype = 7 THEN (SELECT r.shortname FROM prefix_role AS r WHERE r.id = t.role)<br />
WHEN t.criteriatype = 8 THEN (SELECT pc.shortname FROM prefix_course AS pc WHERE pc.id = t.courseinstance)<br />
END AS Criteria_detail<br />
FROM prefix_course_completion_criteria as t<br />
JOIN prefix_course AS c ON t.course = c.id<br />
WHERE c.enablecompletion = 1<br />
ORDER BY course<br />
</code><br />
<br />
===Course Completion Report with custom dates===<br />
<br />
List of users who completed multiple or single course/s from a start date to end date chosen by the user. The output gives username, name, course name, completion date and score<br />
<br />
<code sql><br />
<br />
SELECT u.username AS 'User Name',<br />
CONCAT(u.firstname , ' ' , u.lastname) AS 'Name',<br />
c.shortname AS 'Course Name', <br />
DATE_FORMAT(FROM_UNIXTIME(p.timecompleted),'%W %e %M, %Y') AS 'Completed Date',<br />
ROUND(c4.gradefinal,2) AS 'Score'<br />
FROM prefix_course_completions AS p<br />
JOIN prefix_course AS c ON p.course = c.id<br />
JOIN prefix_user AS u ON p.userid = u.id<br />
JOIN prefix_course_completion_crit_compl AS c4 ON u.id = c4.userid<br />
WHERE c.enablecompletion = 1 AND (p.timecompleted IS NOT NULL OR p.timecompleted !='') <br />
AND (p.timecompleted>= :start_date AND p.timecompleted<=:end_date)<br />
GROUP BY u.username<br />
ORDER BY c.shortname<br />
<br />
</code><br />
<br />
===Scales used in activities===<br />
<code sql><br />
SELECT scale.name<br />
,CONCAT('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS Course<br />
,CONCAT('<a target="_new" href="%%WWWROOT%%/mod/',gi.itemmodule,'/view.php?id=',cm.id,'">',gi.itemname,'</a>') AS "Module View"<br />
,CONCAT('<a target="_new" href="%%WWWROOT%%/course/modedit.php?up','date=',cm.id,'">',gi.itemname,'</a>') AS "Module Settings"<br />
<br />
FROM prefix_grade_items AS gi<br />
JOIN prefix_course AS c ON c.id = gi.courseid<br />
JOIN prefix_course_modules AS cm ON cm.course = gi.courseid AND cm.instance = gi.iteminstance<br />
JOIN prefix_scale AS scale ON scale.id = gi.scaleid<br />
WHERE gi.scaleid IS NOT NULL<br />
</code><br />
<br />
<br />
===Extra Credit Items by Name Only===<br />
Contributed by Eric Strom<br />
<br />
This query identifies grade items in visible courses with student enrollment that have "extra credit" in the name of the item but set as extra credit in the grade settings. Includes the defined course start date, count of students and instructors, and a clickable email link of instructor (first found record if more than one).<br />
<br />
<code sql><br />
SELECT DATE(FROM_UNIXTIME(c.startdate)) AS StartDate, <br />
concat('<a target="_new" href="%%WWWROOT%%/grade/edit/tree/index.php',CHAR(63),'id=',<br />
c.id,'">',c.idnumber,'</a>') AS Course_ID, gi.itemname AS Item_Name<br />
<br />
,(SELECT COUNT( ra.userid ) FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = c.id) AS Students<br />
<br />
,(SELECT COUNT( ra.userid ) FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id) AS Instructors<br />
<br />
,(SELECT DISTINCT concat('<a href="mailto:',u.email,'">',u.email,'</a>')<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_user AS u ON ra.userid = u.id<br />
JOIN prefix_context AS ctx ON ctx.id = ra.contextid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id AND ctx.contextlevel = 50 LIMIT 1) AS 'Instructor_Email'<br />
<br />
,now() AS Report_Timestamp<br />
<br />
FROM prefix_grade_items AS gi<br />
JOIN prefix_course AS c ON gi.courseid = c.id<br />
<br />
WHERE gi.itemname LIKE '%extra credit%' <br />
AND gi.gradetype = '1' <br />
AND gi.hidden = '0' <br />
AND gi.aggregationcoef = '0' <br />
AND c.visible = 1<br />
AND (SELECT COUNT( ra.userid ) FROM prefix_role_assignments AS ra JOIN prefix_context AS ctx ON ra.contextid = ctx.id WHERE ra.roleid = 5 AND ctx.instanceid = c.id) > 0<br />
<br />
GROUP BY Course_ID, gi.id<br />
ORDER BY StartDate, Course_ID<br />
<br />
%%FILTER_SEARCHTEXT:Course_ID:~%%<br />
</code><br />
<br />
===Site Wide Number of Courses Completed by User===<br />
Contributed by Ken St. John<br />
<br />
Simple report that shows the number of completed courses for all users site wide<br />
<br />
<code sql><br />
SELECT u.lastname, u.firstname,<br />
COUNT(p.timecompleted) AS TotalCompletions<br />
FROM prefix_course_completions AS p<br />
JOIN prefix_user AS u ON p.userid = u.id<br />
GROUP BY p.userid<br />
ORDER BY u.lastname<br />
</code><br />
<br />
==Activity Module Reports==<br />
<br />
=== User activity completions with dates===<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
This report shows the users completion status of activities across all courses. It is intended to be uses with Configurable Reports filters for user, start and end times, and also to be able to search the Module names. <br />
<br />
Note: The CASE statement with module numbers may differ on different systems, depending on the number give to the module when the site was created or the module added to the site. These are common default numbers, but you should check your id numbers for them in the course_modules table and adjust as required. You can also add other, third-party plugins too if you wish. <br />
<br />
<code sql><br />
SELECT<br />
u.username As 'User',<br />
c.shortname AS 'Course',<br />
m.name AS Activitytype, <br />
CASE <br />
WHEN cm.module = 1 THEN (SELECT a1.name FROM prefix_assign a1 WHERE a1.id = cm.instance)<br />
WHEN cm.module = 2 THEN (SELECT a2.name FROM prefix_assignment a2 WHERE a2.id = cm.instance)<br />
WHEN cm.module = 3 THEN (SELECT a3.name FROM prefix_book a3 WHERE a3.id = cm.instance)<br />
WHEN cm.module = 4 THEN (SELECT a4.name FROM prefix_chat a4 WHERE a4.id = cm.instance)<br />
WHEN cm.module = 5 THEN (SELECT a5.name FROM prefix_choice a5 WHERE a5.id = cm.instance)<br />
WHEN cm.module = 6 THEN (SELECT a6.name FROM prefix_data a6 WHERE a6.id = cm.instance)<br />
WHEN cm.module = 7 THEN (SELECT a7.name FROM prefix_feedback a7 WHERE a7.id = cm.instance)<br />
WHEN cm.module = 8 THEN (SELECT a8.name FROM prefix_folder a8 WHERE a8.id = cm.instance)<br />
WHEN cm.module = 9 THEN (SELECT a9.name FROM prefix_forum a9 WHERE a9.id = cm.instance)<br />
WHEN cm.module = 10 THEN (SELECT a10.name FROM prefix_glossary a10 WHERE a10.id = cm.instance)<br />
WHEN cm.module = 11 THEN (SELECT a11.name FROM prefix_imscp a11 WHERE a11.id = cm.instance)<br />
WHEN cm.module = 12 THEN (SELECT a12.name FROM prefix_label a12 WHERE a12.id = cm.instance)<br />
WHEN cm.module = 13 THEN (SELECT a13.name FROM prefix_lesson a13 WHERE a13.id = cm.instance)<br />
WHEN cm.module = 14 THEN (SELECT a14.name FROM prefix_lti a14 WHERE a14.id = cm.instance)<br />
WHEN cm.module = 15 THEN (SELECT a15.name FROM prefix_page a15 WHERE a15.id = cm.instance)<br />
WHEN cm.module = 16 THEN (SELECT a16.name FROM prefix_quiz a16 WHERE a16.id = cm.instance)<br />
WHEN cm.module = 17 THEN (SELECT a17.name FROM prefix_resource a17 WHERE a17.id = cm.instance)<br />
WHEN cm.module = 18 THEN (SELECT a18.name FROM prefix_scorm a18 WHERE a18.id = cm.instance)<br />
WHEN cm.module = 19 THEN (SELECT a19.name FROM prefix_survey a19 WHERE a19.id = cm.instance)<br />
WHEN cm.module = 20 THEN (SELECT a20.name FROM prefix_url a20 WHERE a20.id = cm.instance)<br />
WHEN cm.module = 21 THEN (SELECT a21.name FROM prefix_wiki a21 WHERE a21.id = cm.instance)<br />
WHEN cm.module = 22 THEN (SELECT a22.name FROM prefix_workshop a22 WHERE a22.id = cm.instance)<br />
END AS Actvityname,<br />
# cm.section AS Coursesection,<br />
CASE<br />
WHEN cm.completion = 0 THEN '0 None'<br />
WHEN cm.completion = 1 THEN '1 Self'<br />
WHEN cm.completion = 2 THEN '2 Auto'<br />
END AS Activtycompletiontype, <br />
CASE<br />
WHEN cmc.completionstate = 0 THEN 'In Progress'<br />
WHEN cmc.completionstate = 1 THEN 'Completed'<br />
WHEN cmc.completionstate = 2 THEN 'Completed with Pass'<br />
WHEN cmc.completionstate = 3 THEN 'Completed with Fail'<br />
ELSE 'Unknown'<br />
END AS 'Progress', <br />
DATE_FORMAT(FROM_UNIXTIME(cmc.timemodified), '%Y-%m-%d %H:%i') AS 'When'<br />
FROM prefix_course_modules_completion cmc <br />
JOIN prefix_user u ON cmc.userid = u.id<br />
JOIN prefix_course_modules cm ON cmc.coursemoduleid = cm.id<br />
JOIN prefix_course c ON cm.course = c.id<br />
JOIN prefix_modules m ON cm.module = m.id<br />
# skip the predefined admin and guest user<br />
WHERE u.id > 2<br />
# config reports filters<br />
%%FILTER_USERS:u.username%%<br />
%%FILTER_SEARCHTEXT:m.name:~%%<br />
%%FILTER_STARTTIME:cmc.timemodified:>%% %%FILTER_ENDTIME:cmc.timemodified:<%%<br />
<br />
ORDER BY u.username<br />
<br />
</code><br />
<br />
===How many SCORM activities are used in each Course===<br />
<code sql><br />
SELECT cm.course,c.fullname ,m.name <br />
,concat('<a target="_new" href="%%WWWROOT%%/mod/scorm/index.php?id=',c.id,'">',count(cm.id),'</a>') AS Counter<br />
<br />
FROM `prefix_course_modules` as cm <br />
JOIN prefix_modules as m ON cm.module=m.id <br />
JOIN prefix_course as c ON cm.course = c.id <br />
WHERE m.name LIKE '%scorm%' <br />
GROUP BY cm.course,cm.module <br />
ORDER BY count(cm.id) desc<br />
</code><br />
<br />
===SCORM Usage by Course Start Date===<br />
Contributed by Elizabeth Dalton, Granite State College <br />
<br />
Report of number of inclusions of SCORM activities in courses, filtered by course start date.<br />
<br />
<code sql><br />
SELECT <br />
<br />
CONCAT('<a target="_blank" href="%%WWWROOT%%/course/view.php',CHAR(63),'id=',c.id,'">',c.shortname,'</a>') AS 'course'<br />
<br />
, cc.name AS 'Category'<br />
, scm.name AS 'Sample Activity Name'<br />
, FROM_UNIXTIME(c.startdate) AS 'Course Start Date'<br />
, COUNT(DISTINCT cm.id) AS 'Resources Used'<br />
#, FROM_UNIXTIME(cm.added) AS 'resource added'<br />
<br />
<br />
FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id AND m.name LIKE 'SCO%'<br />
<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
JOIN prefix_scorm AS scm ON scm.id = cm.instance<br />
<br />
WHERE<br />
1<br />
<br />
%%FILTER_STARTTIME:c.startdate:>%%<br />
%%FILTER_ENDTIME:c.startdate:<%%<br />
<br />
GROUP BY c.shortname, m.name<br />
ORDER BY c.startdate, c.shortname <br />
</code><br />
<br />
=== LTI (External Tool) Usage by Course Start Date===<br />
Contributed by Elizabeth Dalton, Granite State College <br />
<br />
Report of number of inclusions of LTI (External Tool) Usage activities in courses, filtered by course start date.<br />
<br />
<code sql><br />
SELECT <br />
<br />
CONCAT('<a target="_blank" href="%%WWWROOT%%/course/view.php',CHAR(63),'id=',c.id,'">',c.shortname,'</a>') AS 'course'<br />
<br />
, cc.name AS 'Category'<br />
, lti.name AS 'Sample Activity Name'<br />
, FROM_UNIXTIME(c.startdate) AS 'Course Start Date'<br />
, COUNT(DISTINCT cm.id) AS 'Resources Used'<br />
#, FROM_UNIXTIME(cm.added) AS 'resource added'<br />
<br />
<br />
FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id AND m.name LIKE 'lti'<br />
<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
JOIN prefix_lti AS lti ON lti.id = cm.instance<br />
WHERE<br />
1<br />
<br />
%%FILTER_STARTTIME:c.startdate:>%%<br />
%%FILTER_ENDTIME:c.startdate:<%%<br />
<br />
GROUP BY c.shortname, m.name<br />
ORDER BY c.startdate, c.shortname <br />
</code><br />
<br />
===Detailed ACTIONs for each MODULE===<br />
<code sql><br />
SELECT module,action,count(id) as counter<br />
FROM prefix_log<br />
GROUP BY module,action<br />
ORDER BY module,counter desc<br />
</code><br />
<br />
===Most popular ACTIVITY===<br />
<code sql><br />
SELECT COUNT(l.id) hits, module<br />
FROM prefix_log l<br />
WHERE module != 'login' AND module != 'course' AND module != 'role'<br />
GROUP BY module<br />
ORDER BY hits DESC<br />
</code><br />
<br />
===System wide use of ACTIVITIES and RESOURCES===<br />
<code sql><br />
SELECT count( cm.id ) AS counter, m.name<br />
FROM `prefix_course_modules` AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
GROUP BY cm.module<br />
ORDER BY counter DESC<br />
</code><br />
<br />
===LOG file ACTIONS per MODULE per COURSE (IDs)===<br />
<code sql><br />
select course,module,action,count(action) as summa from prefix_log<br />
where action <> 'new'<br />
group by course,action,module<br />
order by course,module,action<br />
</code><br />
<br />
===System Wide usage count of various course Activities===<br />
(Tested and works fine in Moodle 2.x)<br />
Like: Forum, Wiki, Blog, Assignment, Database,<br />
#Within specific category<br />
#Teacher name in course<br />
<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') as Course<br />
<br />
,(SELECT CONCAT(u.firstname,' ', u.lastname) AS Teacher<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS Teacher <br />
<br />
,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%') AS Wikis<br />
,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
WHERE cm.course = c.id AND m.name LIKE '%blog%') AS Blogs<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
WHERE cm.course = c.id AND m.name LIKE '%forum%') AS Forums<br />
<br />
,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
WHERE cm.course = c.id AND m.name LIKE '%data%') AS Databses<br />
<br />
,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
WHERE cm.course = c.id AND m.name LIKE '%assignment%') AS Assignments<br />
<br />
,(SELECT Count( ra.userid ) AS Users FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = c.id) AS Students<br />
<br />
FROM prefix_course AS c<br />
WHERE c.category IN ( 18)<br />
ORDER BY Wikis DESC,Blogs DESC, Forums DESC<br />
</code><br />
<br />
===Course wiki usage/activity over the last 6 semesters===<br />
<code sql><br />
SELECT "Courses with Wikis"<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%'<br />
and c.fullname LIKE CONCAT('%','2010','%') and c.fullname LIKE '%Semester A%') AS '2010 <br/> Semester A'<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%'<br />
and c.fullname LIKE CONCAT('%','2010','%') and c.fullname LIKE '%Semester B%') AS '2010 <br/> Semester B'<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%'<br />
and c.fullname LIKE CONCAT('%','תשעא','%') and c.fullname LIKE '%סמסטר א%') AS 'תשעא <br/> סמסטר א'<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%'<br />
and c.fullname LIKE CONCAT('%','תשעא','%') and c.fullname LIKE '%סמסטר ב%') AS 'תשעא <br/> סמסטר ב'<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%'<br />
and c.fullname LIKE CONCAT('%','תשעב','%') and c.fullname LIKE '%סמסטר א%') AS 'תשעב <br/> סמסטר א'<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%'<br />
and c.fullname LIKE CONCAT('%','תשעב','%') and c.fullname LIKE '%סמסטר ב%') AS 'תשעב <br/> סמסטר ב'<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%'<br />
and c.fullname LIKE CONCAT('%','תשעג','%') and c.fullname LIKE '%סמסטר א%') AS 'תשעג <br/> סמסטר א'<br />
<br />
,(SELECT count( m.name ) AS count FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_course AS c ON c.id = cm.course<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%'<br />
and c.fullname LIKE CONCAT('%','תשעג','%') and c.fullname LIKE '%סמסטר ב%') AS 'תשעג <br/> סמסטר ב'<br />
</code><br />
<br />
===Detailed WIKI activity (per wiki per course)===<br />
Including Number of Students in course (for reference)<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',cm.course,'">',c.fullname,'</a>') as CourseID <br />
,(SELECT Count( ra.userid ) AS Users<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = c.id ) AS Students<br />
,m.name<br />
, ( SELECT count(id) FROM prefix_log WHERE cmid = cm.id AND action LIKE '%updat%' ) as 'UPDAT E'<br />
, ( SELECT count(id) FROM prefix_log WHERE cmid = cm.id AND action LIKE '%annotate%' ) as ANNOTATE<br />
, ( SELECT count(id) FROM prefix_log WHERE cmid = cm.id AND action LIKE '%comment%' ) as COMMENT<br />
, ( SELECT count(id) FROM prefix_log WHERE cmid = cm.id AND action LIKE '%add%' ) as 'A DD'<br />
, ( SELECT count(id) FROM prefix_log WHERE cmid = cm.id AND action LIKE '%edit%' ) as EDIT<br />
, ( SELECT count(id) FROM prefix_log WHERE cmid = cm.id AND action NOT LIKE '%view%' ) as 'All (NO View)'<br />
FROM `prefix_course_modules` as cm <br />
JOIN prefix_modules as m ON cm.module=m.id <br />
JOIN prefix_course as c ON cm.course = c.id <br />
WHERE m.name LIKE '%wiki%'<br />
GROUP BY cm.course,cm.module<br />
ORDER BY 'All (NO View)' DESC<br />
</code><br />
<br />
===Wiki usage, system wide===<br />
(you can filter the output by selecting some specific course categories : "WHERE c.category IN ( 8,13,15)")<br />
<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') as Course<br />
<br />
,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
WHERE cm.course = c.id AND m.name LIKE '%wiki%') AS Wikis<br />
<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.course = c.id AND l.module LIKE '%wiki%') AS 'WikiActivity<br/>ALL'<br />
<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.course = c.id AND l.module LIKE '%wiki%' and l.action LIKE '%add%' ) AS 'WikiActivity<br/>ADD'<br />
<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.course = c.id AND l.module LIKE '%wiki%' and l.action LIKE '%edit%' ) AS 'WikiActivity<br/>EDIT'<br />
<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.course = c.id AND l.module LIKE '%wiki%' and l.action LIKE '%annotate%' ) AS 'WikiActivity<br/>ANNOTATE'<br />
<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.course = c.id AND l.module LIKE '%wiki%' and l.action LIKE '%comments%' ) AS 'WikiActivity<br/>Comments'<br />
<br />
,(SELECT Count( ra.userid ) AS Users FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = c.id) AS Students<br />
<br />
,(SELECT count(*) FROM prefix_ouwiki_pages as ouwp<br />
JOIN prefix_ouwiki as ouw ON ouw.id = ouwp.subwikiid<br />
WHERE ouw.course = c.id GROUP BY ouw.course ) as OUWikiPages<br />
<br />
,(SELECT count( DISTINCT nwp.pagename ) FROM prefix_wiki_pages AS nwp<br />
JOIN prefix_wiki AS nw ON nw.id = nwp.dfwiki WHERE nw.course = c.id ) As NWikiPages<br />
<br />
FROM prefix_course AS c<br />
WHERE c.category IN ( 8,13,15)<br />
HAVING Wikis > 0<br />
ORDER BY 'WikiActivity<br/>ALL' DESC<br />
</code><br />
<br />
===Aggregated Teacher activity by "WEB2" Modules===<br />
(Tested and works fine in Moodle 2.x)<br />
The NV column shows activity without VIEW log activity<br />
<code sql><br />
SELECT ra.userid, u.firstname,u.lastname<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.userid = u.id AND l.module LIKE '%wiki%') AS Wiki<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.userid = u.id AND l.module LIKE '%wiki%' AND l.action NOT LIKE '%view%') AS Wiki_NV<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.userid = u.id AND l.module LIKE '%forum%') AS Forum<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.userid = u.id AND l.module LIKE '%forum%' AND l.action NOT LIKE '%view%') AS Forum_NV<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.userid = u.id AND l.module LIKE '%blog%') AS Blog<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.userid = u.id AND l.module LIKE '%blog%' AND l.action NOT LIKE '%view%') AS Blog_NV<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.userid = u.id AND l.module LIKE '%assignment%') AS Assignment<br />
,(SELECT count(*) FROM prefix_log as l WHERE l.userid = u.id AND l.module LIKE '%assignment%' AND l.action NOT LIKE '%view%') AS Assignment_NV<br />
FROM prefix_role_assignments AS ra <br />
JOIN prefix_user AS u ON u.id = ra.userid <br />
WHERE ra.roleid = 3 <br />
GROUP BY ra.userid<br />
</code><br />
<br />
===List all the certificates issued, sort by variables in the custom profile fields===<br />
Note: The SQL queries look intimidating at first, but isn't really that difficult to learn. I've seen in the forums that users wanted to do 'site-wide' groups in 1.9x. This is sort of the idea. It pulls all the certificates issued to all users sorted by the custom profile fields, which in my case is the Units or Depts (i.e. my site wide groups). Why certificates? I've explored with both grades and quizzes, the course admins are not really interested in the actual grades but whether the learner received a certificate (i.e. passed the course with x, y, z activities). It also saves me from creating groups and assigning them into the right groups. Even assigning in bulk is not efficient, since I have upward of 25 groups per course and constantly new learners enrolling in courses. The limitation is something to do with the server? as it only pull 5000 rows of data. If anyone figured out how to change this, please let me know. In the meantime, the work around is to pull only a few units/depts at a time to limit the number of rows. This is fine at the moment, since each course admin are only responsible for certain units/depts.<br />
<br />
<code sql><br />
SELECT<br />
DATE_FORMAT( FROM_UNIXTIME(prefix_certificate_issues.timecreated), '%Y-%m-%d' ) AS Date,<br />
prefix_certificate_issues.classname AS Topic,<br />
prefix_certificate.name AS Certificate,<br />
prefix_certificate_issues.studentname as Name,<br />
prefix_user_info_data.data AS Units<br />
<br />
FROM<br />
prefix_certificate_issues<br />
<br />
INNER JOIN prefix_user_info_data<br />
on prefix_certificate_issues.userid = prefix_user_info_data.userid<br />
<br />
INNER JOIN prefix_certificate<br />
on prefix_certificate_issues.certificateid = prefix_certificate.id<br />
<br />
WHERE prefix_user_info_data.data='Unit 1'<br />
OR prefix_user_info_data.data='Unit 2'<br />
OR prefix_user_info_data.data='Unit 3'<br />
<br />
ORDER BY Units, Name, Topic ASC<br />
</code><br />
<br />
<br />
=== All Simple Certificates Earned in the Site===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
Basic report of all certificates earned with the Simple Certificate plugin module in the whole site, sorted by most recent first. (Note: this uses the MySQL [http://www.mysqltutorial.org/mysql-date_format/ DATE_FORMAT] function.)<br />
<br />
<code sql><br />
SELECT<br />
CONCAT (u.firstname, ' ',u.lastname) As 'User',<br />
c.fullname AS 'Course',<br />
sc.name AS 'Certificate',<br />
DATE_FORMAT( FROM_UNIXTIME(sci.timecreated), '%Y-%m-%d' ) As 'Date Awarded'<br />
# sci.code 'CertificateId'<br />
FROM prefix_simplecertificate_issues sci<br />
JOIN prefix_user u ON sci.userid = u.id<br />
JOIN prefix_simplecertificate sc ON sci.certificateid = sc.id<br />
JOIN prefix_course AS c ON sc.course = c.id<br />
ORDER BY sci.timecreated DESC<br />
</code><br />
<br />
If you want to limit this to the most recent ones, you can add a condition to limit it to a certain number of days past. For example, adding this WHERE clause (above the ORDER BY) will show only those earned in the last 30 days:<br />
<code sql><br />
WHERE DATEDIFF(NOW(),FROM_UNIXTIME(sci.timecreated) ) < 30<br />
</code><br />
<br />
===Counter Blog usage in Courses,system wide===<br />
What teachers in what courses, uses blogs and how many + student count in that course.<br />
<code sql><br />
<br />
SELECT ( @counter := @counter+1) as counter, <br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') as Course<br />
<br />
,( SELECT DISTINCT CONCAT(u.firstname,' ',u.lastname)<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_user AS u ON ra.userid = u.id<br />
JOIN prefix_context AS ctx ON ctx.id = ra.contextid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id AND ctx.contextlevel = 50 LIMIT 1) AS Teacher<br />
<br />
,(SELECT count( m.name ) AS count FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
WHERE cm.course = c.id AND m.name LIKE '%blog%') AS Blogs<br />
<br />
,(SELECT Count( ra.userid ) AS Users FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = c.id) AS Students<br />
<br />
FROM prefix_course AS c, (SELECT @counter := 0) as s_init<br />
WHERE c.category IN ( 8,13,15)<br />
HAVING Blogs > 0<br />
ORDER BY Blogs DESC<br />
</code><br />
<br />
=== Elluminate (Blackboard Collaborate) - system wide usage===<br />
<code sql><br />
SELECT e.name As Session ,er.recordingsize<br />
,c.fullname As Course<br />
,u.firstname,u.lastname <br />
,DATE_FORMAT(FROM_UNIXTIME(e.timestart),'%d-%m-%Y') AS dTimeStart<br />
,concat('<a target="_new" href="%%WWWROOT%%/moodle/mod/elluminate/loadrecording.php?id=',er.id,'">Show</a>') AS RecordedSession<br />
<br />
FROM prefix_elluminate_recordings AS er<br />
JOIN prefix_elluminate AS e ON e.meetingid = er.meetingid<br />
JOIN prefix_course as c ON c.id = e.course<br />
JOIN prefix_user AS u ON u.id = e.creator <br />
ORDER BY er.recordingsize DESC<br />
</code><br />
<br />
<br />
=== Choice ===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
Results of the Choice activity. For all courses, shows course shortname, username, the Choice text, and the answer chosen by the user.<br />
<br />
<code sql><br />
SELECT c.shortname AS course, u.username, h.name as question, o.text AS answer<br />
FROM prefix_choice AS h<br />
JOIN prefix_course AS c ON h.course = c.id<br />
JOIN prefix_choice_answers AS a ON h.id = a.choiceid<br />
JOIN prefix_user AS u ON a.userid = u.id<br />
JOIN prefix_choice_options AS o ON a.optionid = o.id<br />
</code><br />
<br />
=== Assignment type usage in courses ===<br />
<code sql><br />
SELECT <br />
<br />
CONCAT('<a target="_new" href="%%WWWROOT%%/mod/assign/index.php?id=',c.id,'">',c.fullname,'</a>') AS "List assignments"<br />
<br />
,(SELECT COUNT(*) FROM prefix_assign WHERE c.id = course) AS Assignments<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_assign_plugin_config AS apc<br />
JOIN prefix_assign AS iassign ON iassign.id = apc.assignment <br />
WHERE iassign.course = c.id AND apc.plugin = 'file' AND apc.subtype = 'assignsubmission' AND apc.name = 'enabled' AND apc.value = '1'<br />
#GROUP BY apc.plugin<br />
) AS "File Assignments"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_assign_plugin_config AS apc<br />
JOIN prefix_assign AS iassign ON iassign.id = apc.assignment <br />
WHERE iassign.course = c.id AND apc.plugin = 'onlinetext' AND apc.subtype = 'assignsubmission' AND apc.name = 'enabled' AND apc.value = '1'<br />
) AS "Online Assignments"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_assign_plugin_config AS apc<br />
JOIN prefix_assign AS iassign ON iassign.id = apc.assignment <br />
WHERE iassign.course = c.id AND apc.plugin = 'pdf' AND apc.subtype = 'assignsubmission' AND apc.name = 'enabled' AND apc.value = '1'<br />
) AS "PDF Assignments"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_assign_plugin_config AS apc<br />
JOIN prefix_assign AS iassign ON iassign.id = apc.assignment <br />
WHERE iassign.course = c.id AND apc.plugin = 'offline' AND apc.subtype = 'assignsubmission' AND apc.name = 'enabled' AND apc.value = '1'<br />
) AS "Offline Assignments"<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_assign_plugin_config AS apc<br />
JOIN prefix_assign AS iassign ON iassign.id = apc.assignment <br />
WHERE iassign.course = c.id AND apc.plugin = 'comments' AND apc.subtype = 'assignsubmission' AND apc.name = 'enabled' AND apc.value = '1'<br />
) AS "Assignments Comments"<br />
<br />
FROM prefix_assign AS assign<br />
JOIN prefix_course AS c ON c.id = assign.course<br />
GROUP BY c.id <br />
</code><br />
<br />
==Moodle Learning Analytics Reports==<br />
<br />
===Average Cognitive Depth and Social Breadth===<br />
<br />
Here is a simple SQL snippet to calculate average cognitive depth and social breadth indicators for all students in the system. This one ignores indicator values of 0, as they are nulls as defined in this model.<br />
Contributed by Elizabeth Dalton, Moodle HQ<br />
<br />
<code sql><br />
SELECT<br />
<br />
i.contextid,<br />
i.sampleid,<br />
<br />
TRUNC(AVG(CASE<br />
WHEN i.indicator LIKE '%cognitive%' THEN i.value <br />
ELSE '0'<br />
END),2) AS "Average Cognitive Depth",<br />
<br />
TRUNC(AVG(CASE<br />
WHEN i.indicator LIKE '%social%' THEN i.value <br />
ELSE '0'<br />
END),2) AS "Average Social Breadth"<br />
<br />
FROM prefix_analytics_indicator_calc as i<br />
WHERE<br />
i.value != 0<br />
GROUP BY i.contextid, i.sampleid<br />
</code><br />
<br />
==Assignment Module Reports==<br />
===All Ungraded Assignments===<br />
<br />
'''NOTE: This query is for the deprecated old Assignment module from Moodle 2.2, not the new Assignments module. Please update this query if you are the author or it will be removed as the 2.2 Assignment module is no longer supported since release 2.7.<br />
''' See: [https://docs.moodle.org/dev/Moodle_2.7_release_notes#Assignment]<br />
<br />
Returns all the submitted assignments that still need grading<br />
<code sql><br />
select <br />
u.firstname AS "First",<br />
u.lastname AS "Last",<br />
c.fullname AS "Course",<br />
a.name AS "Assignment"<br />
<br />
from prefix_assignment_submissions as asb<br />
join prefix_assignment as a ON a.id = asb.assignment<br />
join prefix_user as u ON u.id = asb.userid<br />
join prefix_course as c ON c.id = a.course<br />
join prefix_course_modules as cm ON c.id = cm.course<br />
<br />
where asb.grade < 0 and cm.instance = a.id<br />
and cm.module = 1<br />
<br />
order by c.fullname, a.name, u.lastname<br />
</code><br />
<br />
===All Ungraded Assignments w/ Link===<br />
<br />
'''NOTE: This query is for the deprecated old Assignment module from Moodle 2.2, not the new Assignments module. Please update this query if you are the author or it will be removed as the 2.2 Assignment module is no longer supported since release 2.7.<br />
''' See: [https://docs.moodle.org/dev/Moodle_2.7_release_notes#Assignment]<br />
<br />
<br />
Returns all the submitted assignments that still need grading, along with a link that goes directly to the submission to grade it. The links work if you view the report within Moodle.<br />
<code sql><br />
select <br />
u.firstname AS "First",<br />
u.lastname AS "Last",<br />
c.fullname AS "Course",<br />
a.name AS "Assignment",<br />
<br />
'<a href="http://education.varonis.com/mod/assignment/submissions.php' + char(63) +<br />
+ 'id=' + cast(cm.id as varchar) + '&userid=' + cast(u.id as varchar) <br />
+ '&mode=single&filter=0&offset=2">' + a.name + '</a>'<br />
AS "Assignmentlink"<br />
<br />
<br />
from prefix_assignment_submissions as asb<br />
join prefix_assignment as a ON a.id = asb.assignment<br />
join prefix_user as u ON u.id = asb.userid<br />
join prefix_course as c ON c.id = a.course<br />
join prefix_course_modules as cm ON c.id = cm.course<br />
<br />
where asb.grade < 0 and cm.instance = a.id and cm.module = 1<br />
<br />
order by c.fullname, a.name, u.lastname<br />
</code><br />
<br />
===Assignments (and Quizzes) waiting to be graded===<br />
<br />
'''NOTE: This query is for the deprecated old Assignment module from Moodle 2.2, not the new Assignments module. Please update this query if you are the author or it will be removed as the 2.2 Assignment module is no longer supported since release 2.7.<br />
''' See: [https://docs.moodle.org/dev/Moodle_2.7_release_notes#Assignment]<br />
<br />
<br />
This report requires a YEAR filter to be added (Available when using the latest block/configurable_reports)<br />
<br />
Which you can always remove, to make this query work on earlier versions.<br />
<br />
The report includes: <br />
*number of quizzes<br />
*unFinished Quiz attempts<br />
*Finished Quiz attempts<br />
*number of students<br />
*number of Assignments<br />
*number of submitted answers by students <br />
*number of unchecked assignments (waiting for the Teacher) in a Course.<br />
<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS Course<br />
<br />
,(SELECT CONCAT(u.firstname,' ', u.lastname) AS Teacher<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS Teacher <br />
<br />
,concat('<a target="_new" href="%%WWWROOT%%/mod/assignment/index.php?id=',c.id,'">מטלות</a>') AS Assignments<br />
<br />
,concat('<a target="_new" href="%%WWWROOT%%/mod/quiz/index.php?id=',c.id,'">בחנים</a>') AS 'Quizzes'<br />
<br />
,(SELECT COUNT(*) <br />
FROM prefix_course_modules cm <br />
JOIN prefix_modules as m ON m.id = cm.module <br />
WHERE m.name LIKE 'quiz' AND cm.course = c.id <br />
GROUP BY cm.course <br />
) AS 'nQuizzes'<br />
<br />
,(SELECT COUNT(*)<br />
FROM prefix_quiz_attempts AS qa<br />
JOIN prefix_quiz AS q ON q.id = qa.quiz<br />
WHERE q.course = c.id<br />
AND qa.timefinish = 0<br />
GROUP BY q.course) AS 'unFinished Quiz attempts'<br />
<br />
,(SELECT COUNT(*)<br />
FROM prefix_quiz_attempts AS qa<br />
JOIN prefix_quiz AS q ON q.id = qa.quiz<br />
WHERE q.course = c.id<br />
AND qa.timefinish > 0<br />
GROUP BY q.course) AS 'finished quiz attempts'<br />
<br />
,(SELECT Count( ra.userid ) AS Users<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5<br />
AND ctx.instanceid = c.id<br />
) AS nStudents<br />
<br />
<br />
,(<br />
SELECT count(a.id)<br />
FROM prefix_assignment AS a <br />
JOIN prefix_course_modules AS cm ON a.course = cm.course <br />
WHERE cm.instance = a.id AND cm.module = 1 AND a.course = c.id<br />
) nAssignments<br />
<br />
,(<br />
SELECT count(*)<br />
FROM prefix_assignment AS a <br />
WHERE a.course = c.id AND FROM_UNIXTIME(a.timedue) > NOW()<br />
GROUP BY a.course<br />
) 'Open <br/>Assignments'<br />
<br />
, CONCAT(ROUND( (100 / iAssignments ) * iOpenAssignments ) ,'%') 'unFinished <br/>Assignments <br/>(percent)'<br />
<br />
,(<br />
SELECT count(asb.id)<br />
FROM prefix_assignment_submissions AS asb<br />
JOIN prefix_assignment AS a ON a.id = asb.assignment<br />
JOIN prefix_course_modules AS cm ON a.course = cm.course <br />
WHERE asb.grade < 0 AND cm.instance = a.id AND cm.module = 1 AND a.course = c.id<br />
) 'unChecked <br/>Submissions' <br />
<br />
,(<br />
SELECT count(asb.id)<br />
FROM prefix_assignment_submissions AS asb<br />
JOIN prefix_assignment AS a ON a.id = asb.assignment<br />
JOIN prefix_course_modules AS cm ON a.course = cm.course <br />
WHERE cm.instance = a.id AND cm.module = 1 AND a.course = c.id<br />
) 'Submitted <br/>Assignments'<br />
<br />
FROM prefix_course AS c<br />
LEFT JOIN (<br />
SELECT course, count(*) AS iAssignments<br />
FROM prefix_assignment AS a <br />
GROUP BY a.course <br />
) AS tblAssignmentsCount ON tblAssignmentsCount.course = c.id<br />
<br />
LEFT JOIN (<br />
SELECT course, count(*) AS iOpenAssignments<br />
FROM prefix_assignment AS a <br />
WHERE FROM_UNIXTIME(a.timedue) > NOW()<br />
GROUP BY a.course <br />
) AS tblOpenAssignmentsCount ON tblOpenAssignmentsCount.course = c.id<br />
<br />
WHERE 1=1 <br />
#AND c.fullname LIKE '%תשעג%'<br />
%%FILTER_YEARS:c.fullname%%<br />
## You can enable the SEMESTER filter as well, <br />
## by uncommenting the following line:<br />
## %%FILTER_SEMESTERS:c.fullname%%<br />
ORDER BY 'Open <br/>Assignments' DESC<br />
</code><br />
<br />
===Rubrics without zero values in criteria===<br />
Contributed by Eric Strom<br />
<br />
Rubric calculations in Moodle can fail to align with instructors expectations if they lack a zero value for each criterion used in the assessment. From documentation at https://docs.moodle.org/32/en/Rubrics#Grade_calculation:<br />
<br />
"For example, when the teacher in the previous example chose both levels with 1 point, the plain sum would be 2 points. But that is actually the lowest possible score so it maps to the grade 0 in Moodle.<br />
TIP: To avoid confusion from this sort of thing, we recommend including a level with 0 points in every rubric criterion."<br />
<br />
This report identifies rubrics having criteria without a zero value level and the courses they live in. This also refines to only assignments with active rubrics that are visible to students in the course. Links to the each rubric id is the direct link to edit the rubric. Fix by adding a zero level for each criteria that is missing it. In general, the grading changes that result will be in the students' favor.<br />
<br />
Includes search filter of course idnumber.<br />
<br />
<code sql><br />
SELECT cat.name AS Department, concat('<a target="_new" href="%%WWWROOT%%/course/view.php',CHAR(63),'id=',<br />
c.id,'">',c.idnumber,'</a>') AS Course_ID, <br />
c.fullname AS Course_Name, <br />
concat('<a target="_new" href="%%WWWROOT%%/grade/grading/form/rubric/edit.php',CHAR(63),'areaid=',gd.areaid,'">',gd.areaid,'</a>') AS Rubric<br />
FROM prefix_course AS c<br />
JOIN prefix_course_categories AS cat <br />
ON cat.id = c.category<br />
JOIN prefix_course_modules AS cm <br />
ON c.id=cm.course<br />
JOIN prefix_context AS ctx <br />
ON cm.id = ctx.instanceid<br />
JOIN prefix_grading_areas AS garea <br />
ON ctx.id = garea.contextid<br />
JOIN prefix_grading_definitions AS gd <br />
ON garea.id = gd.areaid<br />
JOIN prefix_gradingform_rubric_criteria AS crit <br />
ON gd.id = crit.definitionid<br />
JOIN prefix_gradingform_rubric_levels AS levels <br />
ON levels.criterionid = crit.id<br />
WHERE cm.visible='1' AND garea.activemethod = 'rubric' AND (crit.id NOT IN<br />
(SELECT crit.id<br />
FROM prefix_gradingform_rubric_criteria AS crit<br />
JOIN prefix_gradingform_rubric_levels AS levels <br />
ON levels.criterionid = crit.id WHERE levels.score = '0'))<br />
<br />
GROUP BY Rubric<br />
ORDER BY Course_ID, Rubric<br />
<br />
%%FILTER_SEARCHTEXT:c.idnumber:~%%<br />
</code><br />
<br />
===Who is using "Single File Upload" assignment===<br />
<code sql><br />
SELECT <br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS Course<br />
<br />
,(SELECT CONCAT(u.firstname,' ', u.lastname) AS Teacher<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS Teacher <br />
<br />
,ass.name as "Assignment Name"<br />
<br />
FROM <br />
prefix_assignment as ass<br />
<br />
JOIN <br />
prefix_course as c ON c.id = ass.course<br />
<br />
WHERE `assignmenttype` LIKE 'uploadsingle'<br />
</code><br />
<br />
==Feedback Module Reports==<br />
===List the answers to all the Feedback activities within the current course, submitted by the current user===<br />
<code sql><br />
SELECT /* crs.fullname as "Course name", f.name AS "Journal name", CONCAT(u.firstname,' ',UPPER(u.lastname)) as "Participant", */ /* include these fields if you want to check the composition of the recordset */<br />
DATE_FORMAT(FROM_UNIXTIME(c.timemodified),'%W %e %M, %Y') as "Answer Date",<br />
CASE i.typ WHEN 'label' THEN i.presentation ELSE i.name END as "Topic", /* usually labels are used as section titles, so you'd want them present in the recordset */<br />
v.value as "My Answer"<br />
<br />
FROM prefix_feedback AS f<br />
INNER JOIN prefix_course as crs on crs.id=f.course %%FILTER_COURSES:f.course%% <br />
INNER JOIN prefix_feedback_item AS i ON f.id=i.feedback<br />
INNER JOIN prefix_feedback_completed AS c on f.id=c.feedback %%FILTER_COURSEUSER:c.userid%% <br />
LEFT JOIN prefix_feedback_value AS v on v.completed=c.id AND v.item=i.id<br />
INNER JOIN prefix_user AS u on c.userid=u.id<br />
<br />
WHERE c.id = %%COURSEID%% AND u.id = %%USERID%% AND c.anonymous_response = 1 /* This clause limits the recordset to the current course and the current user and includes/ excludes the anonymous responses as needed */<br />
<br />
ORDER BY f.id, c.timemodified, i.id<br />
</code><br />
<br />
===Show all Feedbacks from all courses for all users including showing names of anonymous users===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
Shows all Feedbacks in all Courses with all multi-choice questions and answers of all users including showing the username of anonymous users. Also shows tryly anonymous users on the front page as 'Not-logged-in' users. This is a rough report, not a pretty report, and is limited to multiple-choice type questions, but is shows the answer number and the list of possible answers in raw form. I post it here as a basis for further reports, and also as away to get the identities of anonymous users if needed.<br />
<br />
<code sql><br />
SELECT <br />
c.shortname AS Course, <br />
f.name AS Feedback,<br />
# i.id AS Itemid,<br />
i.name AS Itemname,<br />
i.label AS Itemlabel,<br />
CASE <br />
WHEN f.anonymous = 1 AND u.id != 0 THEN CONCAT(u.username, ' :ANON')<br />
WHEN fc.userid = 0 THEN 'Not-logged-in'<br />
ELSE u.username<br />
END AS 'User',<br />
DATE_FORMAT(FROM_UNIXTIME(fc.timemodified),'%Y-%m-%d %H:%i') AS "Completed",<br />
v.value AS "Choice",<br />
CASE <br />
WHEN i.typ = 'multichoice' THEN<br />
IF ( SUBSTRING(i.presentation,1,6)='d>>>>>',<br />
SUBSTRING(i.presentation,7),<br />
i.presentation)<br />
ELSE i.presentation<br />
END AS "Answers",<br />
i.typ,<br />
i.dependitem,<br />
i.dependvalue<br />
<br />
FROM prefix_feedback f<br />
JOIN prefix_course c ON c.id=f.course <br />
JOIN prefix_feedback_item AS i ON f.id=i.feedback<br />
JOIN prefix_feedback_completed fc ON f.id=fc.feedback<br />
LEFT JOIN prefix_feedback_value v ON v.completed=fc.id AND v.item=i.id<br />
LEFT JOIN prefix_user AS u ON fc.userid=u.id<br />
WHERE i.typ != 'pagebreak'<br />
</code><br />
<br />
==Resource Module Reports==<br />
===List "Recently uploaded files"===<br />
see what users are uploading<br />
<code sql><br />
SELECT FROM_UNIXTIME(time,'%Y %M %D %h:%i:%s') as time ,ip,userid,url,info <br />
FROM `prefix_log` <br />
WHERE `action` LIKE 'upload' <br />
ORDER BY `prefix_log`.`time` DESC<br />
</code><br />
<br />
===List Courses that loaded a specific file: "X"===<br />
Did the Teacher (probably) uploaded course's Syllabus ?<br />
<code sql><br />
SELECT c.id, c.fullname FROM `prefix_log` as l <br />
JOIN prefix_course as c ON c.id = l.course <br />
WHERE `action` LIKE '%upload%' AND ( info LIKE '%Syllabus%' OR info LIKE '%Sylabus%' ) GROUP BY c.id<br />
</code><br />
<br />
===All resources that link to some specific external website===<br />
+ link to course<br />
+ who's the teacher<br />
+ link to external resource<br />
<code sql><br />
SELECT<br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS Course<br />
,c.shortname,r.name<br />
,(SELECT CONCAT(u.firstname,' ', u.lastname) AS Teacher<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id LIMIT 1) AS Teacher<br />
,concat('<a target="_new" href="%%WWWROOT%%/mod/resource/view.php?id=',r.id,'">',r.name,'</a>') AS Resource<br />
FROM prefix_resource AS r <br />
JOIN prefix_course AS c ON r.course = c.id<br />
WHERE r.reference LIKE 'http://info.oranim.ac.il/home%' <br />
</code><br />
<br />
==="Compose Web Page" RESOURCE count===<br />
<code sql><br />
SELECT course,prefix_course.fullname, COUNT(*) AS Total<br />
FROM `prefix_resource`<br />
JOIN `prefix_course` ON prefix_course.id = prefix_resource.course<br />
WHERE type='html'<br />
GROUP BY course<br />
</code><br />
<br />
===Resource count in courses===<br />
+ (First)Teacher name<br />
+ Where course is inside some specific Categories<br />
<code sql><br />
SELECT <br />
COUNT(*) AS count<br />
,r.course <br />
,c.shortname shortname<br />
,c.fullname coursename<br />
,( SELECT DISTINCT CONCAT(u.firstname,' ',u.lastname)<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_user as u ON ra.userid = u.id<br />
JOIN prefix_context AS ctx ON ctx.id = ra.contextid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = r.course AND ctx.contextlevel = 50 LIMIT 1) AS Teacher<br />
FROM prefix_resource r <br />
JOIN prefix_course c ON r.course = c.id<br />
WHERE c.category IN (10,13,28,18,26)<br />
GROUP BY r.course<br />
ORDER BY COUNT(*) DESC<br />
</code><br />
<br />
===Delete all the automated backup files===<br />
Prepare bash cli script to delete all the automated backup files on the file system. (clean up some disk space)<br />
<code sql><br />
SELECT CONCAT( 'rm -f /var/moodledatanew/filedir/', SUBSTRING( contenthash, 1, 2 ) , '/', SUBSTRING( contenthash, 3, 2 ) , '/', contenthash ) <br />
FROM `mdl_files` <br />
WHERE `filename` LIKE '%mbz%'<br />
AND filearea = 'automated'<br />
</code><br />
<br />
Find out how much disk space is used by all automated backup files:<br />
<code sql><br />
SELECT SUM(filesize)/(1024*1024*1024) FROM `mdl_files` WHERE `filename` LIKE '%mbz%' AND filearea = 'automated'<br />
</code><br />
<br />
==Forum Module Reports==<br />
===print all User's post in course Forums===<br />
%%COURSEID%% is a variable the is replace by the current CourseID you are running the sql report from. if you are using the latest block/configurable_reports ! (You can always change it to a fixed course or remove it to display all courses.)<br />
<code sql><br />
SELECT <br />
concat('<a target="_new" href="%%WWWROOT%%/mod/forum/user.php?course=',c.id,'&id=',u.id,'&mode=posts">',CONCAT(u.firstname,' ', u.lastname),'</a>') As Fullname<br />
,concat('<a target="_new" href="%%WWWROOT%%/mod/forum/view.php?f=',fd.forum,'">',f.name,'</a>') AS Forum<br />
,count(*) as Posts<br />
,(SELECT count(*) FROM prefix_forum_discussions AS ifd JOIN prefix_forum as iforum ON iforum.id = ifd.forum WHERE ifd.userid = fp.userid AND iforum.id = f.id) AS cAllDiscussion<br />
<br />
FROM prefix_forum_posts AS fp <br />
JOIN prefix_user as u ON u.id = fp.userid <br />
JOIN prefix_forum_discussions AS fd ON fp.discussion = fd.id <br />
JOIN prefix_forum AS f ON f.id = fd.forum <br />
JOIN prefix_course as c ON c.id = fd.course <br />
WHERE fd.course = %%COURSEID%% <br />
GROUP BY f.id,u.id<br />
ORDER BY u.id<br />
</code><br />
<br />
===FORUM use Count per COURSE -- not including NEWS Forum!===<br />
<code sql><br />
SELECT prefix_course.fullname, prefix_forum.course, count(*) as total FROM prefix_forum<br />
INNER JOIN prefix_course<br />
ON prefix_course.id = prefix_forum.course<br />
WHERE NOT(prefix_forum.type = 'news')<br />
GROUP BY prefix_forum.course<br />
ORDER BY total desc<br />
</code><br />
<br />
===FORUM use Count per COURSE by type -- not including NEWS Forum!===<br />
<code sql><br />
SELECT prefix_course.fullname, prefix_forum.course, prefix_forum.type, count(*) as total FROM prefix_forum<br />
INNER JOIN prefix_course<br />
ON prefix_course.id = prefix_forum.course<br />
WHERE NOT(prefix_forum.type = 'news')<br />
GROUP BY prefix_forum.course,prefix_forum.type<br />
ORDER BY total desc<br />
</code><br />
<br />
===Forum activity - system wide===<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.id,'</a>') AS CourseID<br />
,( SELECT DISTINCT CONCAT(u.firstname,' ',u.lastname)<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_user AS u ON ra.userid = u.id<br />
JOIN prefix_context AS ctx ON ctx.id = ra.contextid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id AND ctx.contextlevel = 50 LIMIT 1) AS Teacher<br />
,c.fullname as Course<br />
,f.type<br />
,(SELECT Count( ra.userid ) AS Users FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = c.id) AS Students<br />
, fd.forum, f.name,count(*) AS cPostAndDisc<br />
,(SELECT count(*) FROM prefix_forum_discussions AS ifd WHERE ifd.forum = f.id) AS cDiscussion<br />
FROM prefix_forum_posts AS fp<br />
JOIN prefix_forum_discussions AS fd ON fd.id = fp.discussion<br />
JOIN prefix_forum AS f ON f.id = fd.forum<br />
JOIN prefix_course AS c ON c.id = f.course<br />
WHERE f.type != 'news' AND c.fullname LIKE '%2013%'<br />
## WHERE 1=1 <br />
## %%FILTER_YEARS:c.fullname%%<br />
## You can enable the SEMESTER filter as well, <br />
## by uncommenting the following line:<br />
## %%FILTER_SEMESTERS:c.fullname%%<br />
<br />
GROUP BY fd.forum<br />
ORDER BY count( * ) DESC<br />
</code><br />
<br />
===Activity In Forums===<br />
Trying to figure out how much real activity we have in Forums by aggregating:<br />
Users in Course, Number of Posts, Number of Discussions, Unique student post, Unique student discussions, Number of Teachers , Number of Students, ratio between unique Student posts and the number of students in the Course...<br />
<code sql><br />
SELECT c.fullname,f.name,f.type <br />
,(SELECT count(id) FROM prefix_forum_discussions as fd WHERE f.id = fd.forum) as Discussions<br />
,(SELECT count(distinct fd.userid) FROM prefix_forum_discussions as fd WHERE fd.forum = f.id) as UniqueUsersDiscussions<br />
,(SELECT count(fp.id) FROM prefix_forum_discussions fd JOIN prefix_forum_posts as fp ON fd.id = fp.discussion WHERE f.id = fd.forum) as Posts<br />
,(SELECT count(distinct fp.userid) FROM prefix_forum_discussions fd JOIN prefix_forum_posts as fp ON fd.id = fp.discussion WHERE f.id = fd.forum) as UniqueUsersPosts<br />
,(SELECT Count( ra.userid ) AS Students<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid =5<br />
AND ctx.instanceid = c.id<br />
) AS StudentsCount<br />
,(SELECT Count( ra.userid ) AS Teachers<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid =3<br />
AND ctx.instanceid = c.id<br />
) AS 'Teacher<br/>Count'<br />
,(SELECT Count( ra.userid ) AS Users<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid IN (3,5)<br />
AND ctx.instanceid = c.id<br />
) AS UserCount<br />
, (SELECT (UniqueUsersDiscussions / StudentsCount )) as StudentDissUsage<br />
, (SELECT (UniqueUsersPosts /StudentsCount)) as StudentPostUsage<br />
FROM prefix_forum as f <br />
JOIN prefix_course as c ON f.course = c.id<br />
WHERE `type` != 'news'<br />
ORDER BY StudentPostUsage DESC<br />
</code><br />
<br />
===All Forum type:NEWS===<br />
<code sql><br />
SELECT f.id, f.name<br />
FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_forum AS f ON cm.instance = f.id<br />
WHERE m.name = 'forum'<br />
AND f.type = 'news'<br />
</code><br />
<br />
===All new forum NEWS items (discussions) from all my Courses===<br />
change "userid = 26" and "id = 26" to a new user id<br />
<code sql><br />
SELECT c.shortname,f.name,fd.name,FROM_UNIXTIME(fd.timemodified ,"%d %M %Y ") as Date<br />
FROM prefix_forum_discussions as fd <br />
JOIN prefix_forum as f ON f.id = fd.forum <br />
JOIN prefix_course as c ON c.id = f.course <br />
JOIN prefix_user_lastaccess as ul ON (c.id = ul.courseid AND ul.userid = 26)<br />
WHERE fd.timemodified > ul.timeaccess <br />
AND fd.forum IN (SELECT f.id<br />
FROM prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
JOIN prefix_forum AS f ON cm.instance = f.id<br />
WHERE m.name = 'forum'<br />
AND f.type = 'news')<br />
AND c.id IN (SELECT c.id<br />
FROM prefix_course AS c<br />
JOIN prefix_context AS ctx ON c.id = ctx.instanceid<br />
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id<br />
JOIN prefix_user AS u ON u.id = ra.userid<br />
WHERE u.id = 26) ORDER BY `fd`.`timemodified` DESC<br />
</code><br />
<br />
<br />
===News Forum - Discussions COUNT===<br />
Which is actually... How much instructions students get from their teachers<br />
<code sql><br />
SELECT c.shortname ,<br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS Course<br />
,( SELECT DISTINCT CONCAT(u.firstname,' ',u.lastname)<br />
FROM prefix_role_assignments AS ra<br />
JOIN prefix_user AS u ON ra.userid = u.id<br />
JOIN prefix_context AS ctx ON ctx.id = ra.contextid<br />
WHERE ra.roleid = 3 AND ctx.instanceid = c.id AND ctx.contextlevel = 50 LIMIT 1) AS Teacher<br />
,concat('<a target="_new" href="%%WWWROOT%%/mod/forum/view.php?f=',fd.forum,'">',count(fd.id),'</a>') AS DiscussionsSum<br />
FROM prefix_forum_discussions AS fd<br />
INNER JOIN prefix_forum AS f ON f.id = fd.forum<br />
INNER JOIN prefix_course AS c ON c.id = f.course<br />
WHERE f.type = 'news' AND c.category IN (10,13,28,18,26)<br />
GROUP BY fd.forum<br />
ORDER BY count(fd.id) DESC<br />
</code><br />
<br />
===Cantidad de foros que han sido posteados por profesor===<br />
<br />
(Number of forums that have been posted by teacher/Google translator)<br />
<br />
Queriamos saber cuales son las acciones del profesor dentro de los foros de cada curso, por ello se hizo este informe.<br />
<br />
(We wanted to know what the teacher's actions are in the forums of each course, so this report was made. /Google translator)<br />
<code sql><br />
SELECT <br />
concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.shortname,'</a>') AS curso,<br />
CONCAT(u.firstname ,' ',u.lastname) AS Facilitador,<br />
<br />
(SELECT COUNT( m.name ) AS COUNT FROM <br />
prefix_course_modules AS cm<br />
JOIN prefix_modules AS m ON cm.module = m.id<br />
WHERE cm.course = c.id AND m.name LIKE '%forum%') AS foros,<br />
<br />
COUNT(*) AS Posts<br />
<br />
FROM prefix_forum_posts AS fp <br />
JOIN prefix_forum_discussions AS fd ON fp.discussion = fd.id <br />
JOIN prefix_forum AS f ON f.id = fd.forum <br />
JOIN prefix_course AS c ON c.id = fd.course<br />
JOIN prefix_user AS u ON u.id = fp.userid <br />
<br />
WHERE fp.userid =<br />
(<br />
select distinct prefix_user.id<br />
from prefix_user <br />
join prefix_role_assignments as ra on ra.userid = prefix_user.id <br />
where ra.roleid = 3 <br />
and userid = fp.userid<br />
limit 1<br />
)<br />
<br />
and c.shortname like '%2014-2-1%'<br />
GROUP BY c.id, u.id<br />
</code><br />
<br />
<br />
===List all the Posts in all the Forums that got high rating===<br />
We setup a scale that let teachers and students Rate forum post with "Important, interesting, valuable, not rated" scale<br />
And then add a link to the following report at the begining of the course "Link to all interesting posts"<br />
<code sql><br />
SELECT <br />
CONCAT('<a target="_new" href="%%WWWROOT%%/mod/forum/view.php?f=',f.id,'">',f.name,'</a>') AS 'Forum name,<br />
CONCAT('<a target="_new" href="%%WWWROOT%%/mod/forum/discuss.php?d=',fd.id,'#p',fp.id,'">',fp.subject,'</a>') AS 'Post link',<br />
SUM(r.rating) AS 'Rating'<br />
FROM mdl_rating AS r<br />
JOIN mdl_forum_posts AS fp ON fp.id = r.itemid<br />
JOIN mdl_forum_discussions AS fd ON fd.id = fp.discussion<br />
JOIN mdl_forum AS f ON f.id = fd.forum<br />
WHERE r.component = 'mod_forum' AND r.ratingarea = 'post' AND f.course = %%COURSEID%%<br />
GROUP BY r.itemid<br />
ORDER BY SUM(r.rating) DESC<br />
</code><br />
<br />
===List all the Posts in all Discussions of a single Forum===<br />
This report is used to help export all the student's posts and discussions of a single forum, by passing the context module id as a parameter to the report using "&filter_var=cmid"<br />
<code sql><br />
SELECT <br />
CONCAT('<a target="_new" href="%%WWWROOT%%/mod/forum/view.php?f=', f.id, '">', f.name, '</a>') AS 'Forum name',<br />
fd.name AS 'Discussion', <br />
CONCAT('<a target="_new" href="%%WWWROOT%%/mod/forum/discuss.php?d=', fd.id, '#p', fp.id, '">', fp.subject, '</a>') AS 'Post (link)',<br />
fp.message<br />
<br />
FROM mdl_forum_posts AS fp <br />
JOIN mdl_forum_discussions AS fd ON fd.id = fp.discussion<br />
JOIN mdl_forum AS f ON f.id = fd.forum<br />
JOIN mdl_course_modules AS cm ON cm.module = 9 AND cm.instance = f.id<br />
WHERE cm.id = %%FILTER_VAR%%<br />
ORDER BY f.id, fd.id<br />
</code><br />
<br />
==Quiz Module Reports==<br />
===Generate a list of instructors and their email addresses for those courses that has "essay questions" in their quizzes===<br />
<code sql><br />
SELECT qu.id AS quiz_id, qu.course AS course_id, qu.questions,<br />
co.fullname AS course_fullname, co.shortname AS course_shortname,<br />
qu.name AS quiz_name, FROM_UNIXTIME(qu.timeopen) AS quiz_timeopen, FROM_UNIXTIME(qu.timeclose) AS quiz_timeclose,<br />
u.firstname, u.lastname, u.email,<br />
FROM prefix_quiz qu, prefix_course co, prefix_role re, prefix_context ct, prefix_role_assignments ra, prefix_user u<br />
WHERE FROM_UNIXTIME(timeopen) > '2008-05-14' AND<br />
qu.course = co.id AND<br />
co.id = ct.instanceid AND<br />
ra.roleid = re.id AND<br />
re.name = 'Teacher' AND<br />
ra.contextid = ct.id AND<br />
ra.userid = u.id<br />
<br />
SELECT Count('x') As NumOfStudents<br />
FROM prefix_role_assignments a<br />
JOIN prefix_user u ON userid = u.id<br />
WHERE roleid = 5 AND contextid = (SELECT id FROM prefix_context WHERE instanceid = 668 AND contextlevel = 50)<br />
</code><br />
<br />
===Number of Quizes per Course===<br />
<code sql><br />
SELECT count(*)<br />
,concat('<a target="_new" href="%%WWWROOT%%/course/view.php?id=',c.id,'">',c.fullname,'</a>') AS Course<br />
,concat('<a target="_new" href="%%WWWROOT%%/mod/quiz/index.php?id=',c.id,'">Link</a>') AS Quizes<br />
<br />
FROM prefix_course_modules cm<br />
JOIN prefix_course c ON c.id = cm.course<br />
JOIN prefix_modules as m ON m.id = cm.module<br />
WHERE m.name LIKE 'quiz'<br />
GROUP BY c.id<br />
</code><br />
<br />
===List all MultiAnswer (Cloze) Questions===<br />
<code sql><br />
SELECT concat('<a target="_new" href="%%WWWROOT%%/mod/quiz/attempt.php?q=', quiz.id, '">', quiz.name, '</a>') AS Quiz<br />
,question.id question_id, question.questiontext <br />
FROM prefix_question question<br />
JOIN prefix_quiz_question_instances qqi ON question.id = qqi.question<br />
JOIN prefix_quiz quiz ON qqi.quiz = quiz.id<br />
WHERE `qtype` LIKE 'multianswer'<br />
</code><br />
<br />
===List courses with MANUAL grades===<br />
Which is basically and indication to teachers using Moodle to hold offline grades inside Moodle's Gradebook,<br />
So grades could be uploaded into an administrative SIS. Use with Configurable Reports.<br />
<code sql><br />
SELECT COUNT( * )<br />
,concat('<a target="_new" href="%%WWWROOT%%/grade/edit/tree/index.php?showadvanced=1&id=',c.id,'">',c.fullname,'</a>') AS Course<br />
FROM prefix_grade_items AS gi<br />
JOIN prefix_course as c ON c.id = gi.courseid<br />
WHERE `itemtype` = 'manual'<br />
GROUP BY courseid<br />
</code><br />
===List the users that did not took the Quiz===<br />
Do not forget to change "c.id = 14" and q.name LIKE '%quiz name goes here%'<br />
<code sql><br />
SELECT<br />
user2.id AS ID,<br />
ul.timeaccess,<br />
user2.firstname AS Firstname,<br />
user2.lastname AS Lastname,<br />
user2.email AS Email,<br />
user2.username AS IDNumber,<br />
user2.institution AS Institution,<br />
<br />
IF (user2.lastaccess = 0,'never',<br />
DATE_FORMAT(FROM_UNIXTIME(user2.lastaccess),'%Y-%m-%d')) AS dLastAccess<br />
<br />
,(SELECT DATE_FORMAT(FROM_UNIXTIME(timeaccess),'%Y-%m-%d') FROM prefix_user_lastaccess WHERE userid=user2.id AND courseid=c.id) AS CourseLastAccess<br />
<br />
,(SELECT r.name<br />
FROM prefix_user_enrolments AS uenrol<br />
JOIN prefix_enrol AS e ON e.id = uenrol.enrolid<br />
JOIN prefix_role AS r ON e.id = r.id<br />
WHERE uenrol.userid=user2.id AND e.courseid = c.id) AS RoleName<br />
<br />
FROM prefix_user_enrolments AS ue<br />
JOIN prefix_enrol AS e ON e.id = ue.enrolid<br />
JOIN prefix_course AS c ON c.id = e.courseid<br />
JOIN prefix_user AS user2 ON user2 .id = ue.userid<br />
LEFT JOIN prefix_user_lastaccess AS ul ON ul.userid = user2.id<br />
WHERE c.id=14 and ue.userid NOT IN (SELECT qa.userid FROM prefix_quiz_attempts AS qa<br />
JOIN prefix_quiz AS q ON qa.quiz = q.id<br />
JOIN prefix_course AS c ON q.course = c.id<br />
WHERE c.id = 14 AND q.name LIKE '%quiz name goes here%')<br />
</code><br />
<br />
<br />
===List Questions in each Quiz===<br />
<br />
<code sql><br />
SELECT quiz.id,quiz.name, q.id, q.name<br />
FROM mdl_quiz AS quiz<br />
JOIN mdl_question AS q ON FIND_IN_SET(q.id, quiz.questions)<br />
WHERE quiz.course = %%COURSEID%%<br />
ORDER BY quiz.id ASC<br />
</code><br />
<br />
Note: this query does not work in Moodle 2.8. There is no mdl_quiz.questions field. It will need to be rewritten to use the usage/contextid organization.<br />
<br />
===Quiz activity research===<br />
This report was made to extract student full activity in quizzes for an academic research about adapting instructional design teaching methods in online learning. The students do not use the Quiz module as a standard quiz but more as Study booklets or mini courses with embedded questions and hints to assist students evaluate their progress (Similar to what you expect to find in a SCORM activity)<br />
<br />
<code sql><br />
SELECT <br />
cm.course "course_id", cm.id "moduel_id", q.id "quiz_id", q.name "quiz_name",<br />
<br />
CASE q.grademethod<br />
WHEN 1 THEN "GRADEHIGHEST"<br />
WHEN 2 THEN "GRADEAVERAGE"<br />
WHEN 3 THEN "ATTEMPTFIRST"<br />
WHEN 4 THEN "ATTEMPTLAST"<br />
END "grade method"<br />
<br />
, q.attempts "quiz_attempts_allowed", cm.groupmode "group_mode"<br />
, qa.id "attempt_id", qa.state "attempt_state", qa.sumgrades "attempt_grade", qg.grade "user_final_grade", q.grade "quiz_max_grade"<br />
,(SELECT GROUP_CONCAT(g.name) FROM mdl_groups AS g<br />
JOIN mdl_groups_members AS m ON g.id = m.groupid WHERE g.courseid = q.course AND m.userid = u.id) "user_groups",<br />
DATE_FORMAT(FROM_UNIXTIME(qa.timestart), '%d-%m-%Y %h:%k') "attempt_start",<br />
DATE_FORMAT(FROM_UNIXTIME(qa.timefinish), '%d-%m-%Y %h:%k') "attempt_finish",<br />
u.id "user_id", u.firstname, u.lastname,<br />
question.id "question_id", question.name "question_name",<br />
qas.state "question_step_state",qas.fraction "question_grade", qh.hint, question.qtype "question_type"<br />
<br />
FROM mdl_quiz as q<br />
JOIN mdl_course_modules as cm ON cm.instance = q.id and cm.module = 14 <br />
JOIN mdl_quiz_attempts qa ON q.id = qa.quiz<br />
LEFT JOIN mdl_quiz_grades as qg ON qg.quiz = q.id and qg.userid = qa.userid<br />
JOIN mdl_user as u ON u.id = qa.userid<br />
JOIN mdl_question_usages as qu ON qu.id = qa.uniqueid<br />
JOIN mdl_question_attempts as qatt ON qatt.questionusageid = qu.id<br />
JOIN mdl_question as question ON question.id = qatt.questionid<br />
JOIN mdl_question_attempt_steps as qas ON qas.questionattemptid = qatt.id<br />
LEFT JOIN mdl_question_hints as qh ON qh.questionid = q.id<br />
#WHERE q.id = "SOME QUIZ ID"<br />
WHERE cm.course = "SOME COURSE ID"<br />
</code><br />
<br />
===Quiz Usage in Courses by Date===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
This report lists the courses containing quizzes with the course start date between the two values, and provides a summary of the types of questions in the quizzes in each course and whether question randomization and answer randomization functions were used.<br />
<br />
"Multiple Choice" questions include true/false and matching question types.<br />
<br />
"Short Answer" are questions that accept a single phrase.<br />
<br />
"Other" questions include fixed numerical, calculated, essay, and various drag and drop types.<br />
<br />
"Min Quiz Age" and "Max Quiz Age" provide data about the last modified date for the quizzes in the course, compared to the course start date. The values are expressed in units of days. A negative value indicates that a quiz was edited after the start of the course. A value greater than 90 days indicates that the quiz may have been used in an earlier term (cohort) without modification.<br />
<br />
'''Note''': In Configurable Reports, the Date Filter is not applied until the "Apply" button is clicked.<br />
<br />
<code sql><br />
SELECT <br />
<br />
c.shortname AS 'Course'<br />
#, u.lastname AS 'Instructor'<br />
, COUNT(DISTINCT q.id) AS 'Quizzes'<br />
, COUNT(DISTINCT qu.id) AS 'Questions'<br />
, SUM(IF (qu.qtype = 'multichoice', 1, 0 )) + SUM(IF (qu.qtype = 'truefalse', 1, 0 )) + SUM(IF (qu.qtype = 'match', 1, 0 )) AS 'multichoice'<br />
<br />
, SUM(IF (qu.qtype = 'shortanswer', 1, 0 )) AS 'shortanswer'<br />
<br />
, COUNT( qu.id) - SUM(IF (qu.qtype = 'multichoice', 1, 0 )) - SUM(IF (qu.qtype = 'truefalse', 1, 0 )) - SUM(IF (qu.qtype = 'match', 1, 0 )) - SUM(IF (qu.qtype = 'shortanswer', 1, 0 )) AS 'Other'<br />
<br />
, (SUM(IF (qu.qtype = 'multichoice', 1, 0 )) + SUM(IF (qu.qtype = 'truefalse', 1, 0 )) + SUM(IF (qu.qtype = 'match', 1, 0 )))/COUNT( qu.id) AS 'Percent MC'<br />
<br />
#, SUM(IF (qu.qtype = 'numerical', 1, 0 )) AS 'numerical'<br />
#, SUM(IF (qu.qtype LIKE 'calc%', 1, 0 )) AS 'calculated'<br />
#, SUM(IF (qu.qtype = 'random', 1, 0 )) AS 'random'<br />
#, SUM(IF (qu.qtype = 'shortanswer', 1, 0 )) AS 'shortanswer'<br />
#, SUM(IF (qu.qtype = 'essay', 1, 0 )) AS 'essay'<br />
<br />
<br />
, IF(q.shufflequestions > 0,'Yes','No') AS 'Randomized Questions'<br />
, IF(q.shuffleanswers > 0,'Yes','No') AS 'Randomized Answers'<br />
<br />
#, FROM_UNIXTIME(c.startdate) AS 'Course Start Date'<br />
#, FROM_UNIXTIME(MIN(q.timemodified)) AS 'Last Modified'<br />
<br />
#, DATEDIFF(FROM_UNIXTIME(c.startdate),FROM_UNIXTIME(MIN(q.timemodified))) AS 'Quiz age'<br />
<br />
, MIN(DATEDIFF(FROM_UNIXTIME(c.startdate),FROM_UNIXTIME(q.timemodified))) AS 'Min Quiz Age' <br />
, MAX(DATEDIFF(FROM_UNIXTIME(c.startdate),FROM_UNIXTIME(q.timemodified))) AS 'Max Quiz Age' <br />
<br />
#, SUM(IF (DATEDIFF(FROM_UNIXTIME(c.startdate),FROM_UNIXTIME(q.timemodified)) < 90, 1,0)) AS 'new quizzes'<br />
<br />
FROM prefix_quiz AS q<br />
JOIN prefix_course AS c on c.id = q.course<br />
JOIN prefix_quiz_question_instances AS qqi ON qqi.quiz = q.id<br />
LEFT JOIN prefix_question AS qu ON qu.id = qqi.question<br />
<br />
WHERE<br />
1<br />
%%FILTER_STARTTIME:c.startdate:>%% %%FILTER_ENDTIME:c.startdate:<%%<br />
<br />
GROUP BY c.id<br />
<br />
ORDER BY c.shortname<br />
</code><br />
<br />
===Student responses (answers) to quiz questions===<br />
(Contributed by Juan F with help from Tim hunt and fellow Moodlers on the forums)<br />
A report that targets a specific quiz for all of our Biology courses, a summary of all questions and how many students get them right/wrong.<br />
<code sql><br />
SELECT<br />
concat( u.firstname, " ", u.lastname ) AS "Student Name",<br />
u.id,<br />
quiza.userid,<br />
q.course,<br />
q.name,<br />
quiza.attempt,<br />
qa.slot,<br />
que.questiontext AS 'Question',<br />
qa.rightanswer AS 'Correct Answer',<br />
qa.responsesummary AS 'Student Answer'<br />
<br />
FROM mdl_quiz_attempts quiza<br />
JOIN mdl_quiz q ON q.id=quiza.quiz<br />
JOIN mdl_question_usages qu ON qu.id = quiza.uniqueid<br />
JOIN mdl_question_attempts qa ON qa.questionusageid = qu.id<br />
JOIN mdl_question que ON que.id = qa.questionid<br />
JOIN mdl_user u ON u.id = quiza.userid<br />
<br />
WHERE q.name = "BIO 208 Post Test Assessment"<br />
AND q.course = "17926"<br />
<br />
ORDER BY quiza.userid, quiza.attempt, qa.slot<br />
</code><br />
<br />
==SCORM Activity Reports==<br />
<br />
===Lists All completed SCORM activites by Course name===<br />
This report will list all completed attempts for all SCORM activities. It is ordered first by Course name, then student's last name, then student's first name, then attempt number. Please note: the FROM_UNIXTIME command is for MySQL.<br />
<code sql><br />
SELECT u.firstname First,u.lastname Last,c.fullname Course, st.attempt Attempt,st.value Status,FROM_UNIXTIME(st.timemodified,"%m-%d-%Y") Date <br />
FROM prefix_scorm_scoes_track AS st <br />
JOIN prefix_user AS u ON st.userid=u.id<br />
JOIN prefix_scorm AS sc ON sc.id=st.scormid<br />
JOIN prefix_course AS c ON c.id=sc.course<br />
WHERE st.value='completed' <br />
ORDER BY c.fullname, u.lastname,u.firstname, st.attempt<br />
</code><br />
<br />
===Lists SCORM status for all enrolled users by Course name===<br />
This report will list the SCORM status for all users enrolled in the course. It is ordered first by Course name, then student's last name, then student's first name, then attempt number. This can be limited to individual courses by adding to the where clause the course id to report on. <br />
<code sql><br />
SELECT<br />
u.firstname AS First,<br />
u.lastname AS Last, <br />
u.idnumber AS Employee_ID, <br />
u.city AS City,<br />
uid.data AS State,<br />
u.country AS Country,<br />
g.name AS Group_name,<br />
c.fullname AS Course, <br />
st.attempt AS Attempt,<br />
st.value AS Status,<br />
FROM_UNIXTIME(st.timemodified,"%m-%d-%Y") AS Date <br />
<br />
FROM prefix_scorm_scoes_track AS st <br />
JOIN prefix_user AS u ON st.userid=u.id<br />
JOIN prefix_user_info_data AS uid ON uid.userid = u.id <br />
JOIN prefix_scorm AS sc ON sc.id=st.scormid<br />
JOIN prefix_course AS c ON c.id=sc.course<br />
JOIN prefix_groups AS g ON g.courseid = c.id<br />
JOIN prefix_groups_members AS m ON g.id = m.groupid<br />
<br />
WHERE st.element='cmi.core.lesson_status' AND m.userid=u.id<br />
<br />
UNION<br />
<br />
SELECT<br />
user2.firstname AS First,<br />
user2.lastname AS Last,<br />
user2. idnumber AS Employee_ID,<br />
user2.city AS City,<br />
uid.data AS State,<br />
user2.country AS Country,<br />
g.name AS Group_name,<br />
c.fullname AS Course,<br />
"-" AS Attempt,<br />
"not_started" AS Status,<br />
"-" AS Date<br />
<br />
FROM prefix_user_enrolments AS ue<br />
JOIN prefix_enrol AS e ON e.id = ue.enrolid<br />
JOIN prefix_course AS c ON c.id = e.courseid<br />
JOIN prefix_user AS user2 ON user2 .id = ue.userid<br />
JOIN prefix_user_info_data AS uid ON uid.userid = user2.id <br />
JOIN prefix_groups AS g ON g.courseid = c.id<br />
JOIN prefix_groups_members AS m ON g.id = m.groupid<br />
JOIN prefix_scorm AS sc ON sc.course=c.id<br />
Left Join prefix_scorm_scoes_track AS st on st.scormid=sc.id AND st.userid=user2.id<br />
<br />
WHERE st.timemodified IS NULL AND m.userid=user2.id<br />
<br />
ORDER BY Course, Last, First, Attempt<br />
<br />
</code><br />
<br />
== Badges==<br />
<br />
=== All badges issued, by User ===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
This report will show you all the badges on a site that have been issued, both site and all courses, by the username of each user issued a badge. Includes the type of criteria passed (activity, course completion, manual), date issued, date expires, and a direct link to that issued badge page so you can see all the other details for that badge.<br />
<br />
<code sql><br />
SELECT u.username, b.name AS badgename, <br />
CASE<br />
WHEN b.courseid IS NOT NULL THEN<br />
(SELECT c.shortname<br />
FROM prefix_course AS c<br />
WHERE c.id = b.courseid)<br />
WHEN b.courseid IS NULL THEN "*"<br />
END AS Context,<br />
CASE <br />
WHEN t.criteriatype = 1 AND t.method = 1 THEN "Activity Completion (All)"<br />
WHEN t.criteriatype = 1 AND t.method = 2 THEN "Activity Completion (Any)"<br />
WHEN t.criteriatype = 2 AND t.method = 2 THEN "Manual Award"<br />
WHEN t.criteriatype = 4 AND t.method = 1 THEN "Course Completion (All)"<br />
WHEN t.criteriatype = 4 AND t.method = 2 THEN "Course Completion (Any)"<br />
ELSE CONCAT ('Other: ', t.criteriatype)<br />
END AS Criteriatype,<br />
DATE_FORMAT( FROM_UNIXTIME( d.dateissued ) , '%Y-%m-%d' ) AS dateissued,<br />
DATE_FORMAT( FROM_UNIXTIME( d.dateexpire ), '%Y-%m-%d' ) AS dateexpires,<br />
CONCAT ('<a target="_new" href="%%WWWROOT%%/badges/badge.php?hash=',d.uniquehash,'">link</a>') AS Details<br />
FROM prefix_badge_issued AS d <br />
JOIN prefix_badge AS b ON d.badgeid = b.id<br />
JOIN prefix_user AS u ON d.userid = u.id<br />
JOIN prefix_badge_criteria AS t on b.id = t.badgeid <br />
WHERE t.criteriatype <> 0<br />
ORDER BY u.username<br />
</code><br />
<br />
Please note: the FROM_UNIXTIME command is for MySQL.<br />
<br />
=== All badges available in the system, with Earned count ===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
Report of all badges in the system, with badge name and description, context, course shortname if a course badge, whether it is active and available, and a count of how many users have been issued that badge.<br />
<br />
<code sql><br />
SELECT b.id, b.name, b.description,<br />
CASE<br />
WHEN b.type = 1 THEN "System"<br />
WHEN b.type = 2 THEN "Course"<br />
END AS Context, <br />
CASE<br />
WHEN b.courseid IS NOT NULL THEN <br />
(SELECT c.shortname <br />
FROM prefix_course AS c <br />
WHERE c.id = b.courseid)<br />
WHEN b.courseid IS NULL THEN "*"<br />
END AS Course, <br />
CASE<br />
WHEN b.status = 0 OR b.status = 2 THEN "No"<br />
WHEN b.status = 1 OR b.status = 3 THEN "Yes"<br />
WHEN b.status = 4 THEN "x"<br />
END AS Available,<br />
CASE<br />
WHEN b.status = 0 OR b.status = 1 THEN "0"<br />
WHEN b.status = 2 OR b.status = 3 OR b.status = 4 THEN <br />
(SELECT COUNT(*) <br />
FROM prefix_badge_issued AS d<br />
WHERE d.badgeid = b.id<br />
)<br />
END AS Earned<br />
FROM prefix_badge AS b<br />
<br />
</code><br />
<br />
=== Badges Leaderboard ===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
A simple list of usernames and how many badges they have earned overall.<br />
<br />
<code sql><br />
SELECT u.username, (SELECT COUNT(*) FROM prefix_badge_issued AS d WHERE d.userid = u.id) AS earned<br />
FROM prefix_user AS u<br />
ORDER BY earned DESC, u.username ASC<br />
</code><br />
<br />
=== Manage badges (System & Course) ===<br />
<br />
List system wide badges, course and system level badges + a link to relevant "manage badges" page.<br />
<br />
<code sql><br />
SELECT b.id, b.name, b.description <br />
,CASE <br />
WHEN b.type = 1 THEN 'System'<br />
WHEN b.type = 2 THEN 'Course'<br />
END AS Level<br />
,CONCAT('<a target="_new" href="%%WWWROOT%%/badges/index.php?type=', b.type, '&id=',<br />
c.id, '">Manage badges in: ', c.fullname, '</a>') AS Manage <br />
FROM prefix_badge AS b<br />
JOIN prefix_course AS c ON c.id = b.courseid<br />
</code><br />
<br />
==Administrator Reports==<br />
<br />
===Config changes in Export friendly form===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
The Administrative report Config changes is very useful but it would be nice to have it in a format that could be easily exported in one listing. Here is code to do that.<br />
<br />
<code sql><br />
SELECT <br />
DATE_FORMAT( FROM_UNIXTIME( g.timemodified ) , '%Y-%m-%d' ) AS date, <br />
u.username AS user, <br />
g.name AS setting, <br />
CASE <br />
WHEN g.plugin IS NULL THEN "core"<br />
ELSE g.plugin<br />
END AS plugin, <br />
g.value AS new_value, <br />
g.oldvalue AS original_value<br />
FROM prefix_config_log AS g<br />
JOIN prefix_user AS u ON g.userid = u.id<br />
ORDER BY date DESC<br />
</code><br />
<br />
===Cohorts by user===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
How to get a list of all users and which cohorts they belong to.<br />
<br />
<code sql><br />
SELECT u.firstname, u.lastname, h.idnumber, h.name<br />
FROM prefix_cohort AS h<br />
JOIN prefix_cohort_members AS hm ON h.id = hm.cohortid<br />
JOIN prefix_user AS u ON hm.userid = u.id<br />
ORDER BY u.firstname<br />
</code><br />
<br />
===Cohorts with Courses===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
List of all cohorts with name, id, visibility, and which courses they are enrolled in.<br />
<br />
<code sql><br />
SELECT<br />
# h.id,<br />
# e.customint1,<br />
h.name AS Cohort,<br />
h.idnumber AS Cohortid,<br />
CASE <br />
WHEN h.visible = 1 THEN 'Yes'<br />
ELSE '-'<br />
END AS Cohortvisible,<br />
CONCAT('<a target="_new" href="%%WWWROOT%%/course/view.php', CHAR(63),'id=',c.id,'">',c.fullname,'</a>') AS Course<br />
FROM prefix_cohort h<br />
JOIN prefix_enrol e ON h.id = e.customint1<br />
JOIN prefix_course c ON c.id = e.courseid %%FILTER_COURSES:e.courseid%% <br />
WHERE e.enrol = 'cohort' AND e.roleid = 5<br />
</code><br />
<br />
===Courses created And Active courses by Year===<br />
Active courses is counting course that have at least one Hit, And "Active_MoreThan100Hits" counts courses that have at least 100 Hits<br />
<code sql><br />
SELECT <br />
<br />
YEAR( FROM_UNIXTIME( `timecreated` ) ) AS YEAR, COUNT( * ) AS Counter<br />
<br />
, (SELECT COUNT( DISTINCT course ) <br />
FROM prefix_log AS l<br />
WHERE YEAR( FROM_UNIXTIME( l.`time` ) ) = YEAR( FROM_UNIXTIME( `timecreated` ) )<br />
) AS "Active"<br />
<br />
,(SELECT COUNT(*) FROM ( <br />
SELECT COUNT( * ),time <br />
FROM prefix_log AS l <br />
GROUP BY course <br />
HAVING COUNT(*) > 100) AS courses_log<br />
WHERE YEAR( FROM_UNIXTIME( courses_log.`time` ) ) = YEAR( FROM_UNIXTIME( `timecreated` ) )<br />
) AS "Active_MoreThan100Hits"<br />
<br />
FROM `prefix_course` <br />
GROUP BY YEAR( FROM_UNIXTIME( `timecreated` ) ) <br />
</code><br />
<br />
===Users created And Active users by Year===<br />
Active users is counting users that have at least one Hit, And "Active_MoreThan500Hits" counts users that have at least 500 Hits<br />
<code sql><br />
SELECT <br />
<br />
YEAR( FROM_UNIXTIME( `firstaccess` ) ) AS YEAR, COUNT( * ) AS Counter<br />
<br />
, (SELECT COUNT( DISTINCT userid ) <br />
FROM prefix_log AS l<br />
WHERE YEAR( FROM_UNIXTIME( l.`time` ) ) = YEAR( FROM_UNIXTIME( `firstaccess` ) )<br />
) AS "Active"<br />
<br />
,(SELECT COUNT(*) FROM ( <br />
SELECT COUNT( * ),time <br />
FROM prefix_log AS l <br />
GROUP BY userid <br />
HAVING COUNT(*) > 500) AS users_log<br />
WHERE YEAR( FROM_UNIXTIME( users_log.`time` ) ) = YEAR( FROM_UNIXTIME( `firstaccess` ) )<br />
) AS "Active_MoreThan500Hits"<br />
<br />
FROM `prefix_user` <br />
GROUP BY YEAR( FROM_UNIXTIME( `timecreated` ) ) <br />
</code><br />
<br />
===Course Aggregation Report===<br />
Contributed by Elizabeth Dalton, Granite State College<br />
<br />
If you are considering upgrading from Moodle 2.6 to 2.8 or later, your grades may be changed. This report can help quantify and identify the courses at risk of changes.<br />
<br />
In particular, be on the lookout for any courses with the following combinations of parameters, which are known to cause changes in calculations:<br />
<br />
# mean of grades set with aggregate with subcategory.<br />
# Simple weighted mean of grades with aggregate with sub category and drop the lowest<br />
# Sum of grades drop the lowest<br />
<br />
Also review:<br />
https://tracker.moodle.org/browse/MDL-48618<br />
https://tracker.moodle.org/browse/MDL-48634<br />
https://tracker.moodle.org/browse/MDL-49257<br />
https://tracker.moodle.org/browse/MDL-50089<br />
https://tracker.moodle.org/browse/MDL-50062<br />
<br />
<code sql><br />
SELECT<br />
<br />
COUNT(c.shortname) AS 'Count of Courses'<br />
<br />
# If you want to display all the courses for each aggregation type, uncomment the next line and change GROUP BY settings<br />
#, c.shortname AS 'course name'<br />
<br />
# If you need to display grade categories for each aggregation type, uncomment the next line and change GROUP BY settings<br />
#, gc.fullname AS 'grade category name'<br />
<br />
, gc.aggregation AS 'aggregation method'<br />
<br />
#These aggregation text strings appear to be hard-coded. I couldn't find a table for them. If you have aggregation types I haven't included here, they'll be blank in your report results.<br />
, CASE gc.aggregation<br />
WHEN 0 THEN 'Mean of Grades'<br />
WHEN 2 THEN 'Median of Grades'<br />
WHEN 6 THEN 'Highest Grade'<br />
WHEN 8 THEN 'Mode of Grades'<br />
WHEN 10 THEN 'Weighted Mean of Grades'<br />
WHEN 11 THEN 'Simple Weighted Mean of Grades'<br />
WHEN 12 THEN 'Mean of Grades (with extra credits)'<br />
WHEN 13 THEN 'Sum of Grades'<br />
END AS 'aggregation name'<br />
<br />
# Note that gc.aggregatesubcats column is eliminated in 2.8 and later per MDL-47503, so comment that line on updated systems or you'll get an error<br />
, gc.keephigh AS 'keep high'<br />
, gc.droplow AS 'dr0p low'<br />
, gc.aggregateonlygraded AS 'Aggregate only graded'<br />
, gc.aggregateoutcomes AS 'aggregate outcomes'<br />
, gc.aggregatesubcats AS 'aggregate subcategories'<br />
<br />
# If you are displaying data about individual courses, you may want to know how old they are<br />
#, FROM_UNIXTIME(c.startdate) AS 'course start date'<br />
<br />
# If you are trying to use this report to check to see if final grades have changed after an upgrade, you might want these data items, but calculations can still change later when the courses are actually viewed. Also, you'll need to uncomment the necessary JOINs below<br />
#, gi.itemname AS 'grade item'<br />
#, gg.finalgrade AS 'final grade'<br />
<br />
FROM<br />
<br />
prefix_course AS c<br />
JOIN prefix_grade_categories AS gc ON gc.courseid = c.id<br />
JOIN prefix_course_categories AS cc ON cc.id = c.category<br />
<br />
#LEFT JOIN prefix_grade_items AS gi ON gi.courseid = c.id #AND gi.categoryid=gc.id<br />
#LEFT JOIN prefix_grade_grades AS gg ON gg.itemid = gi.id AND gg.userid = u.id<br />
<br />
WHERE<br />
1<br />
#AND gc.aggregation = 13 #only the dreaded Sum of Grades aggregations<br />
#AND gc.depth = 1 # if for some reason you only want course aggregations, not subcategories<br />
<br />
<br />
GROUP BY gc.aggregation, gc.keephigh, gc.droplow, gc.aggregateonlygraded, gc.aggregateoutcomes, gc.aggregatesubcats<br />
<br />
</code><br />
<br />
=== Running Cron jobs (task_scheduled) ===<br />
<code sql><br />
SELECT classname<br />
,DATE_FORMAT(FROM_UNIXTIME(lastruntime), '%H:%i [%d]') AS 'last'<br />
,DATE_FORMAT(now(), '%H:%i') AS 'now'<br />
,DATE_FORMAT(FROM_UNIXTIME(nextruntime), '%H:%i [%d]') AS 'next'<br />
,DATE_FORMAT(FROM_UNIXTIME(UNIX_TIMESTAMP()-nextruntime), '%i') AS 'next in min'<br />
FROM mdl_task_scheduled<br />
WHERE now() > FROM_UNIXTIME(nextruntime)<br />
</code><br />
<br />
=== All Meta courses with Parent and Child course relationships ===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
This shows the list of courses with Meta course link enrollments in them ('Parent course'), and the courses which are connected to them to provide enrollments ('Child courses').<br />
<br />
<code sql><br />
SELECT <br />
c.fullname AS 'Parent course name',<br />
c.shortname AS 'Parent course shortname',<br />
en.courseid AS 'Parent course id',<br />
(SELECT fullname FROM prefix_course WHERE prefix_course.id = en.customint1) As 'Child course name',<br />
(SELECT shortname FROM prefix_course WHERE prefix_course.id = en.customint1) As 'Child course shortname',<br />
en.customint1 AS 'Child course id'<br />
FROM prefix_enrol en<br />
JOIN prefix_course c ON c.id = en.courseid<br />
WHERE en.enrol = 'meta'<br />
ORDER BY c.fullname<br />
</code><br />
<br />
== Useful sub queries ==<br />
<br />
IN this section please put any short one purpose sub queries that show how common procedures often useful as part of larger queries.<br />
<br />
=== All teachers in the course ===<br />
<br />
<br />
This snippet shows how to get teachers from a course. The contextevel for course objects is 50. And the default Teacher role is role id 3.<br />
<br />
<code sql><br />
,(SELECT GROUP_CONCAT( CONCAT( u.firstname, " ", u.lastname ) ) <br />
FROM prefix_course ic<br />
JOIN prefix_context con ON con.instanceid = ic.id<br />
JOIN prefix_role_assignments ra ON con.id = ra.contextid AND con.contextlevel = 50<br />
JOIN prefix_role r ON ra.roleid = r.id<br />
JOIN prefix_user u ON u.id = ra.userid<br />
WHERE r.id = 3 AND ic.id = c.id<br />
GROUP BY ic.id<br />
) AS TeacherNames<br />
</code><br />
<br />
=== Get custom User profile fields for a user ===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
This snippet of code shows how to connect a user with their custom profile field data. This will list all users with all custom profile fields and data. Custom profile fields have two tables, one for the definition of the profile field (user_info_field) and its settings, and a separate table to hold the data entered by users (user_info_data). <br />
<br />
<code sql><br />
SELECT u.username, uif.name, uid.data<br />
FROM prefix_user AS u<br />
JOIN prefix_user_info_data AS uid ON uid.userid = u.id<br />
JOIN prefix_user_info_field AS uif ON uid.fieldid = uif.id <br />
</code><br />
<br />
If you want to limit it to one of those fields, you can restrict it by shortname of the custom profile field, so:<br />
<br />
<code sql><br />
SELECT u.username, uif.name, uid.data<br />
FROM prefix_user AS u<br />
JOIN prefix_user_info_data AS uid ON uid.userid = u.id<br />
JOIN prefix_user_info_field AS uif ON (uid.fieldid = uif.id AND uif.shortname = 'shortname1')<br />
</code><br />
<br />
will show you only the data from the custom profile field with the shortname 'shortname1'.<br />
<br />
If you want to do this with two or more custom profile fields, you will need to have a JOIN and table alias for each with a restriction for each profile field shortname. Example:<br />
<br />
<code sql><br />
SELECT u.username, d1.data AS 'Profile One', d2.data As 'Profile Two'<br />
FROM prefix_user u<br />
JOIN prefix_user_info_data d1 ON d1.userid = u.id<br />
JOIN prefix_user_info_field f1 ON d1.fieldid = f1.id AND f1.shortname = 'shortname1'<br />
JOIN prefix_user_info_data d2 ON d2.userid = u.id<br />
JOIN prefix_user_info_field f2 ON d2.fieldid = f2.id AND f2.shortname = 'shortname2'<br />
</code><br />
<br />
==== NOTE: Alternate Method ====<br />
<br />
If you have more than a couple of fields you need to use, then this query may time out or not return data due to too many joins. The limit seems to be around 10 custom profile fields. <br />
<br />
Instead you should use an alternate method which uses Subselects for each of the profile fields. Details and sample code are in this forum discussion: https://moodle.org/mod/forum/discuss.php?d=355502#p1434854. A sample of the style is:<br />
<br />
<code sql><br />
SELECT u.username<br />
<br />
,(SELECT d1.data FROM prefix_user_info_data d1<br />
JOIN prefix_user_info_field f1 ON d1.fieldid = f1.id AND f1.shortname = 'shortname1'<br />
WHERE d1.userid = u.id<br />
) AS thefirstfield<br />
<br />
,(SELECT d1.data FROM prefix_user_info_data d1<br />
JOIN prefix_user_info_field f1 ON d1.fieldid = f1.id AND f1.shortname = 'shortname2'<br />
WHERE d1.userid = u.id<br />
) AS thesecondfield<br />
<br />
FROM prefix_user u<br />
</code><br />
<br />
=== How to use Configurable Reports Date Time Filters===<br />
<br />
Contributed by: [https://moodle.org/user/profile.php?id=88992 Randy Thornton]<br />
<br />
In the Configurable Reports block, you can set the Time and Date filter to allow you to pick your report Start date/time and End date/time interactively. This will work on any column in a table that is a timestamp.<br />
<br />
Here is a simple example:<br />
<br />
<code sql><br />
SELECT u.username, <br />
DATE_FORMAT(FROM_UNIXTIME(u.firstaccess),'%Y-%m-%d %H:%i') AS 'FirstAccess',<br />
DATE_FORMAT(FROM_UNIXTIME(u.lastaccess),'%Y-%m-%d %H:%i') AS 'LastAccess' <br />
FROM prefix_user u<br />
<br />
WHERE 1=1<br />
%%FILTER_STARTTIME:u.firstaccess:>%% <br />
%%FILTER_ENDTIME:u.lastaccess:<%% <br />
</code><br />
<br />
1) You will need to replace name of the table and column for the filter to use the time and date column you need for your query. In the example above, it filters on the firstaccess and lastaccess columns in the user table. If you were doing a report on course completion, you might put the timecompleted column, and so forth.<br />
<br />
2) You MUST then add the Start / End date filter on the Filters tab of the Report. If you don't, the report will still run, probably, but the filter will be ignored.<br />
<br />
Note: the WHERE 1=1 statement is a peculiarity of the filters in Config reports: if you don't have a WHERE statement in your query already, then you must add this dummy WHERE to keep the statement valid. If you already have a WHERE statement in your code, simply add the %%FILTER%% placeholders after it (and before any GROUP or ORDER BY statements.)<br />
<br />
==See also==<br />
* [https://github.com/jleyva/moodle-configurable_reports_repository Configurable Reports Repository on GitHub]<br />
* [https://moodleschema.zoola.io/index.html Moodle DB schema explorer] - searching and filtering tables, fields and external key connections between tables.<br />
<br />
[[Category:Contributed code]]<br />
<br />
[[es:Reportes específicos hechos por usuarios]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=Managing_a_Moodle_course&diff=131114Managing a Moodle course2018-05-28T13:24:05Z<p>Fox: French link</p>
<hr />
<div>{{Main page}}<br />
A'' course'' in Moodle is an area where a teacher will add [[Resources|resources]] and [[Activities|activities]] for their students to complete. It might be a simple page with downloadable documents or it might be a complex set of tasks where learning progresses through interaction. See the screencast [http://youtu.be/iOyLq0B-rz0 What is a course in Moodle?] for an example. <br />
<br />
The course page is made up of central sections which contain the tasks and (if desired) [[Block|blocks]] to the side. The course teacher has control over the layout of the [[Course homepage|course homepage]] and can change it at any time. Progress can be [[Tracking progress|tracked]] in a number of ways.<br />
<br />
Students can be [[Course enrolment|enrolled]] manually by the teacher, automatically by the administrator, or they can be allowed to enrol themselves. Students can also be added to [[Grouping users|groups]] if they need to be separated from classes sharing the same course or if tasks need to be differentiated.<br />
<br />
'''New to the role of teacher? See our [[Teacher quick guide]].<br />
'''<br />
* [[Courses]] - how to set up your courses.<br />
* [[Editing text]] - how to use the text editor and what the icons mean.<br />
* [[Activities]] - how to involve students actively in their learning.<br />
* [[Resources]] - how to add static materials to your course.<br />
* [[Blocks]] - how to add extra items and information to the sides of your course page.<br />
* [[Questions]] - how to create questions for use in [[Quiz|quizzes]] and Moodle's [[Lesson|lesson module]]<br />
* [[Course enrolment]] - how to give students access to your course.<br />
* [[Grouping users]] - how to put students into groups and why this is useful.<br />
* [[Grades]] - how to use the gradebook, scales and advanced grading methods.<br />
* [[Tracking progress]] - how to control and display progress through a course.<br />
* [[Reusing activities]] - how to copy or recycle elements of your course.<br />
<br />
<br />
<br />
[[de:Moodle-Kurs verwalten]]<br />
[[es:Gestionando un curso Moodle]]<br />
[[fr:Gestion d'un cours Moodle]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=Upgrading&diff=131020Upgrading2018-05-16T07:26:41Z<p>Fox: /* Check the requirements */ Moodle 3.1 is required to update to 3.5</p>
<hr />
<div>{{Installing Moodle}} <br />
''This page explains in detail how to upgrade Moodle. For a summary of the process, see [[Upgrade overview]].''<br />
<br />
==Check the requirements==<br />
<br />
Check that your server meets all requirements for {{Version}} in ''Administration > Site administration > Server > [[Environment]]''. <br />
<br />
See the [{{Release notes}} release notes] in the dev docs for software requirements.<br />
<br />
Notes:<br />
<br />
* You can only upgrade to Moodle {{Version}} from Moodle 3.1 or later. If upgrading from earlier versions, you must [https://docs.moodle.org/31/en/Upgrading_to_Moodle_3.1 upgrade to 3.1] as a first step.<br />
* The minimum PHP version has increased and is now 7.0.0.<br />
* The PHP extension '''intl''' is now required in Moodle 3.4 (previously it was only recommended).<br />
<br />
==Before upgrading==<br />
<br />
'''We advise that you test the upgrade first on a COPY of your production site, to make sure it works as you expect.'''<br />
<br />
Consider setting the [[Upgrade key|upgrade key]] for your site.<br />
<br />
== Backup important data ==<br />
<br />
There are three areas that should be backed up before any upgrade:<br />
#Moodle software (For example, everything in server/htdocs/moodle)<br />
#Moodle uploaded files (For example, server/moodledata)<br />
#Moodle database (For example, your Postgres or MySQL database dump)<br />
<br />
See [[Site backup]] for more specific information.<br />
<br />
== Check for plugin updates ==<br />
<br />
If you have [[Automatic updates deployment]] enabled, you will be able to update installed plugins automatically during the upgrade. Just make sure you check for available updates (via the button for it) at the Plugins check screen.<br />
<br />
If you are updating plugins manually, it is a good moment now to check in the [http://moodle.org/plugins Moodle Plugins directory] whether there is a {{Version}} version available for any plugins (including themes) that you have previously installed on your site. If so, download the plugin package. In the next step, you will copy it to the appropriate location in your Moodle code (see [[Installing plugins]]).<br />
<br />
The upgrade of the plugin will then happen as part of the Moodle upgrade process.<br />
<br />
If an out-of-date plugin causes your upgrade to fail, you can usually delete the plugin code rather than uninstalling it from within Moodle so that the data associated with it is not deleted.<br />
<br />
==Put your site into maintenance mode==<br />
Before you begin upgrading your site, you should put it into [[Maintenance_mode | maintenance mode]] to stop any non-admin users from logging in. Then you should wait for any currently running cron processes to complete before proceeding.<br />
<br />
== Install the new Moodle software ==<br />
You can fetch the current version of the software through <br />
<br />
wget http://sourceforge.net/projects/moodle/files/Moodle/stable{{Version2}}/moodle-latest-{{Version2}}.tgz<br />
<br />
=== Standard install package ===<br />
<br />
# Move your old Moodle software program files to another location. ''Do NOT copy new files over the old files.''<br />
# Unzip or unpack the upgrade file so that all the new Moodle software program files are in the location the old files used to be in on the server. Moodle will adjust SQL and moodledata if it needs to in the upgrade.<br />
# Copy your old [[Configuration file|config.php file]] back to the new Moodle directory. <br />
# As mentioned above, if you had installed any plugins on your site you should add them to the new code tree (Moodle directory structure) now. It is important to check that you get the correct version for your new version of Moodle. Be particularly careful that you do not overwrite any code in the new version of Moodle and that you place the plugin folders in the correct directory (the same directory that they are in in the current installation.)<br />
# Your moodledata folder should be located separately to your Moodle code folder and, as such, should not need anything done to it. Moodle 3.0 will throw a warning if it is located in a web accessible folder and the moodledata should never be located in the Moodle code folder. If you are moving your installation to a new server or new location on your server, then you will need to follow the Migration documents.<br />
<br />
====Linux====<br />
mv moodle moodle.backup<br />
tar xvzf moodle-{{Version}}.tgz<br />
<br />
Next, copy across your config.php, any custom plugins, and your .htaccess file if you created one ('''check that custom plugins are the correct version for your new Moodle first'''):<br />
<br />
cp moodle.backup/config.php moodle<br />
cp -pr moodle.backup/theme/mytheme moodle/theme/mytheme<br />
cp -pr moodle.backup/mod/mymod moodle/mod/mymod<br />
<br />
Don't forget to make moodle/config.php (and the rest of the source code) readable by your www server. Ideally the files should not be writeable by your server.<br />
<br />
chown -R www-data:www-data moodle (Linux debian - change to appropriate user and group for your OS version)<br />
chmod -R 755 moodle<br />
<br />
If you use cron, take care that cron.php is executeable and uses the correct php command: <br />
chmod 740 admin/cli/cron.php (some configurations need chmod 750 or chmod 755)<br />
copy the first line from cron.php (if it looks like '#!/usr/local/bin/php' or '#!/usr/local/bin/php5.3', no need to copy '<?php') <br />
if necessary. However, for a simple upgrade, there should be no need to change anything with cron.<br />
<br />
=== Using Git ===<br />
<br />
You can use Git for updating or upgrading your Moodle. See [[Git for Administrators]] for details.<br />
<br />
===Command line upgrade===<br />
<br />
On Linux servers, Moodle {{Version}} supports running the [[CLI|upgrade from the command line]], rather than through a web browser. This is likely to be more reliable, particularly for large sites.<br />
<br />
== Finishing the upgrade ==<br />
<br />
The last step is to trigger the upgrade processes within Moodle. <br />
<br />
If you put your site into Maintenance mode earlier; take it out now!<br />
<br />
To do this just go to ''Administration > Site administration > Notifications''.<br />
<br />
Moodle will automatically detect the new version and perform all the SQL database or file system upgrades that are necessary. If there is anything it can't do itself (very rare) then you will see messages telling you what you need to do.<br />
<br />
Assuming all goes well (no error messages) then you can start using your new version of Moodle and enjoy the new features!<br />
<br />
Note: If you are running multiple servers then you should purge all caches manually (via ''Administration > Site administration > Development > Purge all caches'') after completing the upgrade on all servers.<br />
<br />
===Fatal error: Maximum execution time of 30 seconds exceeded...===<br />
<br />
If your server uses a main language other than English, you may encounter a 'Fatal error: Maximum execution time of 30 seconds exceeded' when you try to upgrade it. You can increase max_execution_time = 160 on php.ini to allow the scripts enough time to process the language update. Otherwise, you can switch to English as the default language before doing the upgrade and back to your original language after a succcessful upgrade. See the forum discussion at https://moodle.org/mod/forum/discuss.php?d=119598.<br />
<br />
==After upgrading==<br />
<br />
The config.php file from your installation should work fine but if you take a look at config-dist.php that came with Moodle 3.0 there are more/different options available (e.g. database drivers and settings). It's a good idea to map your old config.php settings to a new one based on the 3.0 config-dist.php.<br />
<br />
===Cron===<br />
<br />
Cron has received a major update (MDL-25499) and now has support for both scheduled and ad hoc tasks.<br />
<br />
The benefits of these changes are:<br />
* The schedule for every task can be configured by the admin<br />
* Tasks can run in parallel<br />
* Cron processes use locking to prevent the same task running at the same time by different processes<br />
* Clusters with multiple identical application nodes are supported, you can run cron on all of them<br />
<br />
A result of this is that cron can be run much more often, which means (for example) forum posts can be sent out sooner. To take advantage of the new cron system it is now strongly recommended that administrators increase the frequency that cron is run to at least ''once per minute''.<br />
<br />
You also may need to modify any automated scripts you have that are parsing the output from cron. It is no longer possible to simply monitor the output of cron for the string "Cron script completed correctly" (if that is what you were doing). An alternative is to monitor the output for the string "task failed:". If you detect that a task is failing, [[Cron#Debugging_Scheduled_Tasks|here]] are some tips for debugging the failure. <br />
<br />
Before the upgrade, there may have been a cron task that was failing, which was preventing the rest of cron from being executed. A failure in any single task will no longer prevent the rest of the Moodle cron tasks from executing, so you may uncover previously masked bugs. It is a good idea to closely monitor the output from cron after the upgrade.<br />
<br />
===Assignments===<br />
<br />
The old assignment (2.2) module has been removed from core and has been replaced by a stub to support transparently remapping URLs and restoring course backups from the old module to the new one. <br />
<br />
If you are still using the old assignment (2.2) module, after upgrading to Moodle 3.0 all assignment (2.2) activities will be hidden. You need to run the [[Assignment upgrade tool]] to un-hide the activities.<br />
<br />
If you really, really need to keep using the old assignment (2.2) module, you should update the code to Moodle 3.0, and then replace the "mod/assignment" folder with the one from https://github.com/moodlehq/moodle-mod_assignment/releases before completing the upgrade.<br />
<br />
==Possible issues that may affect you in Moodle {{Version}}==<br />
<br />
''Please add items here...''<br />
<br />
See the [[dev:Moodle {{Version}} release notes|Moodle {{Version}} release notes]] for the full list of changes in Moodle {{Version}}.<br />
<br />
=== Moodle 3.1, 3.2, 3.3 and 3.4 improvements ===<br />
<br />
Depending on which version you are upgrading from, please see the section 'Possible issues that may affect you' in the documentation<br />
<br />
* [https://docs.moodle.org/31/en/Upgrading Upgrading to Moodle 3.1]<br />
* [https://docs.moodle.org/32/en/Upgrading Upgrading to Moodle 3.2]<br />
* [https://docs.moodle.org/33/en/Upgrading Upgrading to Moodle 3.3]<br />
* [https://docs.moodle.org/34/en/Upgrading Upgrading to Moodle 3.4]<br />
<br />
==See also==<br />
<br />
* [[Installation]]<br />
* Using Moodle [http://moodle.org/mod/forum/view.php?id=28 Installation help forum] <br />
* [[dev:Moodle {{Version}} release notes|Moodle {{Version}} release notes]]<br />
<br />
[[es:Actualización de moodle]]<br />
[[fr:Mise à jour]]<br />
[[ja:Moodleをアップグレードする]]<br />
[[de:Aktualisierung von Moodle]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=GDPR&diff=130461GDPR2018-03-20T10:26:42Z<p>Fox: French link</p>
<hr />
<div>{{Managing a Moodle site}}<br />
== Overview ==<br />
<br />
GDPR stands for General Data Protection Regulation and refers to the European Union regulation for data protection for all individuals within the European Union. The regulation (Regulation (EU) 2016/679)[[#ref2|2]] becomes enforceable on 25 May 2018 and replaces the data protection directive (officially Directive 95/46/EC)[[#ref3|3]] from 1995.<br />
<br />
Who does it affect?<br />
<br />
Any individual or organisation that stores or processes personal information on an identifiable person from an EU member state (regardless if the processing or storage of information occurs in the EU or not). It also applies if the individual or organisation themselves is located in an EU member state.<br />
<br />
What kind of information comprises personal data in a Moodle site?<br />
<br />
It is all information that can be associated with a natural person. Each user account and all the activity associated with that user account is classified as personal information. This extends to information stored in backups, as well as associated information such as web server log files.<br />
<br />
What are the penalties for non-compliance with the regulations?<br />
<br />
Severe!<br />
<br />
== Disclaimer ==<br />
<br />
The advice in this document is provided for informational purposes only, and not be construed as legal or professional advice. Moodle Pty Ltd does not warrant that the advice is accurate, complete, reliable, current or error-free.<br />
<br />
== Checklist ==<br />
<br />
<ol><br />
<li> Is the Moodle site hosted in an EU member state, or is it possible that any user of the Moodle site is an individual from an EU member state?<br />
<ul><br />
<li> If you answered no to this question, you are not affected by this regulation. However, the benefits of data protection afforded by the regulation are universally applicable and you may consider voluntarily complying with this legislation for the benefit of your site users.</li><br />
</ul><br />
</li><br />
<li><br />
Do you require your site users to accept a site policy document before using your site (either in Moodle or something outside of Moodle, like a paper form)?<br />
<ul><br />
<li>If you answered no to this question, you must start doing so. Users need to be aware of their rights and the processes with which they can exercise their rights.</li><br />
<li>If you answered yes to this question you must review your privacy policy to make sure it covers all requirements of the new regulations (see “Site policy” below). If you change your privacy policy you must get all site users to accept the new policy before they can continue using the site.</li><br />
</ul><br />
</li><br />
<li>Is it possible that your site is used by minors? (Under 16 in most member states, but some states may reduce this as low as 13 years).<br />
<ul><br />
<li>If you answered yes to this question, you must ensure that the consent is obtained from their legal guardian. Keep in mind that collecting and processing personal information on minors is may impact your risk assessment. You should take extra care to adequately secure this information, and retain it for as short a period as is necessary.</li><br />
</ul><br />
</li><br />
<li>Is it the collection or storage of personal data from your site users likely to result in a high risk to their rights and freedoms?<br />
<ul><br />
<li>Some examples that would indicate high risk are:<br />
<ul><br />
<li>a systematic and extensive evaluation of personal aspects relating to natural persons which is based on automated processing, including profiling, and on which decisions are based that produce legal effects concerning the natural person or similarly significantly affect the natural person</li><br />
<li>processing on a large scale of special categories of data including<br />
<ul><br />
<li>Racial or ethnic origin</li><br />
<li>Political opinions</li><br />
<li>Religious or philosophical beliefs</li><br />
<li>Trade union membership</li><br />
<li>Genetic data</li><br />
<li>Biometric data</li><br />
<li>Data concerning health</li><br />
<li>Sexual orientation</li><br />
<li>Data concerning a natural person’s sex life</li><br />
<li>Criminal convictions</li><br />
</ul><br />
</li><br />
<li>This is not an exhaustive list and if you are unsure if you should consider the data collected from your users as “High risk” you should refer to the legislation and seek professional advice.</li><br />
</ul><br />
</li><br />
<li>If the answer is “Yes”, you should perform a Data Protection Impact Assessment. Refer to the legislation and seek professional advice.</li><br />
</ul><br />
</li><br />
<li>Do you use any of the collected personal information for the purposes of marketing?<br />
<ul><br />
<li>If you answered yes to this question - you must obtain a separate consent from each user to use this data for this purpose. Consent to use the data for marketing must be separately withdrawable by the user.</li><br />
</ul><br />
</li><br />
<li>Do you use any of the collected personal information for the purposes of research?<br />
<ul><br />
<li>If you answered yes to this question, you must either obtain a specific consent from each user to use the data for this purpose, or completely anonymise the data before using it for research. <br /><br />[https://github.com/moodlehq/moodle-local_anonymise https://github.com/moodlehq/moodle-local_anonymise] is an example of a tool designed to anonymise all the data on a moodle site.</li><br />
</ul><br />
</li><br />
<li>Do you share any of the collected data with any third parties? This includes sites and services that integrate with Moodle such as: Google analytics, LTI, Repositories (Google Docs, OneDrive etc), Authentication systems etc. This also includes sites and services used in the provision of your own Moodle site such as hosting providers.<br />
<ul><br />
<li>If you answered yes to this question then you are responsible for all data that is shared with a third party. You must obtain the user’s consent to share this data with each third party. If the list of third party services changes you must re-obtain consent from all site users for each new third party site/service. You should also take reasonable steps to ensure that each third party will adequately protect users personal data including:<br />
<ul><br />
<li>Reviewing the third party privacy policy to make sure it is congruent with your own</li><br />
<li>Monitoring and notifying your site users about changes to the third party privacy policy</li><br />
<li>Identify the mechanism for processing requests to erase or correct personal data with each third party so that you can follow this process when you receive one of these requests for your own site</li><br />
<li>Identify and list the data protection officer, and privacy policy for each third party site as part of your own privacy policy</li><br />
</ul><br />
</li><br />
<li>Google analytics for example has not yet provided clear updated instructions on how to comply with the new GDPR when using their service. It is probable that they will issue guidance on how to use Google Analytics in compliance with the GDPR before it becomes enforceable, but this example demonstrates that it is your responsibility to ensure the protection of privacy of the users of your site and it is not legal to use cloud services without considering the privacy implications of each and every service provider.</li><br />
</ul><br />
</li><br />
<li>Do you follow best practice policies and procedures to ensure data security?<br />
<ul><br />
<li>If you answered no to this question then you have must review your policies and procedures to ensure you are not placing your sites users personal data at risk.<br />
<ul><br />
<li>“Best practices” includes but is not limited to organisational and technical measures to ensure a level of security appropriate to the risk such that:<br />
<ul><br />
<li>pseudonymisation and encryption of personal data</li><br />
<li>the ability to ensure the ongoing confidentiality, integrity, availability and resilience of processing systems and services</li><br />
<li>the ability to restore the availability and access to personal data in a timely manner in the event of a physical or technical incident</li><br />
<li>a process for regularly testing, assessing and evaluating the effectiveness of technical and organisational measures for ensuring the security of the processing</li><br />
</ul><br />
</li><br />
<li>Examples:<br />
<ul><br />
<li>Appropriate use of encryption (https)</li><br />
<li>Maintaining all systems and software with relevant security updates.</li><br />
<li>Deletion of personal data as soon as possible, once it is no longer required for the purpose it was collected.</li><br />
</ul><br />
</li><br />
</ul><br />
</li><br />
</ul><br />
</li><br />
<li>Do you have defined policies and procedures for disclosing data breaches?<br />
<ul><br />
<li>If you answered no this question then you must define some</li><br />
<li>If you have existing policies and procedures they should be reviewed</li><br />
<li>These policies and procedures must include notifying the Supervisory Authority within 72 hours of the data breach and notifying all affected users if they have been adversely affected (personal data disclosed).</li><br />
</ul><br />
</li><br />
<li>Have you appointed a data protection officer, and listed them in your privacy policy?<br />
<ul><br />
<li>If you answered no to this question then you must appoint one and list them in your sites privacy policy. The data protection officer is expected to be “proficient at managing IT processes, data security (including dealing with cyber-attacks) and other critical business continuity issues around the holding and processing of personal and sensitive data [[#ref1|1]].</li><br />
</ul><br />
</li><br />
<li>Do you have a mechanism with with your site users can request their personal data is erased, corrected or made available to the requesting user on your site?<br />
<ul><br />
<li>If you answered yes to this question then must ensure it is listed in your sites privacy policy</li><br />
<li>If you answered no to this question then you define one and list it in your sites privacy policy<br />
<ul><br />
<li>For a Moodle site a suitable mechanism would be an email address, reserved for this purpose that is monitored by an administrator for your Moodle site. Once a request is received, reasonable steps should be taken to ensure the authenticity of the request and the identity of the user making the request</li><br />
<li>Corrections to personal data can be processed by changing the data in Moodle directly using an administrator account</li><br />
<li>Erasures of personal data can be processed by either deleting the user account, or by editing the user account to remove all identifying information and making it inactive</li><br />
<li>Records of personal data can be obtained from the “Site Administration -&gt; Reports -&gt; Logs” by downloading all the logs for a single user as a CSV file. There will likely be additional personal data about a user that is stored outside of Moodle, such as web server access logs.</li><br />
</ul><br />
</li><br />
</ul><br />
</li><br />
<li>Does your organisation have more than 250 employees?<br />
<ul><br />
<li>If you answered yes to this question then you must maintain detailed records on all processing of personal data. Refer to the regulation for details of the records that must be maintained</li><br />
</ul><br />
</li><br />
</ol><br />
<br />
== Site policy ==<br />
<br />
Moodle site policy can be used to collect consent for the purposes of GDPR compliance. The site policy document should be reviewed carefully to make sure it covers all the information listed below, in succinct, simple language.<br />
<br />
Site policies can be enabled in Moodle via the “Site policy URL (sitepolicy)” setting on the “Site Administration -&gt; Security -&gt; Site policies” page. This setting should be set to a public page that contains all of the information listed below. The site policy will be displayed in an iframe as part of the login process, so it does not require headers and footers.<br />
<br />
A recommended practice is to create a file resource on the frontpage of the Moodle site and copy the url for this resource to use as the site policy. This means the site policy is always available for your users to access, and can be updated easily from within Moodle. Note that this technique is incompatible with the “Force users to log in (forcelogin)” setting, also on the “Site Administration -&gt; Security -&gt; Site policies” page as the file resource will no longer be visible until the user has logged into the site.<br />
<br />
For more information on the “sitepolicy” setting in Moodle see the section 'Site policy URL' in [[Site policies]].<br />
<br />
The site policy must include all of the following information in simple language:<br />
<br />
# What information is collected.<br />
# The purpose of all processing to be performed on the users data. Marketing must be listed separately with a separate revocable “consent”.<br />
# The identity of the data controller and contact information<br />
# List of rights<br />
# The period the data is stored<br />
# The mechanism for withdrawing consent<br />
# The mechanism for requesting corrections, or erasures of personal data<br />
# The mechanism for requesting a record of all personal data<br />
# List of third parties that data will be shared with (This includes integrations such as LTI, portfolios, plagiarism, repositories, authentication etc.) including:<br />
## The contact details of the data protection officer for each<br />
## The privacy policy for each.<br />
# Whether the personal data will be used for any automated decision making process, including the significance and details of the process (e.g. analytics).<br />
<br />
=== Sample site policy ===<br />
<br />
'''Privacy and personal data'''<br />
<br />
At Company XYZ we take your privacy very seriously. In order to provide access to the service we must collect and store some personal information about you.<br />
<br />
'''Minors'''<br />
<br />
Children under 16 years of age are not permitted to access the services provided by [https://example.com/ https://example.com/]. By agreeing to this privacy policy you are also agreeing that you are 16 years of age or older.<br />
<br />
'''What is collected?'''<br />
<br />
Basic profile information is collected from you when you create your account including your full name and email address.<br />
<br />
As you use the site, information about the users, courses, activities and resources you interact with will also be stored and linked to your profile information.<br />
<br />
'''How is this information used?'''<br />
<br />
This information is only used to provide you access to the online courses at [https://example.com/ https://example.com/]. Statistical information about usage of the site is also used to improve the site and services provided on the [https://example.com/ https://example.com/] website.<br />
<br />
'''Who can I contact?'''<br />
<br />
The data protection officer for Company XYZ is John Smith and they may be contacted at [mailto:privacy@example.com privacy@example.com]<br />
<br />
'''Who is my data shared with?'''<br />
<br />
In order to provide access to LTI content provided by https://www.awesomeltis.com, we may share your basic profile information with Awesome LTI Ltd. The data protection officer for Awesome LTI Ltd is Mrs Jane Smith and she may be contacted at [mailto:privacy@awesomeltis.com privacy@awesomeltis.com]. The privacy policy for Awesome LTI Ltd is available at [http://www.awesomeltis.com/privacy https://www.awesomeltis.com/privacy]. In order to protect your privacy Company XYZ has entered into a data sharing agreement with Awesome LTI Ltd. The terms of this agreement are available here: [https://example.com/data-sharing.html https://example.com/data-sharing.html].<br />
<br />
'''How long is my data stored?'''<br />
<br />
Your personal data is stored as long as you are enrolled in one or more online courses at [https://example.com/ https://example.com/]. Course data is deleted 6 months after the end date for each course and profile information will be anonymised when an account has not been accessed for 12 consecutive months.<br />
<br />
'''How do I withdraw my consent for Company XYZ to store and process my personal data?'''<br />
<br />
If you have previously consented to allow Company XYZ to store and process your personal data in accordance with this privacy policy, and you wish to withdraw your consent, please send an email to the data protection officer at [mailto:privacy@example.com privacy@example.com]. You will no longer be able to access the services provided by [https://example.com/ https://example.com/] if your consent is withdrawn.<br />
<br />
'''How do I request that my personal data is corrected or erased?'''<br />
<br />
You may make corrections to your basic profile information by logging into the [https://example.com/ https://example.com/] and editing your own profile. If you have questions, or would like any other data to be corrected or erased, please send an email to the data protection officer at [mailto:privacy@example.com privacy@example.com].<br />
<br />
'''How do I request a record of all my personal data that has been collected?'''<br />
<br />
You may request a record of all of the personal data relating to you that has been collected in accordance with this privacy policy. To do so, please send an email to the data protection officer at [mailto:privacy@example.com privacy@example.com].<br />
<br />
==Plugins==<br />
<br />
Two plugins are available as follows for adding GDPR functionality to Moodle 3.4.2 or 3.3.5 sites. (All GDPR functionality will be available as standard in Moodle 3.5.)<br />
<br />
The '''[https://moodle.org/plugins/tool_policy Policies plugin]''' provides a new user sign on process, with ability to define multiple policies (site, privacy, third party), track user consents, and manage updates and versioning of the policies.<br />
<br />
The '''[https://moodle.org/plugins/tool_dataprivacy Data privacy plugin]''' provides the workflow for users to submit subject access requests and for site administrators and privacy officers to process these requests. The subject access request process currently retrieves the user information from the following core plugins:<br />
<br />
* Choice Activity Module<br />
* HTML Block<br />
* User Tours<br />
<br />
Support for retrieving user information from the remaining core plugins will be added soon. The plugin will also be further extended to include functionality for data erasure requests and the data registry to define a purpose and retention period for data stored in a Moodle site.<br />
<br />
Moodle 3.4.2 and 3.3.5 include the following core API changes that are required to support the GDPR plugins:<br />
<br />
* An age and location check to identify minors<br />
* The API to request personal data from all plugins<br />
* Implementation of the API for a subset of Moodle core plugins so far<br />
<br />
==See also==<br />
<br />
* [[:dev:GDPR for plugin developers|GDPR for plugin developers]] in the dev docs<br />
* [https://moodle.org/mod/forum/discuss.php?d=352538 EU General Data Protection Regulation (GDPR) compliance] forum discussion<br />
<br />
References:<br />
<br />
* [https://www.eugdpr.org/ Home Page of EU GDPR]<br />
* [http://data.consilium.europa.eu/doc/document/ST-5419-2016-INIT/en/pdf GDPR Regulation]<br />
* [http://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX:31995L0046 Directive 95/46/EC]<br />
<br />
==Any questions?==<br />
<br />
Please post in the [https://moodle.org/mod/forum/view.php?id=7301 Security and privacy forum] on moodle.org.<br />
<br />
[[Category:GDPR]]<br />
<br />
[[es:GDPR]]<br />
[[fr:RGPD]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=Offline_quiz_activity&diff=129829Offline quiz activity2018-01-08T15:00:36Z<p>Fox: Link corrected</p>
<hr />
<div>{{Infobox plugin<br />
|type = activity<br />
|entry = https://moodle.org/plugins/view/mod_offlinequiz<br />
|tracker = https://github.com/academic-moodle-cooperation/moodle-mod_offlinequiz<br />
|discussion = https://github.com/academic-moodle-cooperation/moodle-mod_offlinequiz<br />
|maintainer = [[user:AMC Academic Moodle Cooperation|AMC Academic Moodle Cooperation]]<br />
|float = right<br />
}}<br />
{{Note|You can find the most up-to-date English and German documentation for this plugin in the AMC website at http://www.academic-moodle-cooperation.org/en/module/offline-quiz/. This page is intended for users who clicked on the 'Moodle Docs for this page' link and for Moodle users of languages other than English and German (IN OTHER LANGUAGES at the bottom of this page).}}<br />
<br />
[[File:MC Offline quiz module thumbnail.png]]<br />
The Moodle MC Offline quiz module adds paper-and-pencil multiple-choice quizzes to Moodle. In offline quizzes students mark answers to questions on a sheet of paper (the answer form). The students' answer forms are evaluated and graded automatically by the offline quiz module. <br />
<br />
More precisely, a complete offline quiz consists (at least) of the following steps:<br />
<br />
* A teacher creates an offline quiz in Moodle and adds multiple-choice questions, all-or-nothing multiple-choice questions or description questions (text) to the quiz. This is very similar to creating online quizzes (standard Moodle quizzes).<br />
* From the question lists the teacher creates question sheets and answer forms as PDF (DOCX) documents using the module. <br />
* The question sheets and answer forms are handed out to students for the actual quiz. The students mark the answers they think are correct in the answer form.<br />
* The teacher scans the filled-in answer forms and uploads the resulting images into the offline quiz. The scanned answer forms are evaluated and graded automatically by the module. <br />
* If necessary, the teacher corrects errors that might have occurred due to mistakes made by the students or due to bad scan quality. <br />
<br />
After results have been created in an offline quiz, students can review their result as usual. If the teacher allows it, students can also see the scanned answer forms and which markings have been recognised as crosses.<br />
<br />
The module supports up to six groups which are not related to Moodle course groups. Each group can contain a different set of questions in a different order. Separate question sheets and answer forms are created for the different offline quiz groups.<br />
<br />
The module also supports lists of participants which are useful for checking which students actually took part in the exam. Lists of participants are pre-filled with students in Moodle. PDF versions of those lists can be created in the module for easy marking during the exam. The marked lists can be uploaded and evaluated automatically.<br />
<br />
==Example==<br />
<br />
The offline quiz module is used intensively at different Austrian universities for mass exams. Hundreds of students can be easily examined at the same time (given enough seating space in lecture halls) without the need for expensive e-testing equipment.<br />
<br />
==Author==<br />
Juergen Zimmer, from the [http://www.academic-moodle-cooperation.org Academic Moodle Cooperation] of several Vienna Universities.<br />
<br />
==Moodle versions==<br />
* This module is available from [https://moodle.org/plugins/view.php?plugin=mod_offlinequiz the Moodle plugins database] for Moodle 2.6, Moodle 2.7 and Moodle 2.8. <br />
* The Moodle 2.8 version released on september 2nd 2015, but seems to have a problem that it can not add specific questions from the question bank, even though adding random questions and making a new question work OK.<br />
<br />
[[File:Offline quiz edit offline quiz.jpg|600px]]<br />
<br />
[[File:Offline quiz add random questions.jpg|600px]]<br />
<br />
[[File:Offline quiz add a new question.jpg|600px]]<br />
<br />
* You can expect a version for Moodle 2.9 to be released approximately in February 2016.<br />
<br />
* There seems to be a version for Moodle 2.5 in [https://github.com/academic-moodle-cooperation/moodle-mod_offlinequiz/tree/MOODLE_25_STABLE Github].<br />
* There seems to be a version for Moodle 2.2 in [https://github.com/academic-moodle-cooperation/moodle-mod_offlinequiz/blob/5dbf36388eea93f09c3bedfb06dcc77b9e993f8e/README.txt Github].<br />
<br />
==Translations available==<br />
The Moodle 2.8 version has French, German and Mexican Spanish language translations made in [https://lang.moodle.org/local/amos/ AMOS].<br />
<br />
==Installation==<br />
<br />
Copy the module code directly to the "mod/offlinequiz" directory. Open the messages page in the administration area to automatically start the installation.<br />
<br />
The automatic analysis of questionnaires requires the activation of an appropriate cronjob (see README.txt).<br />
<br />
===Cronjob===<br />
<br />
For the evaluation of answer forms an additional cronjob has to be installed. This should look similar to the following:<br />
<br />
*/10 * * * * DATE=`date +\%Y\%m\%d`; php <your moodle root dir>/mod/offlinequiz/cron.php --cli=1 >> /var/log/moodle/cron-olq.log.$DATE 2>&1<br />
<br />
but has to be adjusted to your environment. Since the evaluation of answer forms usually takes a lot of system resources, it is recommended to run this cronjob on a separate application server to take load from the frontend servers.<br />
<br />
===Website settings===<br />
In the website admin settings for the module <br />
<br />
Site Administration -> Plugins -> Activity modules -> Offline Quiz<br />
<br />
One can choose the default settings for the module and also determine the University Logo that will appear on the top of the answer forms (Logo URL).<br />
<br />
The user identification has to be set to a formula describing how the user IDs can be retrieved from the digits marked by the students on the answer forms.<br />
<br />
For example:<br />
<br />
A user identification formula <br />
a[7]=username<br />
<br />
means that the students mark a 7 digit number on the answer form. A concatenation of the letter 'a' and that number denotes the 'username' of the user in Moodle's 'user' table.<br />
<br />
A formula <br />
b[5]cd=idnumber <br />
means that the students mark a 5 digit number on the answer form. A concatenation of the letter 'b', the marked number, and the string 'cd' denotes the 'idnumber' of the user in Moodle's 'user' table.<br />
<br />
==Admin settings==<br />
<br />
As an administrator you can set the default values instance-wide on the settings page for administrators in the MC Offline quiz module.<br />
<br />
* formula for participant identification (text field)<br />
* mix questions (checkbox)<br />
* mix answers (checkbox)<br />
* logo URL (text field)<br />
* copyright indication (checkbox)<br />
* settings for exam inspection (checkbox)<br />
* decimal places (drop down)<br />
* paper's white level (drop down)<br />
* 1-click inscription (checkbox)<br />
* role for inscription (drop down)<br />
* saving days (text field)<br />
<br />
==Screenshot of the module==<br />
[[File:Offline_quiz_screenshot.png|600px]]<br />
<br />
===Contact===<br />
In case you have any questions regarding this module you can either contact the author of the module (zimmerj7@univie.ac.at) or the e-learning support of the University of Vienna (e-support.zid@univie.ac.at).<br />
<br />
===See also===<br />
This information was copied from http://www.academic-moodle-cooperation.org/en/modules/offline-quiz/ <br />
<br />
[[Category:Quiz]]<br />
[[Category:Questions]]<br />
[[Category:AMC Academic Moodle Cooperation]]<br />
<br />
[[es:Actividad de examen fuera-de-línea]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=Search_and_replace_tool&diff=129660Search and replace tool2017-12-12T12:10:22Z<p>Fox: </p>
<hr />
<div>{{Admin tools}}<br />
Admins can search and replace text e.g. URLs in their Moodle database using the search and replace tool at <nowiki>http://yourmoodlesite.org/admin/tool/replace/index.php</nowiki> (replacing yourmoodlesite.org with the address of your Moodle site). This is useful when a [[Moodle migration|Moodle site is moved from one server to another]] or when the URL changes.<br />
<br />
Alternatively, a command line script can be used to search and replace text. See [[Administration via command line]] for details.<br />
<br />
{{Warning|A database backup should be created before performing a search and replace.}}<br />
<br />
==See also==<br />
<br />
* Tracker issue MDL-35099 Convert hidden search/replace script into a proper core admin tool<br />
<br />
[[es:Herramienta para buscar y remplazar]]<br />
[[fr: Recherche et remplacement]]<br />
[[de:Datenbank-Suche]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=Moodle_migration&diff=129659Moodle migration2017-12-12T10:50:46Z<p>Fox: Typo</p>
<hr />
<div>{{Installing Moodle}}<br />
There may be times when you need to move your Moodle site from one server to another. For example, moving a Moodle site from shared hosting service's server to a dedicated server.<br />
<br />
==Recommended method==<br />
<br />
This involves moving a whole site from one server to another. If you are changing the domain/IP address to the new server you need to do these steps:<br />
<br />
===Turn on maintenance mode===<br />
<br />
Place your current Moodle site into [[Maintenance mode]] via ''Site Administration > Server > Maintenance Mode'' to prevent any further additions to the Moodle database. Don't let administrators login during the migration as they are not affected by the maintenance mode setting.<br />
<br />
===Backup the Moodle database on the old sever===<br />
<br />
The right way to back up your database depends on which database system you are using. The instructions below are one way to back up a MySQL database. Another option would be to use a tool like phpMyAdmin to manually make a backup. The documentation for your database will give more options. There are many ways to do such backups. Here is an outline of a little script you can run from command line on Unix to backup the database:<br />
<br />
<pre><br />
cd /my/backup/directory<br />
mv moodle-database.sql.gz moodle-database-old.sql.gz<br />
mysqldump -h example.com -u myusername -p'mypassword' -C -Q -e --create-options mydatabasename > moodle-database.sql<br />
</pre> <br />
If you only write "-p" without your password, you will be prompted for it.<br />
<br />
=== Restore the database backup to the new server ===<br />
<br />
Copy the database back up files to the new server and restore into the new database server.<br />
<br />
Once you have created the new database on the new server:<br />
<br />
<pre>mysql -p new_database < moodle-database.sql</pre><br />
<br />
For other databases, follow their instructions for restoring a backup. <br />
<br />
===Copy moodledata from the old server to the new server===<br />
<br />
Copy the contents of your data directory (check for the value in <code>$CFG->dataroot</code>) to the new server. This can be a lot of data, so consider using a good data copying tool like rsync. If using an FTP client, the transfer of the <code>filedir</code> folder must be in '''BINARY''' mode or the files will get corrupted in the process.<br />
<br />
Check the file permissions of the copied files. The web server needs read and write access.<br />
<br />
===Copy the Moodle code from the old server to the new server===<br />
<br />
You will need to copy the Moodle code itself to the new server (this is the Moodle folder found in your webroot folder e.g. /var/www or public_html). <br />
<br />
Check the file permissions of the copied files. The web server needs read access.<br />
<br />
===Update config.php with the URL of the new server===<br />
<br />
If the migration will move Moodle to a new URL, then update $CFG->wwwroot in config.php to point to the new location.<br />
<br />
Also check the other properties there. Is the path $CFG->moodledata still correct? Do the database connection settings need to be changed?<br />
<br />
===Test the copied site===<br />
<br />
You should now be able to log into the new site as admin, and verify that most things are working.<br />
<br />
===Update links containing wwwroot in the database===<br />
<br />
The one thing we have not fixed is any internal links stored in the database. To fix these use the [[Search and replace tool]] buy going to {wwwroot}/admin/tool/replace/index.php.<br />
<br />
Enter the url for your old server (<nowiki>http://oldserver.com/</nowiki>) and new server (<nowiki>http://newserver.com/</nowiki>) and it will fix any links stored in the database.<br />
<br />
===Take the site out of maintenance mode===<br />
<br />
Test the migration some more, then when you are satisfied, remember to take the site out of maintenance mode.<br />
<br />
==Quick and hacky method==<br />
<br />
If you have shell access on both servers, here is a quick command-line based method.<br />
<br />
*Set up a new empty database on the '''new''' server.<br />
*Place your existing Moodle site into maintenance mode.<br />
*Login to shell on the '''old''' existing server.<br />
*Use rsync to copy '''moodledata''' and '''public_html''' or '''moodle''' folders (or whatever directory your Moodle install is in) to the new server - execute (replacing caps with your details; SOURCE = the directory you want to copy) for each directory:<br />
::<code>rsync -av -e ssh SOURCE/ USERNAME@NEW_SERVER.COM:/PATH/TO/DESTINATION/</code><br />
*Dump existing database and move and import into database on new server by executing:<br />
::<code>mysqldump --allow-keywords --opt -uMySQL_USERNAME -pPASSWORD DATABASE | ssh USER@DOMAIN "mysql -uMySQL_USERNAME -pPASSWORD DATABASE"</code><br />
*Replace any links in the database that contin the full site URL:<br />
::<code>#sed -e 's/oldserver.com/newserver.com/g' oldmysqldump.sql > newmysqldump.sql</code><br />
*On the '''new server''', update '''config.php''' with relevant details where applicable (e.g. database name and user details, the wwwroot and the dataroot).<br />
*Check ownership and permissions are correct on both moodle code and moodledata directories.<br />
*Make sure everything is working.<br />
<br />
Takes about 15 minutes for a small site. However, transferring several Gigabytes of data for a larger site can take hours depending on your network connection and hard drive read/write speed.<br />
<br />
When you are happy all has gone well, set up redirects/make DNS changes if required, take new site out of maintenance mode and "switch off" old site. <br />
<br />
*If you are switching the ip address from the old server to the new one, you will need to turn off the old server before firing up the new one to avoid ip addressing conflicts and confusion!<br />
<br />
==Other considerations==<br />
<br />
===Upgrade Moodle at the same time?===<br />
<br />
While doing the work of migrating Moodle, you might want to [[Upgrading | upgrade Moodle]] to the latest version at the same time. On the other hand, if you do that, and something breaks, you won't be sure which change caused the problem, so the more cautious approach is to change one thing at a time, and test in between to verify that all is well.<br />
<br />
===DNS & masquerading changes===<br />
<br />
You may have had to change the DNS entries for the new Moodle site. If you have done so, it will take some time for the changes to replicate, so be patient. If your server is located behind a firewall, you may also have to change your firewall rules to allow access to the new server. See the [[Masquerading | masquerading docs]].<br />
<br />
===Internal and external access===<br />
<br />
If you have a set up where your Moodle site can be accessed via a network and via the internet, ensure you check that the new site can be accessed internally and externally.<br />
<br />
===ReCAPTURE===<br />
If you migrate to a new domain and have setup [[Email-based_self-registration]], you need to create new API-Keys at google. You will find the explanation and links to google in [[Email-based_self-registration]].<br />
<br />
==See also==<br />
<br />
* [[Site backup]]<br />
* [[Site restore]]<br />
* [[Backup and restore FAQ]]<br />
<br />
==Any questions?==<br />
<br />
Please post in the [http://moodle.org/mod/forum/view.php?id=28 Installing and upgrading help forum] on moodle.org<br />
<br />
[[es:Migración de Moodle]]<br />
[[fr:Migration de Moodle]]<br />
[[ja:Moodle移行]]<br />
[[de:Moodle-Migration]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=Standard_Moodle_tags&diff=129635Standard Moodle tags2017-12-11T09:00:26Z<p>Fox: /* Tags in use */</p>
<hr />
<div>Tags are useful for connecting different bits of information together.<br />
<br />
Obviously it's important to use the same tags everywhere.<br />
<br />
This page describes standard Moodle tags that you should use when describing Moodle events on the internet (Flickr, Twitter, Facebook, del.icio.us etc)<br />
<br />
==General Moodle stuff==<br />
<br />
For general discussion of Moodle, use the tag "moodle".<br />
<br />
Twitter example:<br />
I just installed #moodle on a computer I bought ten years ago!<br />
<br />
==Moodle Moots==<br />
<br />
For Moodle conferences (Moots) use mootCCYY where:<br />
* CC is a country ISO code or state abbreviation, and<br />
* YY is a year.<br />
<br />
mootAU09<br />
<br />
Capitalisation doesn't matter and just helps readability.<br />
<br />
The two letter code would usually be a country, but for somewhere like the US where there are different moots they might choose to use "us" or a state like "sf" or "ok". It really doesn't matter if two moots both used mootus09 for example, because they would be separated in time.<br />
<br />
==Tags in use==<br />
<br />
* #mooteu09 MoodleMoot Euskadi<br />
* #mootNL09 Amsterdam Moodlemoot<br />
* #mootUS09ok Moodlemoot Oklahoma (or #mootok09)<br />
* #mootUS09SF Moodlemoot San Francisco (or #mootsf09)<br />
* #mootin09 Goshen Midwest MoodleMoot<br />
* #mootus09ny MoodleMoot Delhi (or #mootny09) <br />
* #mootar09 MoodleMoot Argentina<br />
* #mootat09 MoodleMoot Austria <br />
* #mootDE09 MoodleMoot Germany 2009<br />
* #mootco09 MoodleMoot Colombia<br />
* #mootcl09 MoodleMoot Chile<br />
* #mootes09 MoodleMoot Spain 2009<br />
* #moodle #OE09 Moodle at Online Educa 2009 in Berlin (December)<br />
* #moodledev09 [[Development:Czech Hackfest 2009|Czech Hackfest 2009]]<br />
* #imoot and #imoot2010 iMoot 2010<br />
* #mootJP10hk Moodlemoot Japan in Hakodate, February 2010<br />
* #mootDE10b Moodlemoot Germany 2010 in Berlin March<br />
* #mootDE10e [http://moodle2010.de/ Moodlemoot Germany 2010 in Essen] 16-17 September 2010<br />
* #mootNZ10 Moodle Moot New Zealand (Christchurch) April 2010<br />
* #mootUK10 MoodleMoot UK April 2010<br />
* #mootsi10 Slovenian MoodleMoot<br />
* #mootok10 MoodleMoot Oklahoma<br />
* #mootau10 MoodleMoot AU 2010<br />
* #mootcz10 [http://www.moodlemoot.cz/ MoodleMoot Czech Republic, Brno] 10-11 June 2010<br />
* #mootfr10 6th French MoodleMoot<br />
* #mootIT10 MoodleMoot Italia 2010<br />
* #mootnl10 MoodleMoot NL 2010<br />
* #mootPL10 Second Polish MoodleMoot, 4-5 November 2010, Czestochowa, Poland, http://moodlemoot.pl<br />
* #mootusin10 Goshen, Indiana, USA 26-28 July, 2010<br />
* #mootustx10 Austin, Texas, USA 2-3 August, 2010<br />
* #mootfr11 [http://moodlemoot2011.uvt.rnu.tn/ 7th French MoodleMoot], Hammamet, Tunisia, 27-29 June 2011<br />
* #mootde12 [http://moodlemoot.de/ German Moodlemoot], Münster, Germany, 13-16 March 2012<br />
* #mootfr12 [http://moodlemoot2012.unimes.fr/ 8th French MoodleMoot], Nîmes, France, 20-22 June 2012<br />
* #mootde13 [http://moodlemoot.de/ German Moodlemoot], München, Germany, 28 Feb - 1 Mar 2013<br />
* #mootfr13 [http://moodlemoot2013.univ-bordeaux.fr/ 9th French MoodleMoot], Bordeaux, France, 5-7 June 2013<br />
* #smootau13 [http://http://school.moodlemoot.com.au/ 2nd Australian Schoolmoot], Sydney, Australia, 2-4 October 2013<br />
* #mootfr14 [http://moodlemoot2014.univ-paris3.fr 10th French MoodleMoot], Paris, 4-6 June 2014<br />
* #mootfr15 [https://moodlemoot2015.univ-tours.fr 11th French MoodleMoot], Tours, 10-12 June 2015<br />
* #mootfr16 [http://2016.moodlemoot.fr 12th French MoodleMoot], Sierre, Switzerland, 6-8 July 2016<br />
* #mootfr17 [http://2017.moodlemoot.fr 13th French MoodleMoot], Lyon, 28-30 June 2017<br />
* #mootfr18 [https://2018.moodlemoot.fr 14th French MoodleMoot], Bruxelles, 4-6 July 2018<br />
<br />
==See also==<br />
<br />
* Lounge discussion [http://moodle.org/mod/forum/discuss.php?d=121619 A standard naming scheme for Moodle hashtags]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=Talk:New_features&diff=129143Talk:New features2017-11-03T14:06:50Z<p>Fox: Please update interlanguage link to 3.4</p>
<hr />
<div>Hi,<br />
Can you please change [[es:Nuevas características de Moodle 3.3]] to [[es:Nuevas características de Moodle 3.4]] for this 3.4 version page ?<br />
And I guess the French link also, Thanks in advance. :) [[User:German Valero|German Valero]] ([[User talk:German Valero|talk]])<br />
<br />
Hi,<br />
Yes, please do it so. I was about to ask the same (or opposite ?) thing ;-) --[[User:Séverin Terrier|Séverin Terrier]] ([[User talk:Séverin Terrier|talk]]) 14:06, 3 November 2017 (UTC)</div>Foxhttps://docs.moodle.org/39/en/index.php?title=User:S%C3%A9verin_Terrier&diff=128871User:Séverin Terrier2017-09-22T08:59:14Z<p>Fox: https link</p>
<hr />
<div>Working in [http://www.ut-capitole.fr Université Toulouse 1 Capitole], i'm administrator of several Moodle sites.<br />
<br />
In Moodle community, i :<br />
* assist [[User:Nicolas Martignoni|Nicolas Martignoni]] for [https://moodle.org/course/view.php?id=20 Moodle en français].<br />
* try to improve the [[:fr:|french Moodle documentation]]<br />
<br />
[[fr:Utilisateur:Séverin Terrier]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=Boost_Campus_theme&diff=128859Boost Campus theme2017-09-19T09:41:38Z<p>Fox: RTL as title</p>
<hr />
<div>{{Themes}}<br />
{{Infobox plugin<br />
|type = Theme <br />
|entry = https://moodle.org/plugins/theme_boost_campus<br />
|tracker = https://github.com/moodleuulm/moodle-theme_boost_campus/issues<br />
|discussion = https://github.com/moodleuulm/moodle-theme_boost_campus<br />
|maintainer = [[User:Ulm University|Ulm University]]<br />
|float = right<br />
}}<br />
<br />
{{Note|You can find the most up-to-date English documentation for this plugin in the Ulm University's Github address at https://github.com/moodleuulm/moodle-theme_boost_campus/.}}<br />
<br />
<br />
==Description==<br />
Moodle Boost child theme which is intended to meet the needs of university campuses and adds several features and improvements<br />
<br />
==Images==<br />
<br />
[[File:Boost Campus screen 1 .png]]<br />
<br />
[[File:Boost Campus screen 2 .png]]<br />
<br />
[[File:Boost Campus screen 3.png]]<br />
<br />
[[File:Boost Campus screen 4.png]]<br />
<br />
<br />
==Requirements==<br />
This plugin requires Moodle 3.2+<br />
<br />
==Motivation for this theme==<br />
Moodle installations on university campuses have certain constraints which are not completely covered by the Boost theme in Moodle core. We implemented this Boost child theme to accommodate these needs as much as possible while keeping the functionality from Boost from Moodle core as much as possible as well.<br />
<br />
==Installation==<br />
Install the plugin like any other theme to folder /theme/boost_campus<br />
<br />
See [[Installing plugins]] for details on installing Moodle plugins<br />
<br />
==Usage & Settings==<br />
<br />
After installing the theme, it does not do anything to Moodle yet.<br />
<br />
To configure the theme and its behaviour, please visit: Site administration ►Appearance ►Themes ►Boost Campus.<br />
<br />
There, you find multiple settings tabs:<br />
==1. Tab "General Settings"==<br />
<br />
In this tab there are the following settings:<br />
===Theme presets===<br />
Theme preset<br />
<br />
This setting is already available in the Moodle core theme Boost. For more information how to use it, please have a look at the official Moodle documentation: [[Boost theme]]<br />
<br />
===Additional theme preset files===<br />
<br />
This setting is already available in the Moodle core theme Boost. For more information how to use it, please have a look at the official Moodle documentation: [[Boost theme]]<br />
<br />
===Brand colors===<br />
Brand color<br />
<br />
This setting is already available in the Moodle core theme Boost. For more information how to use it, please have a look at the official Moodle documentation: [[Boost theme]]<br />
<br />
===Brand success color===<br />
<br />
This color is used for example in regards to form valiations.<br />
<br />
===Brand info color===<br />
<br />
This color is used for example for availabiity information of course activities or resources.<br />
Brand warning color<br />
<br />
This color is used for example for warning texts.<br />
<br />
===Brand danger color===<br />
<br />
This color is used for example in regards to form valiations.<br />
<br />
===Favicon===<br />
<br />
This setting allows you to upload an image (.ico or .png format) that your browser will display as a favicon.<br />
<br />
==2. Tab "Advanced Settings"==<br />
<br />
In this tab there are the following settings:<br />
<br />
===Raw initial SCSS===<br />
<br />
This setting is already available in the Moodle core theme Boost. For more information how to use it, please have a look at the official Moodle documentation: [[Boost theme]]<br />
<br />
===Raw SCSS===<br />
<br />
This setting is already available in the Moodle core theme Boost. For more information how to use it, please have a look at the official Moodle documentation: [[Boost theme]]<br />
<br />
===Catch keyboard commands===<br />
<br />
The following settings are intended to serve the needs for advanced users, especially if your Moodle instance has a large footer. Advanced users are likely to use keyboard shortcuts to navigate through the sites. They may use this for reaching the end of the page in the intention to get fast to the most recent topic in the course (for adding content or grading latest activities). If the footer is not quite small, they would need to scroll up again. With these settings you can enable that the following shortcuts are caught and would only scroll to the bottom of the main course content.<br />
<br />
===End key===<br />
<br />
This setting will catch the "End" key (should work on all main browsers and operating systems), prevent the default scrolling to the bottom of the web page and changes the behavior to scroll only to the bottom of the main course content.<br />
<br />
===Cmd + Arrow down shortcut===<br />
<br />
This setting will catch the "Cmd + Arrow down" shortcut (MAC), prevent the default scrolling to the bottom of the web page and changes the behavior to scroll only to the bottom of the main course content.<br />
<br />
===Ctrl + Arrow down shortcut===<br />
<br />
This setting will catch the "Ctrl + Arrow down" shortcut (Windows), prevent the default scrolling to the bottom of the web page and changes the behavior to scroll only to the bottom of the main course content.<br />
<br />
==3. Tab "Course Layout Settings"==<br />
===Section 0: Title===<br />
<br />
This setting can change the behaviour Moodle displays the title for the first course section. Moodle does not display it as long as the default title for this section is set. As soon as a user changes the title, it will appear. With this setting (option is checked), you can achieve a consistent behaviour by always showing the title for section 0.<br />
<br />
===Course edit button===<br />
<br />
With this setting you can add an additional course edit on / off button to the course header for faster accessibility. This the same way as it was displayed before theme_boost.<br />
<br />
===Position of switch role information===<br />
<br />
With this setting you can choose the place where the information to which role a user has switched is being displayed. If not checked (default value), the role information will be displayed right beneath the user's name in the user menu (like in theme Boost). If checked, this information - together with a link to switch back - will be displayed beneath the course, as this functionality is course related.<br />
<br />
===Course settings===<br />
In course settings menu<br />
<br />
With this setting you can change the displaying of the course context menu. In Boost, there is a popup context menu right next to the cog icon and clicking on the "More..." menu item will lead the user to another page with all course settings. By enabling this setting the settings will occur directly beneath the course header. Please note that this change does not affect users who have switched off javascript in their browsers - they will still get the behaviour from Moodle core with a popup course context menu.<br />
<br />
===Move "Switch role to..." to the course settings===<br />
<br />
With this setting you can move the "Switch role to..." link as a new tab from the user menu to the in-course course menu. The role switching is a feature which is used in course context and thus it is better to place it in the course settings menu than in the user menu. Please note that this setting won't have any effect if you do not activate the "In course settings menu" above.<br />
<br />
==4. Tab "Footer Layout Settings"==<br />
===Footer blocks===<br />
<br />
You can chose if you want to enable the possibility to place blocks into the footer. If enabled, you can choose between one, two or three block columns. These columns are only displayed on large screens. On small screens the columns will be automatically reduced to one column for better readability and layout.<br />
<br />
===Default footer links===<br />
<br />
Moodle provides some default links in the footer: Link to the Moodle docs, login information, and a link to the webpage start. With these three settings you can decide if you want to hide specific links because you think that your users won't need them in your instance. If checked, the link will not be displayed in the footer. If not checked (default), it will be shown.<br />
<br />
==5. Tab "Additional Layout Settings"==<br />
===Badgearea===<br />
Badge area items<br />
<br />
With this widget you can upload your images that will be displayed in the additional badge area region. The images will be sorted and displayed alphabetically by the filename. To remove this region, simply delete all uploaded images.<br />
===Badge area item links===<br />
<br />
With this optional setting you can add links to your uploaded images. Each line consists of the file identifier (the file name) the a link URL, separated by pipe characters. Each link declaration needs to be written in a new line. For example: moodle.jpg|http://moodle.org You can declare links for a abitrary amount of your uploaded images. The links will be added only to those badges that match their filename with the identifier declared in this setting.<br />
===Badge area items maximal height===<br />
<br />
With this setting you can change the height in pixels for your uploaded badges. All images will have the same maximum height and their width will be resized proportionally. The default value is set to 100 pixels.<br />
===Footnote===<br />
<br />
Whatever you add to this textarea will be displayed beneath the footer on every page that renders the theme standard footer (for layouts "columns2", "login" and "maintenance"). Content in this area could be for example the copyright, the terms of use and the name of your organisation.<br />
===Nav drawer menu===<br />
Default homepage on top<br />
<br />
By checking this setting the default homepage link (Dashboard or Site home) will always be located at the top of the nav drawer. By default, this is already the case on every Moodle page except for course pages. There, the current course and its contents are placed on top. This might break user's expectations for the placement of the default homepage link.<br />
<br />
==6. Tab "Design Settings"==<br />
===Login Page===<br />
Login page background images<br />
<br />
In this setting you can add up to 10 files as a background image for the login page. One of these images will be picked randomly and delivered when the user visits the login page.<br />
===Login form===<br />
<br />
With this setting you can optimize the login form to fit to a greater variety background images (if checked). This means that the login form will be moved to the left of the login page, will get smaller in width and will get a background that let the background image shine through. The login form will be placed on the left because many images have their main content rather in the center and so we keep this content visible. Note: You can also activate this setting if no background images are uploaded, of course.<br />
===Fonts===<br />
Font files<br />
<br />
With this dialogue you can upload own font files. The upload is resricted to the font files of type .eot, .woff, .woff2, .ttf and .svg.<br />
<br />
Important: To be able to use the uploaded fonts within this theme, you have to add related code to your "Raw SCSS" area in the tab "Advanced Settings"! First you have to add all font-faces correctly and then you can set the font as font-family to any tag. Set it for the body tag to use it all over the instance. With the following expamle you can see how the SCSS code should look like. Of course you have to adapt it for your individual font and the number and type of uploaded files.<br />
<br />
<code css> /* your-font-regular - latin */<br />
@font-face {<br />
font-family: "Your Font";<br />
font-style: normal;<br />
font-weight: 400;<br />
/* IE9 Compat Modes */<br />
src: url("/pluginfile.php/1/theme_boost_campus/fontfiles/0/your-font-latin-regular.eot");<br />
src: local("Your Font"), local("YourFont-Regular"),<br />
/* IE6-IE8 */<br />
url("/pluginfile.php/1/theme_boost_campus/fontfiles/0/your-font-latin-regular.eot?#iefix") format("embedded-opentype"),<br />
/* Super Modern Browsers */<br />
url("/pluginfile.php/1/theme_boost_campus/fontfiles/0/your-font-latin-regular.woff2") format("woff2"),<br />
/* Modern Browsers */<br />
url("/pluginfile.php/1/theme_boost_campus/fontfiles/0/your-font-latin-regular.woff") format("woff"),<br />
/* Safari, Android, iOS */<br />
url("/pluginfile.php/1/theme_boost_campus/fontfiles/0/your-font-latin-regular.ttf") format("truetype"),<br />
/* Legacy iOS */<br />
url("/pluginfile.php/1/theme_boost_campus/fontfiles/0/your-font-latin-regular.svg#YourFont") format("svg");<br />
\}<br />
/* your-font-italic - latin */<br />
@font-face {<br />
font-family: "Your Font";<br />
font-style: italic;<br />
font-weight: 400;<br />
src: url("/pluginfile.php/1/theme_boost_campus/fontfiles/0/your-font-latin-italic.eot");<br />
src: local("Your Font Italic"), local("YourFont-Italic"),<br />
url("/pluginfile.php/1/theme_boost_campus/fontfiles/0/your-font-latin-italic.eot?#iefix") format("embedded-opentype"),<br />
url("/pluginfile.php/1/theme_boost_campus/fontfiles/0/your-font-latin-italic.woff2") format("woff2"),<br />
url("/pluginfile.php/1/theme_boost_campus/fontfiles/0/your-font-latin-italic.woff") format("woff"),<br />
url("/pluginfile.php/1/theme_boost_campus/fontfiles/0/your-font-latin-italic.ttf") format("truetype"),<br />
url("/pluginfile.php/1/theme_boost_campus/fontfiles/0/your-font-latin-italic.svg#YourFont") format("svg");<br />
}<br />
/* your-font-700 - latin */<br />
@font-face {<br />
font-family: "Your Font";<br />
font-style: normal;<br />
font-weight: 700;<br />
src: url("/pluginfile.php/1/theme_boost_campus/fontfiles/0/your-font-latin-700.eot");<br />
src: local("Your Font Bold"), local("YourFont-Bold"),<br />
url("/pluginfile.php/1/theme_boost_campus/fontfiles/0/your-font-latin-700.eot?#iefix") format("embedded-opentype"),<br />
url("/pluginfile.php/1/theme_boost_campus/fontfiles/0/your-font-latin-700.woff2") format("woff2"),<br />
url("/pluginfile.php/1/theme_boost_campus/fontfiles/0/your-font-latin-700.woff") format("woff"),<br />
url("/pluginfile.php/1/theme_boost_campus/fontfiles/0/your-font-latin-700.ttf") format("truetype"),<br />
url("/pluginfile.php/1/theme_boost_campus/fontfiles/0/your-font-latin-700.svg#YourFont") format("svg");<br />
}<br />
/* your-font-700italic - latin */<br />
@font-face {<br />
font-family: "Your Font";<br />
font-style: italic;<br />
font-weight: 700;<br />
src: url("/pluginfile.php/1/theme_boost_campus/fontfiles/0/your-font-latin-700italic.eot");<br />
src: local("Your Font Bold Italic"), local("YourFont-BoldItalic"),<br />
url("/pluginfile.php/1/theme_boost_campus/fontfiles/0/your-font-latin-700-italic.eot?#iefix") format("embedded-opentype"),<br />
url("/pluginfile.php/1/theme_boost_campus/fontfiles/0/your-font-latin-700-italic.woff2") format("woff2"),<br />
url("/pluginfile.php/1/theme_boost_campus/fontfiles/0/your-font-latin-700-italic.woff") format("woff"),<br />
url("/pluginfile.php/1/theme_boost_campus/fontfiles/0/your-font-latin-700-italic.ttf") format("truetype"),<br />
url("/pluginfile.php/1/theme_boost_campus/fontfiles/0/your-font-latin-700-italic.svg#YourFont") format("svg");<br />
}<br />
<br />
body {<br />
font-family: "Your Font";<br />
}<br />
</code><br />
<br />
Please note: The code itself and the URLs have to fit exactly to your uploaded files, unless the fonts cannot be loaded! As the font files will be delivered with an expires header to the client but currently without a timestamp in the URL, emptying the Moodle cache unfortunately will not force a reload of the font files on the client side.<br />
===Blocks===<br />
Block icon<br />
<br />
With this setting you can add a default Font Awesome icon in front of the block title. If checked, we additionally provide individual icon replacements for many Moodle core blocks and also some widely used blocks. You also can change the icons easily for each block individually in your raw SCSS via the change of the Font Awesome content. For all available icons please visit http://fontawesome.io/icons/ and use the Unicode value of the icon to replace the default one. The code to change the icon looks like this example change for the block "People": .block_people .card-block .card-title::before { content: '\f0c0' ; }.<br />
===Navbar===<br />
Dark navbar<br />
<br />
By enabling this setting you can invert the default light navbar to a dark one with white links.<br />
==Further improvements to Boost core theme==<br />
<br />
Apart from the features which can be configured in the theme's settings, we have added some more improvements which are simply there without any settings:<br />
Font Awesome<br />
<br />
To be able to use icons provided by Font Awesome it is added to theme_boost_campus.<br />
===Flat navigation (nav-drawer) menu===<br />
<br />
We improved the code of the new flatnavigation nay-drawer menu items to be uniformly. Furthermore, we improved the layout of the menu by styling borders, icons and margins. Now a user can recognize faster what items belong together to a parent node.<br />
===Course settings icon===<br />
<br />
The course settings icon will now be displayed on all sites that renders the course header. This improves the accessibility to those settings as there is not a onmipresent block anymore.<br />
===Back to top button===<br />
<br />
We added a back to top button that appears in the right bottom corner when the user scrolls down the page. With a click on it the page scrolls back to top smoothly and the button will disappear again.<br />
<br />
==Design==<br />
<br />
* Added Font Awesome icons to mailto and broken links. Furthermore, colored broken link in red for fast recognizability.<br />
<br />
===Course Design:===<br />
<br />
* Used the brand color as border color.<br />
* Improved highlighting of a highlighted section.<br />
* Improved recognisability of hidden activities by gray scaling the icon.<br />
* Improved paddings and margins for better alignment and better delineation of sections.<br />
* Designed description and intro boxes.<br />
* Designed blockquotes.<br />
* Improved design of maintenance warning to be more visible.<br />
<br />
===Categories overview page===<br />
<br />
Improved font sizes and weights on category overview page for better readability.<br />
<br />
==How this theme works==<br />
<br />
This Boost child theme is implemented with minimal code duplication in mind. It inherits / requires as much code as possible from theme_boost and only implements the extended or modified functionalities.<br />
===Plugin repositories===<br />
<br />
This plugin is published and regularly updated in the Moodle plugins repository: http://moodle.org/plugins/view/theme_boost_campus<br />
<br />
The latest development version can be found on Github: https://github.com/moodleuulm/moodle-theme_boost_campus<br />
==Bug and problem reports / Support requests==<br />
<br />
This plugin is carefully developed and thoroughly tested, but bugs and problems can always appear.<br />
<br />
Please report bugs and problems on Github: https://github.com/moodleuulm/moodle-theme_boost_campus/issues<br />
<br />
We will do our best to solve your problems, but please note that due to limited resources we can't always provide per-case support.<br />
<br />
==Feature proposals==<br />
<br />
Due to limited resources, the functionality of this plugin is primarily implemented for our own local needs and published as-is to the community. We are aware that members of the community will have other needs and would love to see them solved by this plugin.<br />
<br />
Please issue feature proposals on Github: https://github.com/moodleuulm/moodle-theme_boost_campus/issues<br />
<br />
Please create pull requests on Github: https://github.com/moodleuulm/moodle-theme_boost_campus/pulls<br />
<br />
We are always interested to read about your feature proposals or even get a pull request from you, but please accept that we can handle your issues only as feature proposals and not as feature requests.<br />
<br />
==Moodle release support==<br />
<br />
Due to limited resources, this plugin is only maintained for the most recent major release of Moodle. However, previous versions of this plugin which work in legacy major releases of Moodle are still available as-is without any further updates in the Moodle Plugins repository.<br />
<br />
There may be several weeks after a new major release of Moodle has been published until we can do a compatibility check and fix problems if necessary. If you encounter problems with a new major release of Moodle - or can confirm that this plugin still works with a new major relase - please let us know on Github.<br />
<br />
If you are running a legacy version of Moodle, but want or need to run the latest version of this plugin, you can get the latest version of the plugin, remove the line starting with $plugin->requires from version.php and use this latest plugin version then on your legacy Moodle. However, please note that you will run this setup completely at your own risk. We can't support this approach in any way and there is a undeniable risk for erratic behavior.<br />
<br />
==Translating this plugin==<br />
<br />
This Moodle plugin is shipped with an English language pack only. All translations into other languages must be managed through [https://lang.moodle.org AMOS] by what they will become part of Moodle's official language pack.<br />
<br />
As the plugin creator, we manage the translation into German for our own local needs on [https://lang.moodle.org AMOS]. Please contribute your translation into all other languages in [https://lang.moodle.org AMOS]where they will be reviewed by the official language pack maintainers for Moodle.<br />
<br />
==Right-to-left support==<br />
<br />
This plugin has not been tested with Moodle's support for right-to-left (RTL) languages. If you want to use this plugin with a RTL language and it doesn't work as-is, you are free to send us a pull request on Github with modifications.<br />
<br />
==PHP7 Support==<br />
<br />
Since Moodle 3.0, Moodle core basically supports PHP7. Please note that PHP7 support is on our roadmap for this plugin, but it has not yet been thoroughly tested for PHP7 support and we are still running it in production on PHP5. If you encounter any success or failure with this plugin and PHP7, please let us know.<br />
<br />
==Copyright==<br />
<br />
Ulm University kiz - Media Department Team Web & Teaching Support Kathrin Osswald<br />
<br />
<br />
[[es:Tema Boost Campus]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=error/moodle/dmlreadexception&diff=128182error/moodle/dmlreadexception2017-06-16T13:09:07Z<p>Fox: French link</p>
<hr />
<div>This message was displayed because Moodle experienced a problem trying to read data from your Moodle database. <br />
<br />
To get more information about the error you should enable [[Debugging]] in ''Settings > Site administration > Development > Debugging''.<br />
<br />
Setting this debugging mode will cause Moodle to display detailed information about the problem and a stack trace. You can then use this information and try searching moodle.org and the Moodle tracker to find any other reports of the problem with suggested solutions, or if necessary create a new issue for it in the Tracker. The Moodle developers will then use this information to reproduce and debug the problem.<br />
<br />
After you have reported the problem reset the debugging level to the original state so that your users do not see the debugging messages.<br />
<br />
==See also==<br />
<br />
* [[Development:DML exceptions]]<br />
<br />
[[Category:Error|Dmlreadexception]]<br />
<br />
[[es:error/moodle/dmlreadexception]]<br />
[[fr:error/moodle/dmlreadexception]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=error/moodle/invalidrecord&diff=128177error/moodle/invalidrecord2017-06-14T12:59:31Z<p>Fox: French link</p>
<hr />
<div>The message 'Can not find data record in database table' is displayed when a forum post or other data has been deleted.<br />
<br />
If you have recently upgraded and obtain the message, try running [[Cron]] repeatedly until you see the message "Running clean-up tasks..." near the top of the output. See the [https://moodle.org/mod/forum/discuss.php?d=199860 Can not find data record in database table context] discussion for further advice.<br />
<br />
[[Category:Error|Invalidrecord]]<br />
<br />
[[es:error/moodle/invalidrecord]]<br />
[[fr:error/moodle/invalidrecord]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=error/moodle/dmlwriteexception&diff=127167error/moodle/dmlwriteexception2017-03-21T14:07:44Z<p>Fox: French link</p>
<hr />
<div>This indicates that a general error occurred when Moodle tried to write to the database. If you turn on [[Debugging]] you will get more detailed information about what the problem is.<br />
<br />
==MySQL==<br />
<br />
If you're using a MySQL database for your Moodle installation, this error can be caused by the server's <code>max_allowed_packet</code> size being configured incorrectly. [https://moodle.org/mod/forum/discuss.php?d=230681#p1001751 Increasing this value may resolve the issue.]<br />
<br />
==dmlwriteexception error when restoring a course==<br />
<br />
If you obtain a dmlwriteexception error when restoring a course, it is recommended that InnoDB tables are converted to the Barracuda file format. See the section 'Converting InnoDB tables to Barracuda' in [[Administration via command line]] for details of why this is recommended plus information on a tool for converting tables.<br />
<br />
==See also==<br />
<br />
* [[Development:DML exceptions]]<br />
<br />
[[Category:Error|Dmlwriteexception]]<br />
<br />
[[es:error/moodle/dmlwriteexception]]<br />
[[fr:error/moodle/dmlwriteexception]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=Managing_tags&diff=127128Managing tags2017-03-15T10:57:35Z<p>Fox: French link</p>
<hr />
<div>{{Tags}}Tags can be managed by a site administrator or manager (or any other user with the capability [[Capabilities/moodle/tag:manage|moodle/tag:manage]]) in ''Site administration > Appearance > Manage tags''.<br />
<br />
==Tag collections==<br />
<br />
Tag collections are a way to separate out tags by the type of objects the tags are attached to, or sets of tags for different areas. <br />
<br />
For example, a collection of standard tags can be used to tag courses, with user interests and blog post tags kept in a separate collection. When a user clicks on a tag, the tag page displays only items with that tag in the same collection including the same types of objects.<br />
<br />
Tags can be automatically added to a collection according to the area tagged or can be added manually as standard tags.<br />
<br />
Clicking on the name of a tag collection then displays the list of tags, together with information on their creators, how many times they are used, when they were last modified, which tags have been flagged as inappropriate and which tags are marked as standard. <br />
<br />
[[File:managestandardtags.png|thumb|center|600px|Accessing and managing tags]]<br />
<br />
Standard tags are tags which are added by a site administrator and are available for others to use. Standard tags are never deleted during clean-up tasks even when there are no tagged items.<br />
<br />
===Adding a new collection===<br />
<br />
A new collection may be added by clicking the 'Add tag collection' link and giving the new collection a name:<br />
<br />
[[File:Tagcollections.png|thumb|center|600px|A new tag collection]]<br />
<br />
Tag areas may then be selected for this collection, by clicking the pencil icon of a particular tag area in the Tag collection column, and changing it from 'Default collection' to the chosen, new collection:<br />
<br />
[[File:tagareaselect.png|center]]<br />
<br />
==Tag areas==<br />
<br />
Areas in which tags may be used, such as for activities and resources, and user interests, may be enabled or disabled as required. <br />
<br />
For example, if you don't intend to use course tags on your site, the courses tag area can be disabled so that the Tags section doesn't appear on the edit settings page for each course. If you have turned off Blogs at the system level, then you would usually turn off blog tagging too.<br />
<br />
==Managing a tag collection==<br />
<br />
*Tags which are flagged as inappropriate are indicated in red (colour may vary with non-standard theme).<br />
*Tags may be renamed (inline, by clicking on the pencil icon next to them), marked as standard or reset. Tags may also be deleted individually or in bulk.<br />
*Tags may be filtered by adding a term to the search box:<br />
<br />
[[File:tagsfiltering.png|thumb|600px|center|Tag search results]]<br />
<br />
===Combining tags===<br />
<br />
Tags with similar names may be combined by an administrator or manager by selecting them and then, from the bottom of the screen, clicking the 'Combine selected tags' button. A pop up will appear asking which name you want to keep, and clicking 'Continue' will then combine the tags:<br />
<br />
[[File:combinetags.png]]<br />
<br />
[[cs:tag/manage]]<br />
[[es:Gestión de marcas (tags)]]<br />
[[eu:Etiketak kudeatu]]<br />
[[fr:Gérer les tags]]<br />
[[de:Schlagwörter verwalten]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=MySQL_full_unicode_support&diff=127104MySQL full unicode support2017-03-10T15:25:28Z<p>Fox: French link</p>
<hr />
<div>{{Environment}}<br />
==UTF-8==<br />
<br />
UTF-8 is a character encoding that most websites use. It encodes each of the 1,112,064 valid code points. To store all of this information, four bytes is required. The most popular values are in the three byte region. MySQL by default only uses a three byte encoding and so values in the four byte range can not be stored. Any record that contains a four byte character will not be saved.<br />
<br />
MySQL does support full UTF-8 support. It requires certain settings to be configured. From Moodle 3.3 the default will be to use full UTF-8 for MySQL and MariaDB. Existing databases will still run with partial support, but it is recommended to move over to full support.<br />
<br />
Moodle comes with a Command Line Interface (CLI) script for converting to full UTF-8 for MySQL (and MariaDB). Before Moodle 3.3 this conversion tool would only change the collation to some variant of 'utf8_bin'. 'utf8_unicode_ci' was the recommended collation. We now recommend 'utf8mb4_unicode_ci'. 'utf8mb4_unicode_ci' supports 4 byte characters (utf8_unicode_ci only supports 3 byte characters) so four byte characters such as Asian characters and emoji should now be fully supported.<br />
<br />
This script will attempt to change the database collation, character set, and default table settings.<br />
<br />
To summarise:<br />
<br />
* Fresh installs of Moodle 3.1.5 and 3.2.2 onwards will use utf8mb4 by default.<br />
* Sites upgrading to Moodle 3.1.5 or 3.2.2 can use the script to update to utf8mb4. In Moodle 3.3 a warning will show that the database isn't using full UTF-8 support and suggest moving to utf8mb4, but you may choose to keep using utf8.<br />
<br />
===File format===<br />
<br />
To allow for large indexes on columns that are a varchar, a combination of settings needs to be set. The file format for the system needs to be using "Barracuda". This allows for the row format to be set to "Compressed" or "Dynamic". To enable this setting see the upgrade steps listed below.<br />
<br />
===File per table===<br />
<br />
To enable this setting see the upgrade steps listed below.<br />
<br />
===Large prefix===<br />
<br />
This in conjunction with the row format being either "Compressed" or "Dynamic" allows for large varchar indexes above 191 characters.<br />
To enable this setting see the upgrade steps listed below.<br />
<br />
==Steps to upgrade==<br />
<br />
Most important: Please backup your database before making any changes or running the CLI script.<br />
<br />
* Change configuration settings for MySQL (exactly the same for MariaDB). This step is optional. You can run the script and it will try and make these changes itself. If errors occur then try manually changing these settings as listed below.<br />
** On Linux based systems you will want to alter my.cnf. This may be located in '/etc/mysql/'.<br />
** Make the following alterations to my.cnf:<br />
<code><br />
[client]<br />
default-character-set = utf8mb4<br />
<br />
[mysqld]<br />
innodb_file_format = Barracuda<br />
innodb_file_per_table = 1<br />
innodb_large_prefix<br />
<br />
character-set-client-handshake = FALSE<br />
character-set-server = utf8mb4<br />
collation-server = utf8mb4_unicode_ci<br />
<br />
[mysql]<br />
default-character-set = utf8mb4<br />
</code><br />
* Restart your mysql server.<br />
* Run the CLI script to convert to the new character set and collation (requires Moodle 3.1.5, 3.2.2 or newer): '''php admin/cli/mysql_collation.php --collation=utf8mb4_unicode_ci'''<br />
<br />
The upgrade is now complete.<br />
<br />
[[Category:Environment|UTF-8]]<br />
[[Category:UTF-8]]<br />
<br />
<br />
[[es:MySQL soporte unicode completo]]<br />
[[fr:Support unicode complet pour MySQL]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=Custom_SQL_queries_report&diff=127045Custom SQL queries report2017-03-08T11:29:06Z<p>Fox: /* See also */</p>
<hr />
<div>{{Sitewide reports}}<br />
Created by The Open University<br />
<br />
This admin report plugin allows Administrators to set up arbitrary database queries to act as ad-hoc reports. Reports can be of two types: either run on demand, or scheduled to run automatically. Other users with the right capability can go in and see a list of queries that they have access to. Results can be viewed on-screen or downloaded as CSV.<br />
<br />
==Installing this report==<br />
<br />
Follow the generic [[Installing plugins]] documentation.<br />
<br />
==Screen shots==<br />
<br />
Here are two example screen shots, showing the two main screens.<br />
<br />
[[Image:Custom_report_list.png|thumb|none|600px|The list of available reports]]<br />
[[Image:Custom_report.png|thumb|none|600px|The results of running one of the reports]]<br />
<br />
(Note, these screen shots are in the OU theme, not the standard Moodle theme, and iCMA is OU-jargon for quiz.)<br />
<br />
==Interface for normal users==<br />
<br />
===List of available queries===<br />
<br />
Users with the report/customsql:view capability can access the list of reports in the admin block. Each query is accessible only to a certain people. There are three levels of access:<br />
* Available to any one who can access the report at all (those with report/customsql:view).<br />
* Available to people who are able to see other system reports (those with moodle/site:viewreports)<br />
* Available to administrators only (those with moodle/site:config)<br />
<br />
When you go to the list, it will only show the queries you have access to. There is a note beside each query saying when it was last run, and how long it took to generate.<br />
<br />
The list shows on-demand and scheduled queries separately.<br />
<br />
===Running an on-demand query===<br />
<br />
To run an on-demand query, click on its name in the list of queries.<br />
<br />
The query will be run, and the results will be displayed as a table. Any URLs in the table will automatically be made into hyperlinks.<br />
<br />
A description of the query may appear above the table.<br />
<br />
The summary of when the query was run and how long it took is shown at the bottom, along with a link to download the CSV file (for example to get the data into Excel) and a link back to the list of all available queries.<br />
<br />
===Viewing the results of scheduled queries===<br />
<br />
Scheduled queries can work in one of two ways. Either each run of the report generates and entire table of reasults, or each run just creates one line of results, and the report builds up a row at a time.<br />
<br />
When you click the name in the list of queries, you get taken to a display of the latest results, just like in the on-demand case.<br />
<br />
However, if each scheduled run generates a complete report, then at the bottom of a page there will be a list of all the previous runs of the report, so that you can go and see how the report changed over time.<br />
<br />
==Interface for administrators==<br />
<br />
Administrators (that is, users with report/customsql:definequeries) see everything that other users see, but with some additions.<br />
<br />
===Additional controls in the staff interface===<br />
<br />
Administrators get shown who each report in the list is available to.<br />
<br />
They also get an edit and a delete icon next to each query.<br />
<br />
There is an '''Add new query button''' at the end of the list of queries.<br />
<br />
When viewing a particular query, Administrators get an edit and a delete link underneath the table of results.<br />
<br />
===Adding or editing a query===<br />
<br />
When you click the '''Add new query button''', you get taken to an editing form that lets you define the query.<br />
<br />
You must give the query a name.<br />
<br />
You can optionally enter a description that is displayed above the results table. You should use this to explain what the results of the query mean.<br />
<br />
You must enter the SQL to generate the results you want displayed. This must be an SQL select statement. You must use the prefix prefix_ for table names. It should not be possible to enter any SQL that would alter the contents of the database.<br />
<br />
You choose who you want the query to be accessible to.<br />
<br />
You choose whether the query should be run on-demand or scheduled weekly or monthly. If the report is scheduled, you can say whether the each run returns one row to be added to a single table, or whether each run generates a separate table.<br />
<br />
When you save the new query, the SQL is checked to make sure that it will execute without errors. If you have said that the report will only return a single row, this is also checked.<br />
After saving the query, if this was a manual query, you are taken to the query results page, so you can see what the results look like. If it was an automatic query or if you cancel the form, you are taken to the list of available queries.<br />
<br />
Editing an existing query uses the same form as for adding a new query, but to change the properties of an existing query.<br />
<br />
Note that at the OU, weeks start on Saturday. If you don't like that, there is a fairly obvious constant to hack at the top of locallib.php.<br />
<br />
===Deleting a query===<br />
<br />
When you click the delete icon or link for a query, you are taken to a confirmation page that shows you SQL of the query you are about to delete. The query is only deleted if you click Yes on the confirmation page.<br />
<br />
After deleting a query, you are taken back to the list of queries.<br />
<br />
==Share your interesting queries here==<br />
<br />
If you come up with any interesting SQL to custom reports, you can share it here.<br />
<br />
===Quiz attempts in the last week/month===<br />
<br />
Set this up as a scheduled report:<br />
<br />
<code sql><br />
SELECT COUNT(*)<br />
FROM prefix_quiz_attempts<br />
WHERE timefinish > %%STARTTIME%%<br />
AND timefinish <= %%ENDTIME%%<br />
AND preview = 0<br />
</code><br />
<br />
This '''must''' be set up as a '''Scheduled, on the first day of each week''' or '''Scheduled, on the first day of each month''' report, or it will not work.<br />
<br />
===Usage summary===<br />
<br />
This report shows roughly the same usage statistics that are sent to moodle.org when you register your site. The ones that are aggregated at http://moodle.org/stats/. (The only difference is that the registration form does not do AND confirmed = 1 for some reason.<br />
<br />
<code sql><br />
SELECT<br />
(SELECT COUNT(id) FROM prefix_course) - 1 AS courses,<br />
(SELECT COUNT(id) FROM prefix_user WHERE deleted = 0 AND confirmed = 1) AS users,<br />
(SELECT COUNT(DISTINCT ra.userid)<br />
FROM prefix_role_capabilities rc<br />
JOIN prefix_role_assignments ra ON ra.roleid = rc.roleid<br />
WHERE rc.capability IN ('moodle/course:upd' || 'ate', 'moodle/site:doanything')) AS teachers,<br />
(SELECT COUNT(id) FROM prefix_role_assignments) AS enrolments,<br />
(SELECT COUNT(id) FROM prefix_forum_posts) AS forum_posts,<br />
(SELECT COUNT(id) FROM prefix_resource) AS resources,<br />
(SELECT COUNT(id) FROM prefix_question) AS questions<br />
</code><br />
<br />
There are two interesting queries in this blog post [http://tjhunt.blogspot.com/2010/03/when-do-students-submit-their-online.html When do students submit their online tests?].<br />
<br />
===Monthly Usage by Role===<br />
<br />
This report shows a distinct count of users by their role, accessing your site. Each instance of user and role is counted once per month, no matter how many courses they access. We use this to show the total number of students and teachers accessing our site.<br />
<br />
<code sql><br />
SELECT <br />
month(from_unixtime(`prefix_stats_user_monthly`.`timeend`)) AS calendar_month,<br />
year(from_unixtime(`prefix_stats_user_monthly`.`timeend`)) AS calendar_year,<br />
prefix_role.name as user_role,<br />
COUNT(DISTINCT prefix_stats_user_monthly.userid) AS total_users<br />
FROM<br />
prefix_stats_user_monthly<br />
Inner Join prefix_role_assignments ON prefix_stats_user_monthly.userid = prefix_role_assignments.userid<br />
Inner Join prefix_context ON prefix_role_assignments.contextid = prefix_context.id<br />
Inner Join prefix_role ON prefix_role_assignments.roleid = prefix_role.id<br />
WHERE prefix_context.contextlevel = 50<br />
AND `prefix_stats_user_monthly`.`stattype` = 'activity'<br />
AND prefix_stats_user_monthly.courseid <>1<br />
GROUP BY month(from_unixtime(`prefix_stats_user_monthly`.`timeend`)),<br />
year(from_unixtime(`prefix_stats_user_monthly`.`timeend`)),<br />
prefix_stats_user_monthly.stattype,<br />
prefix_role.name<br />
ORDER BY <br />
year(from_unixtime(`prefix_stats_user_monthly`.`timeend`)), month(from_unixtime(`prefix_stats_user_monthly`.`timeend`)),<br />
prefix_role.name<br />
</code><br />
<br />
You must have Statistics turned on to be able to generate any data with this report.<br />
<br />
PostgreSQL version of the Monthly Usage by Role query:<br />
<br />
<code sql><br />
SELECT <br />
extract(month from to_timestamp(prefix_stats_user_monthly.timeend)) AS calendar_month,<br />
extract(year from to_timestamp(prefix_stats_user_monthly.timeend)) AS calendar_year,<br />
prefix_role.name AS user_role,<br />
COUNT(DISTINCT prefix_stats_user_monthly.userid) AS total_users<br />
FROM<br />
prefix_stats_user_monthly<br />
INNER JOIN prefix_role_assignments ON prefix_stats_user_monthly.userid = prefix_role_assignments.userid<br />
INNER JOIN prefix_context ON prefix_role_assignments.contextid = prefix_context.id<br />
INNER JOIN prefix_role ON prefix_role_assignments.roleid = prefix_role.id<br />
WHERE prefix_context.contextlevel = 50<br />
AND prefix_stats_user_monthly.stattype = 'activity'<br />
AND prefix_stats_user_monthly.courseid <>1<br />
GROUP BY extract(month from to_timestamp(prefix_stats_user_monthly.timeend)),<br />
extract(year from to_timestamp(prefix_stats_user_monthly.timeend)),<br />
prefix_stats_user_monthly.stattype,<br />
prefix_role.name<br />
ORDER BY <br />
extract(year from to_timestamp(prefix_stats_user_monthly.timeend)), extract(month from to_timestamp(prefix_stats_user_monthly.timeend)),<br />
prefix_role.name<br />
</code><br />
<br />
===Show all Quiz results across a site===<br />
I'm sure someone will be able to improve upon this, but this is a query that will show Quiz results across a site. --[[User:Stuart Mealor|Stuart Mealor]] 22:07, 9 April 2010 (UTC)<br />
<br />
<code sql><br />
SELECT <br />
prefix_grade_items.itemname,<br />
prefix_grade_items.grademax,<br />
ROUND(prefix_grade_grades.finalgrade, 0) AS finalgrade,<br />
prefix_user.firstname,<br />
prefix_user.lastname,<br />
prefix_user.username<br />
FROM<br />
prefix_grade_grades<br />
INNER JOIN prefix_user ON prefix_grade_grades.userid = prefix_user.id<br />
INNER JOIN prefix_grade_items ON prefix_grade_grades.itemid = prefix_grade_items.id<br />
WHERE (prefix_grade_items.itemname IS NOT NULL)<br />
AND (prefix_grade_items.itemtype = 'mod' OR prefix_grade_items.itemtype = 'manual')<br />
AND (prefix_grade_items.itemmodule = 'quiz' OR prefix_grade_items.itemmodule IS NULL)<br />
AND (prefix_grade_grades.timemodified IS NOT NULL)<br />
AND (prefix_grade_grades.finalgrade > 0)<br />
AND (prefix_user.deleted = 0)<br />
</code><br />
<br />
==See also==<br />
<br />
* [http://moodle.org/mod/forum/discuss.php?d=136484 Custom SQL queries report] forum announcement<br />
* list of [[ad-hoc contributed reports]]<br />
* [http://moodle.org/mod/forum/discuss.php?d=153059 Forum post] with some more useful queries.<br />
* [http://moodle.org/mod/data/view.php?d=13&rid=2884 Modules and plugins database entry]<br />
* [[Configurable_reports|Configurable reports]] bloc<br />
<br />
[[Category:Contributed_code]]<br />
<br />
[[es:Reportes de consultas personalizadas SQL]]<br />
[[fr:admin/report/customsql/index]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=Configurable_reports&diff=127044Configurable reports2017-03-08T11:27:50Z<p>Fox: Add categories</p>
<hr />
<div>{{Infobox plugin<br />
|type = Block<br />
|entry = https://moodle.org/plugins/view.php?plugin=block_configurable_reports<br />
|tracker = http://tracker.moodle.org/browse/CONTRIB/component/10753<br />
|discussion = https://moodle.org/mod/forum/view.php?id=7979<br />
|maintainer = [[User:Juan Leyva|Juan Leyva]]<br />
|float = right<br />
}}<br />
<br />
== Installation ==<br />
<br />
# Download the Configurable Reports installation file and unzip it to the '''\blocks''' directory in your Moodle folder.<br />
# Be sure that the final name of the directory is: configurable_reports, the full path in your Moodle installation will be blocks/configurable_reports<br />
# Login to Moodle as Administrator and click Notifications under Site Administration.<br />
<br />
<br />
For more information see [[Installing contributed modules or plugins]]<br />
<br />
== Overview ==<br />
<br />
This block is a Moodle custom reports builder. It its also connected to a [https://github.com/jleyva/moodle-configurable_reports_repository public repository of sample reports] (only plugin version 2.3 and above)<br />
<br />
It is designed in a modular way to allow developers to create new plugins in less than an hour.<br />
<br />
<br />
'''Who can create custom reports?'''<br />
<br />
Anyone with block, managereports or manageownreports permissions at SITE level or COURSE level.<br />
<br />
<br />
'''What type of reports can I create?'''<br />
<br />
- Courses reports, with information regarding courses.<br />
<br />
- Categories reports, with information regarding categories. A courses report can be embedded in this type of report.<br />
<br />
- Users reports, with information regarding users and their activity in a course.<br />
<br />
- Timeline reports, this is a special type of report that displays a timeline. A course or user report can be embedded in this timeline showing data depending on the start and end time of the current row.<br />
<br />
- Custom SQL Reports, custom SQL queries. This block can use the same SQL queries as [https://moodle.org/plugins/view.php?plugin=report_customsql Tim Hunt's Custom SQL queries] plugin.<br />
<br />
Note for developers: You can create your own type of reports.<br />
<br />
<br />
'''Who can view the reports?'''<br />
<br />
When you create a report you can select which users can view it.<br />
<br />
The reports are displayed in a block in the course or site frontpage.<br />
<br />
== Creating a report ==<br />
<br />
<br />
This is a very simple process. <br />
<br />
If you are going to create a report for a course, you have to add the block in the course and click in the "Manage reports" link.<br />
<br />
On the other hand, for site reports, add the block in the frontpage and click in the "Manage reports" link.<br />
<br />
You must enter a name, an optional description, and you have to choose the type of report, pagination and exports formats.<br />
<br />
Depending on the report choosen, there will be more or less tabs. These are the tabs for the courses and users report:<br />
<br />
'''Columns''': Here you can choose the differents columns of your report depending on the type of report. (Course Name, User firstname, etc..)<br />
<br />
'''Conditions''': Here you can define the conditions (i.e, only courses from this category, only users from Spain, etc.)<br />
<br />
'''Ordering''': Here you can choose how to order the report using fields and directions.<br />
<br />
'''Filters''': Here you can choose which filters will be displayed.<br />
<br />
'''Template''': You can modify the report's layout by creating a template.<br />
<br />
'''Permissions''': Here you can choose who can view a report.<br />
<br />
'''Calculations''': Here you can add calculations for columns, i.e: average of number of users enrolled in courses<br />
<br />
'''Plots''': Here you can add graphs to your report based on the report columns and values.<br />
<br />
'''View report''': Self explanatory<br />
<br />
== Tutorial ==<br />
<br />
=== Creating a users' report ===<br />
<br />
Requirements: ''Users from Spain, but not from Madrid, in this course. This report can be viewed only by users from Spain. A filter based on the user's city must be displayed. A pie plot showing the users' cities is required. A calculation table showing the total forum post views is required. The report must be ordered by users' lastname.''<br />
<br />
<br />
Let's see how easy it is!<br />
<br />
First of all, install the block.<br />
<br />
Go to the course where the report will be created.<br />
<br />
Add an instance of the Custom Reports block.<br />
<br />
Click on "Manage reports"<br />
<br />
Click on "Add report"<br />
<br />
Enter a name, a description and choose "Users report" as Type of Report<br />
<br />
The report will be saved and you will be redirected to the first Tab named "Columns".<br />
<br />
<br />
'''Adding Columns'''<br />
<br />
Here you can define the report table properties, width, align, cell padding, cell spacing, etc.<br />
<br />
Add a Column called "User profile field"<br />
<br />
Choose the field "firstname" and enter a name for the column in the text field. You can leave the rest of elements blank.<br />
<br />
Repeat the process above for the lastname and city fields.<br />
<br />
Add a Column called "User module actions".<br />
<br />
Choose a module from the list, in this example, a forum.<br />
<br />
<br />
'''Adding Conditions'''<br />
<br />
Click on the Conditions Tab.<br />
<br />
Add a Condition named "User field Condition".<br />
<br />
Choose the column "Country", the Operator "=", and enter the value "ES" (this is the international code for Spain as Moodle stores it).<br />
<br />
Add a Condition named "User field Condition".<br />
<br />
Choose the column "city", the Operator "<>", and enter the value "Madrid".<br />
<br />
Add a Condition named "Users in current report course".<br />
<br />
These are the main conditions of the reports. Note that at the bottom there is a text box called condition, with this text:<br />
<br />
"c2 and c1 and c3"<br />
<br />
Here you can define a logic condition, in this case, we don't need to edit this condition but you can create complex expressions like:<br />
<br />
(c1 and c2) or (c4 and c3)<br />
<br />
<br />
'''Adding Ordering'''<br />
<br />
Click on the Ordering Tab.<br />
<br />
Add a ordering named "User field ordering".<br />
<br />
Choose the column "Lastname" and the ordering "ASC" (Ascending).<br />
<br />
<br />
'''Adding Filters'''<br />
<br />
Click on the Filters Tab.<br />
<br />
Add a filter named "User field filter".<br />
<br />
Choose city.<br />
<br />
<br />
'''Adding Permissions'''<br />
<br />
Click on the Permissions Tab.<br />
<br />
Choose "User field Value".<br />
<br />
Choose the column "Country", and enter the value "ES".<br />
<br />
Here you can add more permissions and a logic condition to be achieved.<br />
<br />
<br />
'''Adding Calculations'''<br />
<br />
Click on the Calculations tab.<br />
<br />
Choose Sum.<br />
<br />
Choose the column "User module actions".<br />
<br />
<br />
'''Adding Plots'''<br />
<br />
Click on the Plots tab.<br />
<br />
Choose "Pie".<br />
<br />
Choose the colum "City" as Name and Value.<br />
<br />
<br />
Finally, add a few users in Moodle with the country Spain, and different cities, Madrid, Barcelona, Seville, etc. and test the report.<br />
<br />
You can download the report in different formats (ods and xls), remember to check these options in the report page.<br />
<br />
[[blocks/configurable_reports/#Users_report | See screenshot]]<br />
<br />
=== Creating a SQL Report ===<br />
<br />
You can find a lot of SQL Reports here: [[ad-hoc contributed reports]]<br />
<br />
Since this block supports Tim Hunt's CustomSQL Queries Reports, you can use any query.<br />
<br />
Remember to add a "Time filter" if you are going to use reports with time tokens.<br />
<br />
<br />
First of all, install the block.<br />
<br />
Go to the course where the report will be created.<br />
<br />
Add an instance of the Custom Reports block.<br />
<br />
Click on "Manage reports".<br />
<br />
Click on "Add report<br />
<br />
Enter a name, description, choose "SQL" as Type of Report<br />
<br />
The report will be saved and you redirect to the first Tab named "Custom SQL"<br />
<br />
Add this query (''Courses activity''):<br />
<br />
<code sql><br />
SELECT COUNT(l.id) hits, l.course courseId, c.fullname coursename<br />
FROM prefix_log l INNER JOIN prefix_course c ON l.course = c.id<br />
GROUP BY courseId<br />
ORDER BY hits DESC<br />
</code><br />
<br />
Go to Calculations Tab<br />
<br />
Add a Sum calculation, choose the hits column<br />
<br />
<br />
Go to Plot<br />
<br />
Add a Pie graph, choosing coursename as Name and hits as value<br />
<br />
So, here you have a report with a Graph and calculations based on a SQL Query.<br />
<br />
<br />
You can add a Course filter, it's very easy:<br />
<br />
Go to filters, choose Courses<br />
<br />
Edit the Custom SQL query:<br />
<br />
<code sql><br />
SELECT COUNT(l.id) hits, l.course courseId, c.fullname coursename<br />
FROM prefix_log l INNER JOIN prefix_course c ON l.course = c.id <br />
%%FILTER_COURSES:l.course%% <br />
GROUP BY courseId<br />
ORDER BY hits DESC<br />
</code><br />
<br />
Note that we are adding a token called: %%FILTER_COURSES:l.courseid%% <br />
<br />
Go to View report, and you will see a Courses Filter, choose a Course and click on Add, here you have a report filtered.<br />
<br />
<br />
You can also add a Starttime and endtime filter<br />
<br />
Go to filters, choose Start / End date filter<br />
<br />
Go to Custom SQL tab, this is the new query:<br />
<br />
<code sql><br />
SELECT COUNT(l.id) hits, l.course courseId, c.fullname coursename<br />
FROM prefix_log l INNER JOIN prefix_course c ON l.course = c.id <br />
%%FILTER_COURSES:l.course%% <br />
%%FILTER_STARTTIME:l.time:>%% %%FILTER_ENDTIME:l.time:<%% <br />
GROUP BY courseId<br />
ORDER BY hits DESC<br />
</code><br />
<br />
<br />
If you want to filter text (for example, lastname)<br />
<br />
Go to filters, choose Search Text filter<br />
<br />
Go to Custom SQL tab and type your query. Here is an example for querying the user table:<br />
<br />
<code sql><br />
SELECT u.firstname, u.lastname<br />
FROM prefix_user u<br />
WHERE 1=1<br />
%%FILTER_SEARCHTEXT:u.lastname:~%%<br />
ORDER BY u.lastname<br />
</code><br />
<br />
Replace WHERE 1=1 with your WHERE criteria. If you do not have any where criteria and do not specify WHERE 1=1, you will receive a SQL error.<br />
<br />
<br />
<br />
One more example (for filtering a group of courses by category)<br />
<code sql><br />
SELECT COUNT(l.id) hits, c.fullname as Course,c.id as CourseID<br />
,(SELECT Count( ra.userid ) AS Users FROM prefix_role_assignments AS ra<br />
JOIN prefix_context AS ctx ON ra.contextid = ctx.id<br />
WHERE ra.roleid = 5 AND ctx.instanceid = c.id) AS Students<br />
FROM prefix_log l INNER JOIN prefix_course c ON l.course = c.id<br />
%%FILTER_CATEGORIES:c.category%% <br />
GROUP BY l.course<br />
ORDER BY hits DESC<br />
</code><br />
Go to View report, now you can filter by time also<br />
<br />
'''SQL variables'''<br />
If you place this strings in your SQL queries, it will be replaced by the appropriate value (current course id, current user id, Moodle www root (url))<br />
<br />
* %%COURSEID%% <br />
* %%USERID%%<br />
* %%WWWROOT%%<br />
<br />
[[blocks/configurable_reports/#SQL_report | See screenshot]]<br />
<br />
=== Creating a timeline report ===<br />
<br />
''This report assumes that you have created at least one user or course report''<br />
<br />
Timeline reports are a special type of reports. A timeline report displays a timeline in which a course report or user report can be embedded.<br />
<br />
In this example we are going to create a report showing the user logins to the site during the last month (day per day).<br />
<br />
Create a User report (see tutorial above) with three columns (firstname, lastname and user statistics)<br />
<br />
Select the statistic (User logins)<br />
<br />
Create a Timeline report, in the Timeline tab you can select the dates or days of the report (in this case, the last 30 days) and the interval of time for every row.<br />
<br />
Add three "Other report column" columns, selecting all the previous user report columns.<br />
<br />
And that's all, you can create a new type of plot (line graph). This graph is suitable for data depending on time.<br />
<br />
== Advanced options ==<br />
<br />
=== Export and import of reports ===<br />
<br />
Embedded reports exporting is not working because the reports include references to another reports. A workaround is edit the imported report for changing the references in the "Other report field" column.<br />
<br />
Reports that uses the user module outline column can't be exported either<br />
<br />
=== Use the same report in different courses ===<br />
<br />
(Available only in Configurable Report version 2.3 and above)<br />
<br />
In order to use the same report in different courses you have to check the "Global report" option where creating a new report. This report will be then displayed in all the courses where the configurable report block is displayed and the block instance settings are set to "Display global reports".<br />
<br />
If you don't want to display global reports in a certain block instance you can always edit the instance settings for selecting "No" in the "Display global reports" block setting.<br />
<br />
Notice that these types of reports inherit the context of the course where is displayed, so any condition related to course inside the report is calculated using the course where the report is being viewed<br />
<br />
=== Reports can run on a different DB then the current (production) DB ===<br />
<br />
(Available only in Configurable Report version 2.3 and above)<br />
<br />
Go to Admin -> Plugins -> Blocks -> Configurable Report settings<br />
<br />
=== DataTables for the report table ===<br />
<br />
(Available only in Configurable Report version 2.3 and above)<br />
<br />
Go to Admin -> Plugins -> Blocks -> Configurable Report settings to enable this functionality<br />
<br />
=== CodeMirror.js for highlighting SQL query code ===<br />
<br />
(Available only in Configurable Report version 2.3 and above)<br />
<br />
Go to Admin -> Plugins -> Blocks -> Configurable Report settings to disable this functionality<br />
<br />
=== Using GITHUB as a repository to distribute and manage sharable SQL queries ===<br />
<br />
(Available only in Configurable Report version 2.3 and above)<br />
<br />
Go to Admin -> Plugins -> Blocks -> Configurable Report settings to point to your own repository<br />
<br />
=== Cron SQL queries ===<br />
<br />
(Available only in Configurable Report version 2.3 and above)<br />
<br />
=== Settings to control security of SQL Queries ===<br />
<br />
(Available only in Configurable Report version 2.3 and above)<br />
<br />
Go to Admin -> Plugins -> Blocks -> Configurable Report settings to change the security level<br />
<br />
=== Templates ===<br />
<br />
You can customize the report output using a template.<br />
<br />
Just enable the Template option in the same name tab.<br />
<br />
This is an example html code for displaying a list of users:<br />
<br />
Header:<br />
<br />
<code html4strict><br />
<p align="center"><b>##reportname##</b></p><br />
<table width="60%" align="center"><br />
<tr><br />
<td><br />
</code><br />
<br />
Record:<br />
<br />
<code html4strict><br />
<table width="100%"><br />
<tr><br />
<td><img src="http://yourmoodle.com/user/pix.php/[[id]]/f1.jpg"></td><br />
<td><h2>[[Firstname]] [[Lastname]]</h2><br />
City: [[City]]<br />
</td><br />
</tr><br />
</table><br />
<br><br />
</code><br />
<br />
Footer:<br />
<br />
<code html4strict><br />
</td><br />
<td valign="top"><br />
##graphs## <br />
<br /><br /><br />
##exportoptions##<br />
</td><br />
</table><br />
</code><br />
<br />
=== Embedded reports ===<br />
<br />
An embedded report consists in a report's set of columns that are embedded in another report.<br />
<br />
You can embed a user report into a course report, in this case, the resulting rows will be expanded duplicating each row for each user.<br />
<br />
{| class="wikitable"<br />
|-<br />
! Type of report<br />
! Reports that can be embedded<br />
|-<br />
| Courses<br />
| Users<br />
|-<br />
| Categories<br />
| Courses<br />
|-<br />
| Timeline<br />
| Users, courses<br />
|}<br />
<br />
Imagine you have a courses report, you can embed a user report, every row of the course report will be cloned for each user.<br />
<br />
To embed a report just add a "Other report" column, a list of your reports will be showed.<br />
<br />
Inside a course report you can embed a user report and the other way.<br />
<br />
==== Timeline reports ====<br />
<br />
Timeline reports are a special type of reports. A timeline report displays a timeline in which a courses report or users report can be embedded.<br />
<br />
Timeline reports should be used when your user or course report includes statistics (course stats or user stats columns). I.e: you can create a report showing the number of user logins to the site during a week or month.<br />
<br />
== Reports repository ==<br />
<br />
Configurable Reports is connected to two different repositories:<br />
<br />
* https://github.com/jleyva/moodle-configurable_reports_repository A repository of any type of reports (users, courses, sql, etc...)<br />
* https://github.com/jleyva/moodle-custom_sql_report_queries A repository of just SQL queries to be used in the SQL repor type<br />
<br />
You can use your custom repository following this instructions:<br />
<br />
* First, you need a github account (free)<br />
<br />
* Fork any of the previous repositorys, using the GITHUB fork tool<br />
<br />
* Using GIT, clone the repository to your computer in order to add your custom reports (some GIT knowledge is needed)<br />
<br />
* Go to Administration / Plugins / Blocks / Configurable reports and change the settings for pointing to your repository (github account + / + repository name<br />
<br />
* If you want to contribute to the official repository, use the Pull request Github feature (So I can easily add your reports)<br />
<br />
<br />
== Developers documentation ==<br />
<br />
It's very easy to create new report types, components and plugins.<br />
<br />
'''Report''': A report plugin is a folder located at /report. <br />
This folder contains a .class.php file with the child - class of the report_base.<br />
<br />
You only need to modify a few methods to add a new report type.<br />
Please, take a look at any of the current reports. The SQL report is an example of a non-typical report, <br />
meanwhile the users and courses reports are standard reports.<br />
<br />
The best way to create a report is to duplicate an existing one.<br />
<br />
<br />
'''Component''': A component is part of a report, a component may be used by more than one report.<br />
The main Component is the component Columns, that is used to add the columns of a report.<br />
<br />
Others components are filters, permissions, plot, calculations..<br />
<br />
The best way to create a component is to duplicate an existing one.<br />
<br />
<br />
'''Plugin''': A plugin is a component module. The component column has a few of plugins (coursefield, userfield, etc.)<br />
A plugin usually works for a unique report, but there are plugins that work for more than one report.<br />
The best way to create a plugin is to duplicate an existing one.<br />
<br />
== How to request a new feature ==<br />
<br />
* Go to the Plugin Tracker http://tracker.moodle.org/browse/CONTRIB/component/10753<br />
* Check in the open issues if your feature have been already requested http://tracker.moodle.org/secure/IssueNavigator.jspa?reset=true&jqlQuery=project+%3D+CONTRIB+AND+component+%3D+%22Block%3A+Configurable+report%22+AND+status+%3D+Open+ORDER+BY+priority+DESC&mode=hide<br />
* If not, create a New issue (Component: Non-core contributed modules Issue type: New feature) (You have to register yourself in the tracker)<br />
* Select the component Block: Configurable Reports and your Moodle version<br />
* Explain in the Description field your needs<br />
* If you have funding, you can contact me using the forum or the moodle internal messaging system, since I work for a Moodle Partner I can work on your request.<br />
* Vote and Watch the issue you have created<br />
<br />
== Credits ==<br />
<br />
Juan Leyva [http://moodle.org/user/view.php?id=49568&course=1 Moodle profile]<br />
<br />
[http://twitter.com/jleyvadelgado Follow me in Twitter]<br />
<br />
== Screenshots ==<br />
<br />
=== Users report ===<br />
[[Image:block_custom_reports_sample_user_report.png|600px]]<br />
<br />
<br />
=== SQL report ===<br />
[[Image:block_custom_reports_sample_sql_report.png|600px]]<br />
<br />
<br />
== See Also ==<br />
<br />
* CONTRIB-2386<br />
* [https://tracker.moodle.org/issues/?jql=project%20%3D%20CONTRIB%20AND%20component%20%3D%20%22Block%3A%20Configurable%20report%22 Block: Configurable reports] Tracker component<br />
* [http://moodle.org/plugins/view.php?plugin=block_configurable_reports Modules & Plugins] database entry<br />
* [http://moodle.org/mod/forum/discuss.php?d=159820 Help forum]<br />
* [[ad-hoc_contributed_reports|contributed reports]] (in plain SQL)<br />
* [https://github.com/jleyva/moodle-configurable_reports_repository Configurable Reports Repository on GitHub]<br />
* [https://www.youtube.com/watch?v=lF6CuY2Qiw0 Configurable Reports as a Learning Analytics Tool] - iMoot 2015 presentation by Elizabeth Dalton<br />
* [http://opensourceelearning.blogspot.co.za/2015/08/moodle-configurable-reports-plugin-all.html All Variables and Filters] - Lists the Variables and Filters you can use in a report<br />
<br />
[[Category:Report]]<br />
[[Category:Contributed_code]]<br />
<br />
[[es:blocks/configurable_reports/]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=Upgrading_FAQ&diff=126858Upgrading FAQ2017-02-15T13:51:45Z<p>Fox: French link</p>
<hr />
<div>{{Installing Moodle}}<br />
==How do I upgrade from 1.9.x to {{Version}}?==<br />
<br />
1.x -> 1.9.19+ -> 2.2.11 -> 2.7.18 -> {{Version}} <br />
<br />
(It is better to upgrade to latest current stable before going to next branch, the same for plugins; upgrading from early stable branches usually works but there is no guarantee.)<br />
<br />
Moodle 2.2.11 may be downloaded from https://download.moodle.org/stable22/.<br />
<br />
==How do I upgrade Moodle? Do I just overwrite the files?==<br />
<br />
Do NOT overwrite files, as it may cause strange errors. Read the [[Upgrading]] documentation before proceeding.<br />
<br />
==I obtain the message "Upgrade already running in this session, please wait!"==<br />
<br />
Most likely you refreshed the page before the completion message. If you are absolutely sure that there are no upgrade processes active (php and/or mysql), you can click on "!!!" and restart the upgrade.<br />
<br />
:''Note'': If you click on "'!!!" or try to restart the upgrade from another browser, there is a chance that your data in the database could be corrupted. If this happens, you will need to restore the database from sql dump and then restart the upgrade and wait - the process can take several hours on large sites.<br />
<br />
==Can I upgrade more than one version at a time?==<br />
<br />
You can only upgrade to Moodle {{Version}} from Moodle 2.7 or later.<br />
<br />
You can only upgrade to Moodle 2.7 from Moodle 2.2 or later.<br />
<br />
You can only upgrade to Moodle 2.2 from Moodle 1.9 or later.<br />
<br />
For information on upgrading from versions of Moodle prior to 1.9, see the section 'Upgrading more than one version' in the Moodle 2.2 documentation [https://docs.moodle.org/22/en/Upgrading Upgrading].<br />
<br />
==I have custom code in my site. How do I upgrade?==<br />
Please see this forum post on [https://moodle.org/mod/forum/discuss.php?d=263355#p1141326 upgrading with custom code] for some suggestions.<br />
<br />
==See also==<br />
<br />
* [[Installation FAQ]]<br />
<br />
[[Category:FAQ]]<br />
<br />
[[es:Actualización FAQ]]<br />
[[fr:FAQ de mise à jour]]<br />
[[ja:アップグレードFAQ]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=PayPal_enrolment&diff=126857PayPal enrolment2017-02-15T13:03:29Z<p>Fox: Language links at the bottom</p>
<hr />
<div>{{Enrolment}}<br />
The PayPal enrolment plugin allows users to pay for courses and then be automatically enrolled. <br />
<br />
==PayPal account creation==<br />
<br />
# Go to https://www.paypal.com and create a PayPal account. Not required but recommended for selling: Upgrade your account to "Premier" status and get "Verified".<br />
# Set the Encoding to UFT-8. In Paypal, go to ''Profile > Language Encoding'' (under the Selling Preferences column) and set your website's language (like select "Western European Languages (including English)" as it is the only English version). Then click on the "More Options" button and set the Encoding to "UTF-8", select "Yes" to use the same encoding for data sent from PayPal to you, and save.<br />
# Optionally setup IPN in PayPal to interact with Moodle. Log into PayPal, go to "Profile > Instant Payment Notifications (IPN)”, click "Turn On IPN", click the "Edit settings" and enter a URL that references your IPN file in your Moodle installation (for example: <nowiki>http://<domain name>/moodle/enrol/paypal/ipn.php</nowiki>).<br />
<br />
==Enabling PayPal enrolment==<br />
<br />
An administrator can enable PayPal file enrolment as follows:<br />
<br />
# ''Go to Site administration > Plugins > Enrolments > Manage enrol plugins'' and click the eye icon opposite PayPal. When enabled, it will no longer be greyed out. [[Manual enrolment]] must also be enabled, since the PayPal plugin requires it.<br />
# Click the settings link, configure as required (see details of settings below), then click the 'Save changes' button.<br />
<br />
* PayPal business email - This setting is case sensitive and must exactly match that in PayPal<br />
* Default role assignment - This means the role that a new user will automatically be given in a course when they purchase access. Usually this would be "student" unless you have a special reason for choosing another role. As for other default settings, it may be overridden in individual courses.<br />
<br />
Tip: If you wish to allow users to create their own accounts on your site then you need to set up [[Email-based_self-registration|Email based self registration]].<br />
<br />
==Course settings for PayPal==<br />
<br />
===Checking you have PayPal in your course===<br />
<br />
# In a course, go to ''Course administration > Users > Enrolment methods''<br />
# If you do not see PayPal, use the pull down menu "Add method" and select PayPal<br />
# Make sure PayPal has its "eye" opened: <br />
<br />
[[File:Paypalenrolmentmethod.png]]<br />
{{Note|Make sure you don't have [[Self enrolment]] enabled as this would allow users to access the course without paying. If you do need some users to self enrol for free, then add an [[Enrolment key]] in the self enrolment settings.}}<br />
===Setting a price for your course===<br />
<br />
# In ''Course Administration > Users > Enrolment methods'', click the edit/hand/pen icon to the right of the PayPal option. <br />
# Optional: Give a name to this enrolment method if you wish in "Custom Instance name"<br />
# Ensure that "Allow PayPal enrolments" is set to "yes"<br />
# In "Enrol cost", type in the cost of your course and in "Currency" choose your currency.<br />
# Usually you would leave the "Assign role" as "student" unless you have a very special reason for allowing your users to enrol as, say, editing teachers etc<br />
# Choose an enrolment period and/or start/end dates if desired.<br />
# Click the "Save changes" button.<br />
<br />
[[File:Paypalcoursesettings.png]]<br />
<br />
===What the new user sees===<br />
<br />
When a new user clicks on your course link, they will see a message inviting them to go to PayPal to purchase access to the course. In the list of courses, PayPal courses have a dollar sign icon next to them.<br />
{|<br />
| [[File:Paypaluserview.png|frame|left|Message inviting user to pay via PayPal]]<br />
| [[File:Paypalicon.png|frame|left|PayPal course listed with dollar sign icon]]<br />
|}<br />
<br />
==Changing the dollar symbol==<br />
[[File:PaypalGBP.png|frame|PayPal course listed with GBP sign icon]]<br />
The default currency symbol for PayPal is a dollar sign. If you are using GBP or Euros or another currency, you can change this by creating your own customised icon with your choice of currency. Make it 16x 16 pixels and call it ''icon.gif'' Upload your new icon via FTP to your ''moodle directory>enrol>paypal>pix''. Your icon.gif will override the dollar sign. Make sure you refresh your page to be sure of the changes.<br />
<br />
==PayPal capabilities==<br />
<br />
*[[Capabilities/enrol/paypal:config|Configure PayPal enrol instances]]<br />
*[[Capabilities/enrol/paypal:manage|Manage enrolled users]]<br />
*[[Capabilities/enrol/paypal:unenrol|Unenrol users from course]]<br />
*[[Capabilities/enrol/paypal:unenrolself|Unenrol self from the course]]<br />
<br />
== See also ==<br />
*[http://moodle.org/mod/forum/discuss.php?d=171745#p977221 Testing the PayPal plugin in the PayPal Sandbox]<br />
<br />
[[de:Paypal-Einschreibung]]<br />
[[es:Inscripción por Paypal]]<br />
[[fr:Inscription Paypal]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=PayPal_enrolment&diff=126856PayPal enrolment2017-02-15T13:01:59Z<p>Fox: French link</p>
<hr />
<div>{{Enrolment}}<br />
The PayPal enrolment plugin allows users to pay for courses and then be automatically enrolled. <br />
<br />
==PayPal account creation==<br />
<br />
# Go to https://www.paypal.com and create a PayPal account. Not required but recommended for selling: Upgrade your account to "Premier" status and get "Verified".<br />
# Set the Encoding to UFT-8. In Paypal, go to ''Profile > Language Encoding'' (under the Selling Preferences column) and set your website's language (like select "Western European Languages (including English)" as it is the only English version). Then click on the "More Options" button and set the Encoding to "UTF-8", select "Yes" to use the same encoding for data sent from PayPal to you, and save.<br />
# Optionally setup IPN in PayPal to interact with Moodle. Log into PayPal, go to "Profile > Instant Payment Notifications (IPN)”, click "Turn On IPN", click the "Edit settings" and enter a URL that references your IPN file in your Moodle installation (for example: <nowiki>http://<domain name>/moodle/enrol/paypal/ipn.php</nowiki>).<br />
<br />
==Enabling PayPal enrolment==<br />
<br />
An administrator can enable PayPal file enrolment as follows:<br />
<br />
# ''Go to Site administration > Plugins > Enrolments > Manage enrol plugins'' and click the eye icon opposite PayPal. When enabled, it will no longer be greyed out. [[Manual enrolment]] must also be enabled, since the PayPal plugin requires it.<br />
# Click the settings link, configure as required (see details of settings below), then click the 'Save changes' button.<br />
<br />
* PayPal business email - This setting is case sensitive and must exactly match that in PayPal<br />
* Default role assignment - This means the role that a new user will automatically be given in a course when they purchase access. Usually this would be "student" unless you have a special reason for choosing another role. As for other default settings, it may be overridden in individual courses.<br />
<br />
Tip: If you wish to allow users to create their own accounts on your site then you need to set up [[Email-based_self-registration|Email based self registration]].<br />
<br />
==Course settings for PayPal==<br />
<br />
===Checking you have PayPal in your course===<br />
<br />
# In a course, go to ''Course administration > Users > Enrolment methods''<br />
# If you do not see PayPal, use the pull down menu "Add method" and select PayPal<br />
# Make sure PayPal has its "eye" opened: <br />
<br />
[[File:Paypalenrolmentmethod.png]]<br />
{{Note|Make sure you don't have [[Self enrolment]] enabled as this would allow users to access the course without paying. If you do need some users to self enrol for free, then add an [[Enrolment key]] in the self enrolment settings.}}<br />
===Setting a price for your course===<br />
<br />
# In ''Course Administration > Users > Enrolment methods'', click the edit/hand/pen icon to the right of the PayPal option. <br />
# Optional: Give a name to this enrolment method if you wish in "Custom Instance name"<br />
# Ensure that "Allow PayPal enrolments" is set to "yes"<br />
# In "Enrol cost", type in the cost of your course and in "Currency" choose your currency.<br />
# Usually you would leave the "Assign role" as "student" unless you have a very special reason for allowing your users to enrol as, say, editing teachers etc<br />
# Choose an enrolment period and/or start/end dates if desired.<br />
# Click the "Save changes" button.<br />
<br />
[[File:Paypalcoursesettings.png]]<br />
<br />
===What the new user sees===<br />
<br />
When a new user clicks on your course link, they will see a message inviting them to go to PayPal to purchase access to the course. In the list of courses, PayPal courses have a dollar sign icon next to them.<br />
{|<br />
| [[File:Paypaluserview.png|frame|left|Message inviting user to pay via PayPal]]<br />
| [[File:Paypalicon.png|frame|left|PayPal course listed with dollar sign icon]]<br />
|}<br />
<br />
==Changing the dollar symbol==<br />
[[File:PaypalGBP.png|frame|PayPal course listed with GBP sign icon]]<br />
The default currency symbol for PayPal is a dollar sign. If you are using GBP or Euros or another currency, you can change this by creating your own customised icon with your choice of currency. Make it 16x 16 pixels and call it ''icon.gif'' Upload your new icon via FTP to your ''moodle directory>enrol>paypal>pix''. Your icon.gif will override the dollar sign. Make sure you refresh your page to be sure of the changes.<br />
<br />
==PayPal capabilities==<br />
<br />
*[[Capabilities/enrol/paypal:config|Configure PayPal enrol instances]]<br />
*[[Capabilities/enrol/paypal:manage|Manage enrolled users]]<br />
*[[Capabilities/enrol/paypal:unenrol|Unenrol users from course]]<br />
*[[Capabilities/enrol/paypal:unenrolself|Unenrol self from the course]]<br />
<br />
[[fr:Inscription Paypal]]<br />
[[de:Paypal-Einschreibung]]<br />
<br />
== See also ==<br />
*[http://moodle.org/mod/forum/discuss.php?d=171745#p977221 Testing the PayPal plugin in the PayPal Sandbox]<br />
<br />
[[es:Inscripción por Paypal]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=Category:MoodleDocs&diff=126855Category:MoodleDocs2017-02-15T10:10:06Z<p>Fox: French link</p>
<hr />
<div>An index of pages relating to Moodle documentation.<br />
<br />
[[fr:Catégorie:Documentation]]<br />
[[pt:Categoria:MoodleDocs]]<br />
[[es:Categoría:MoodleDocs]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=Documentation_philosophy&diff=126854Documentation philosophy2017-02-15T09:53:33Z<p>Fox: French link</p>
<hr />
<div>{{Help}}* Focus on '''Moodle Docs''' as the central Moodle knowledge-base<br />
* Transfer content from [http://moodle.org/course/view.php?id=5 Using Moodle] forum discussions (e.g. answers to how-to questions, ideas/suggestions of ways of using a particular feature) to Moodle Docs<br />
* Encourage newcomers to contribute to Moodle Docs<br />
:"New users are ideal for writing system-level documentation aimed at new users. They have the point of view and experience with the current software at the system level rather than at the library level. The most common evidence of this is FAQ lists, in which issues repeatedly raised on mailing lists and chat sessions are answered." Source: [http://www.oss-watch.ac.uk/resources/documentation.xml Documentation issues in open source]<br />
* Encourage Using Moodle regulars to contribute to Moodle Docs by adding content in response to a question in the forums, then provide a link to the Moodle Docs page in the forum discussion<br />
* Provide "See also" links in Moodle Docs to additional information in Using Moodle discussions e.g. [[Forums]] (though if the Using Moodle discussion leads to a conclusion/agreement then this should be transferred to MoodleDocs)<br />
<br />
[[Category:MoodleDocs]]<br />
<br />
[[es:MoodleDocs:Filosofía de la documentación]]<br />
[[fr:Philosophie de la documentation]]<br />
[[zh:文档的哲学]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=User_tours&diff=126341User tours2016-12-09T08:59:04Z<p>Fox: /* See also */ French link</p>
<hr />
<div>{{Site appearance}}<br />
{{New features}}<br />
<br />
User tours are step-by-step guides to various areas of Moodle. Administrators can create new tours or import existing tours from [https://moodle.net/mod/data/view.php?id=17 Moodle.net/tours]. The [[Multi-language_content_filter| multi-lang filters]] allow for tours to display in different languages. Watch the screencast [https://youtu.be/hhLVvyP3DU0 User tours] to see a demonstration.<br />
<br />
==How is it set up?==<br />
* As an administrator, access 'User tours' from Site administration<br />
*Here you see any existing user tours and have the option to create a new tour, import a tour or browse user tours on the [https://moodle.net/mod/data/view.php?id=17 Tour repository]. (An administrator and a teacher tour have been added to new and upgraded sites to introduce the [[Boost theme]] and get you started.)<br />
[[File:usertour_listing_page.png|thumb|600px|center]]<br />
*For each of your existing tours, you can click either directly on its name or on its View action icon to view its current listed steps<br />
*Each tour can be individually enabled or disabled as required in its settings page.<br />
'''Note:''' ''You can have multiple tours created for the same page destination, but you should only have one per page enabled at one time.''<br />
*Icons against each tour allow you to view, edit, export or delete it.<br />
*Tours will be displayed on any page whose URL matches the specified path value, for instance:<br />
#/my/% - to match the Dashboard<br />
#/course/view.php?id=2 - to match a specific course<br />
#/mod/forum/view.php% - to match the forum discussion list<br />
#/user/profile.php% - to match the user profile page<br />
*Each tour will be configured with default step settings which you can edit in the settings page:<br />
*Placement: Top, Bottom (Default), Left, Right. This determines where the step shows relative to its matching block or CSS selector on the page.<br />
*Show if target not found: No (Default), Yes. This determines whether the step is shown or not when the target has not been found.<br />
*Show with backdrop: No (Default), Yes. If yes, the step appears surrounded by a darkened backdrop to emphasis its content and location.<br />
*Move on click: No (Default), Yes. If yes, the tour continues to the next step when the user clicks within the block or area targeted by the current step.<br />
'''Note:''' ''If you want users to be able to fill in forms as they work through the tour, then don't use a backdrop.''<br />
*Tour filters allow you to choose the role(s) and theme(s) for which the tour will be displayed.<br />
<br />
==How do I add steps to a tour ?==<br />
* Either click directly on its name or on its View action icon to view the currently listed steps.<br />
*Here are the initial steps for a sample tour for the Dashboard page:<br />
[[File:usertour steps page.png|thumb|600px|center]]<br />
*Click on the 'New step' link and select what you want to highlight:<br />
#Block - to display next to a matching block on the page. Select the block you want from the dropdown.<br />
#CSS Selector - to display next to a matching selector on the page. Type in the relevant selector. (See examples below.)<br />
#Display in the middle of the page<br />
*Add the title and content<br />
*For all types, select whether to display the step with a darkened backdrop<br />
*For blocks or selectors, select the Placement option for where to place the display<br />
*For blocks or selectors, select whether to display the step if its target isn’t found<br />
*For blocks or selectors, select whether to move on click, ie move to next step when target is clicked<br />
*Click on 'Save changes'<br />
<br />
==How do user tours work?==<br />
[[File:usertours01.png|thumb|600px|center]]<br />
Once a user tour has been created and enabled, the first time that any user views a page which matches that user tour’s page (path) settings, the user tour will automatically start to display, starting with the first step. Each tour step will display its title and content, along with three button options:<br />
*Prev - to return to the previous step in the tour<br />
*Next - to go to the next step in the tour<br />
*End Tour - to exit out of the tour completely<br />
Any time a user wishes to re-run the page's tour, they can click on the "Reset user tour on this page" link at the bottom of the page.<br />
<br />
==Help with CSS selectors==<br />
If you wish to use CSS selectors as part of your user tour, your browser's developer tools will be very useful in helping you create these selectors:<br />
*[https://developer.chrome.com/devtools#dom-and-styles Google Chrome]<br />
*[https://developer.mozilla.org/en-US/docs/Tools/DOM_Property_Viewer Mozilla Firefox]<br />
*[https://developer.microsoft.com/en-us/microsoft-edge/platform/documentation/f12-devtools-guide/ Microsoft Edge]<br />
*[https://developer.apple.com/library/content/documentation/AppleApplications/Conceptual/Safari_Developer_Guide/ResourcesandtheDOM/ResourcesandtheDOM.html#//apple_ref/doc/uid/TP40007874-CH3-SW1 Apple Safari]<br />
<br />
===Example of a very simple CSS selector===<br />
<br />
[[File:CSS_selector_for_user_picture_in_a_user_tour.png|400px]]<br />
<br />
The settings above will produce this in the user tour:<br />
<br />
[[File:user picture chosen by CSS selector in a user tour.png|400px]]<br />
<br />
* How did we know that .userpicture would select just the Moodle user picture?<br />
* By looking at the page with an HTML inspector in Firefox, as described in the 'Help with CSS selectors' section below.<br />
<br />
===Other simple CSS selector examples===<br />
'''.breadcrumb''' These site links (known as breadcrumbs) will always show where you are in the site and how to return to a main page, such as your Dashboard or your course main page.<br />
<br />
'''.usermenu''' This is the user menu. It contains links to your Dashboard, Messages, Profile, and your Preferences.<br />
<br />
'''[value="Customise this page"]''' Add your own blocks of content by clicking here!<br />
<br />
<br />
==Multi-language capability==<br />
<br />
If your Moodle site is already set up or intending to be enabled for multi-lingual usage, tours are completely compatible with this requirement. Using the multi-lang filter formatting, each tour step’s titles and content, displayed to the user, can be edited to cater for multi-lingual requirements. Please see [[Multi-language_content_filter]] for further detailed instructions on how to enable, format and submit multi-lingual strings for your Moodle site.<br />
<br />
Please remember to go to '' Dashboard ► Site administration ► Plugins ► Filters ► Manage filters '' in order to enable the [[Multi-language_content_filter]] before importing any multi-language user tours into your site, or the users will see ALL the texts in ALL the languages simultaneously, as the following image illustrates:<br />
<br />
[[File:Multilang user tour when multilang filter NOT properly configured.png|300px]]<br />
<br />
When properly configured, a multi-language user tour will be automatically displayed in the user's preferred language, as seen in the following Dashboard tours starting pages in Spanish, English and French (in the same server):<br />
<br />
[[File:Multilang user tour in Spanish.png|300px]]<br />
<br />
[[File:Multilang user tour in English.png|300px]]<br />
<br />
[[File:Multilang user tour in French.png|300px]]<br />
<br />
==Translating user tours==<br />
See [https://docs.moodle.org/dev/Translating_User_tours_from_Moodle.net how to translate user tours] in the developer's documentation..<br />
<br />
==Sharing is caring==<br />
<br />
We really hope that you are able to create some really powerful tours to help guide your users around your site. We certainly think you will and we encourage you to share any of the tours you create with others.<br />
<br />
We've created a [https://moodle.net/mod/data/view.php?id=17 Moodle.net tour database] where you can share your creations and also find inspiration from the ideas of others.<br />
<br />
This work was paid for and sponsored by the kind folk of [http://www.dcu.ie/ Dublin City University].<br />
<br />
==User tour capabilities==<br />
<br />
There is just one capability, which is allowed for the default role of manager:<br />
<br />
* [[Capabilities/tool/usertours:managetours|Create, edit and remove user tours]]<br />
<br />
==See also==<br />
<br />
* [http://jsonlint.com/ JSONLint - a JSON validator] useful for checking the workings of a JSON file<br />
<br />
[[es:Tours para Usuarios]]<br />
[[fr:Visites guidées]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=MySQL&diff=125089MySQL2016-08-29T13:40:51Z<p>Fox: /* Which database belongs to which Moodle */</p>
<hr />
<div>{{Installing Moodle}}<br />
MySQL is one of the supported databases that underpins a Moodle installation. <br />
<br />
== Installing MySQL ==<br />
<br />
* If you are running Linux your preference should be to install using your distributions package manager. This ensures you will get any available updates. However, you can also use apt-get or yum depending on the distribution that you are running.<br />
* There are installers available for most popular operating systems at http://www.mysql.com/downloads/mysql/.<br />
* It is possible and reasonably straightforward to build mysql from source but it is not recommended (the pre-built binaries are supposedly better optimised).<br />
* Make sure you set a password for the 'root' user (see http://dev.mysql.com/doc/refman/5.0/en/default-privileges.html).<br />
* Consider installing and configuring my.cnf (the MySQL settings file) to suit your needs. The default configuration is usually very conservative in respect of memory usage versus performance. Increase the 'max_allowed_packet' setting to at least 4 megabytes.<br />
* If you are going to use Master/Slave replication, you must add binlog_format = 'ROW' into your my.cnf within [mysqld]. Otherwise, Moodle will not be able to write to the database.<br />
<br />
== Creating Moodle database ==<br />
<br />
These are the steps to create an empty Moodle database. Substitute your own database name, user name and password as appropriate.<br />
<br />
The instructions assume that the web server and MySQL server are on the same machine. In this case the 'dbhost' is 'localhost'. If they are on different machines substitute the name of the web server for 'localhost' in the following instructions and the 'dbhost' setting will be the name of the database server. <br />
Databases have a "Character set" and a "Collation". For moodle the character set should be utf8 and the collation is utf8_general_ci. You may get the option to set these values when you create the database. If you are not given a choice, the default options are probably good. An install on an old server may have the wrong settings.<br />
<br />
=== Command line === <br />
<br />
* To create a database using the 'mysql' command line client, first log into MySQL<br />
<pre><br />
$ mysql -u root -p<br />
Enter password: <br />
</pre><br />
(Enter the password you previously set - or been given - for the MySQL 'root' user). After some pre-amble this should take you to the ''mysql>'' prompt.<br />
* Create a new database (called 'moodle' - substitute your own name if required). We recommend you use '''utf8_unicode_ci''' for collation.<br />
<pre><br />
mysql> CREATE DATABASE moodle DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;<br />
</pre><br />
* Add a user/password with the minimum needed permissions:<br />
<pre><br />
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,CREATE TEMPORARY TABLES,DROP,INDEX,ALTER ON moodle.* TO moodleuser@localhost IDENTIFIED BY 'yourpassword';<br />
</pre><br />
...which creates a user called 'moodleuser' with a password 'yourpassword'. Make sure you invent a strong password and resist the temptation to 'GRANT ALL'.<br />
<br />
=== phpMyAdmin ===<br />
<br />
[http://www.phpmyadmin.net/ phpMyAdmin] is a web based administration tool for MySQL. If this is available you can use it to create a new database. Make sure that you select 'UTF8' as the default character set.<br />
<br />
==Which database belongs to which Moodle==<br />
If you have installed several Moodle installations on the same server, there will be several databases in your MySQL server. The names might be quite poor reflections of the content like _mdl1 _mdl2 _mdl3 . So how do I see which database goes with which Moodle installation? You can go in with phpMyAdmin and in the various databases check for the table "mdl_course". There you will easily see the name of that Moodle Installation. In table mdl_config you can see the Moodle version. The main URL for the site is not in the database except where there are absolute links.<br />
<br />
== See also ==<br />
<br />
* [[MariaDB]]<br />
* [http://www.mysql.com/ The MySQL homepage]<br />
* [http://en.wikipedia.org/wiki/MySQL Wikipedia article about ''MySQL'']<br />
* [http://forums.mysql.com/read.php?24,92131,92131 List of articles on MySQL performance tuning]<br />
<br />
[[Category:SQL databases]]<br />
<br />
[[ja:MySQL]]<br />
[[de:MySQL]]<br />
[[es:MySQL]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=Cron_with_Unix_or_Linux&diff=124139Cron with Unix or Linux2016-06-20T08:40:00Z<p>Fox: Updated, and deleted (very) old information</p>
<hr />
<div>{{Installing Moodle}}<br />
On Unix and Linux use the built in ''cron'' program which is standard on nearly all systems. You are required to add a command to the 'crontab' (the table that holds cron commands) for the web server user. <br />
<br />
There are two different methods that can be used to invoke the Moodle cron process:<br />
<br />
'''NOTE:''' The commands shown need to be added to the crontab to function (described in a moment). However, you can - and should - run them on the command line to check they work first. <br />
<br />
== Method 1: The command line (cli) cron ==<br />
<br />
If you have a choice, this is normally the best way to run Moodle cron. <br />
<br />
PHP is also capable of running programs directly from the command line. Your system needs to be set up to do this; specifically you need the 'CLI' version of PHP to be installed. Most systems with PHP installed will have this by default. If you have the PHP CLI version installed then this is the recommended method of invoking cron. The correct command will be something like...<br />
<pre><br />
/usr/bin/php /path/to/moodle/admin/cli/cron.php<br />
</pre><br />
(substitute the correct path to moodle and for php as required)<br />
<br />
You can simply type this on the command line this to see if it works. If you are not sure about the path to PHP you can type "<code>which php</code>".<br />
<br />
'''Tip:''': If you have problems, see the [[PHP]] page. In particular, suspect an alternate php.ini for the CLI PHP command which may not have suitable settings.<br />
<br />
== Method 2: Web based cron ==<br />
<br />
'''NOTE:''' In order to use the web based cron script you must first check [[Cron settings]] to make sure this method is permitted. <br />
<br />
The idea is to call the following web page (you can try this from your browser):<br />
<pre><br />
http://url.of.your/moodle/admin/cron.php<br />
</pre><br />
<br />
A command line (text based) browser is needed to run this on the server. Possibilities are as follows (OSX, for example, only ships with curl)...<br />
<pre><br />
/usr/bin/wget -q -O /dev/null/ http://url.of.your/moodle/admin/cron.php<br />
</pre><br />
(no output is displayed - remove the ''-O /dev/null/'' to test)<br />
<br />
...OR...<br />
<br />
<pre><br />
/usr/bin/curl http://url.of.your/moodle/admin/cron.php -o /dev/null/ -silent<br />
</pre><br />
(no output is displayed - remove the ''-o /dev/null/ -silent'' to test)<br />
<br />
==Using the crontab program on Unix/Linux==<br />
<br />
Once you have selected (and tested!) an appropriate command to invoke the Moodle cron it must be added to the web users 'crontab' to schedule it to run regularly. 'Crontab' is both a file containing the user's cron commands and is also the name of the (command line) program used to edit it. Use the following command (as root) substituting the correct user in place of 'www-data' (e.g. 'apache' for Centos, 'www-data' for Debian/Ubuntu - Google will know!)<br />
<pre><br />
# crontab -u www-data -e<br />
</pre><br />
This will bring up an editor window (the first time it may ask you which editor to use). Add the command onto the end of the file in this way (it may be empty or it may have some instructional comments):<br />
<pre><br />
*/1 * * * * /usr/bin/php /path/to/moodle/admin/cli/cron.php >/dev/null<br />
</pre><br />
The first five entries specify the times, followed by the command, to run. This says to run the command every minute which is normally ok. On a hosted system you may get complaints if you do not run it a lot less often (e.g. to run every two hours use '0 */2 * * *' for the first five entries). If you want to use the wget/curl version, the first five entries remain the same - just change the command part.<br />
<br />
== See also ==<br />
<br />
* [http://linuxweblog.com/node/24 A basic crontab tutorial] <br />
* [http://www.freebsd.org/cgi/man.cgi?query=crontab&apropos=0&sektion=5&manpath=FreeBSD+6.0-RELEASE+and+Ports&format=html Online version of the man page]<br />
* [http://www.easycron.com/predictor Predicting Cron job's run time]<br />
<br />
[[es:Cron con Unix o Linux]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=Logged_in_user_block&diff=122247Logged in user block2016-02-11T09:23:06Z<p>Fox: French link</p>
<hr />
<div>{{Blocks}}<br />
The logged in user block displays certain information about the user who is currently logged in to a Moodle course:<br />
<br />
[[File:Loggedinuserexample.png]]<br />
<br />
The information which is displayed can be selected by the course teacher by clicking on the "configure" icon of the block. A number of dropdown boxes then appear for the teacher to choose which items will appear:<br />
<br />
[[File:Loggedinusersettings.png]]<br />
<br />
[[de:Persönliches-Profil-Block]]<br />
[[es:Bloque de usuario ingresado]]<br />
[[fr:Bloc Utilisateur connecté]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=Moodle_app_additional_features&diff=122231Moodle app additional features2016-02-10T16:05:15Z<p>Fox: French link</p>
<hr />
<div>{{Mobile}}<br />
{{Infobox plugin<br />
|type = Local plugin<br />
|entry = http://moodle.org/plugins/view.php?plugin=local_mobile<br />
|tracker = https://tracker.moodle.org/browse/CONTRIB/component/13930<br />
|discussion = https://moodle.org/mod/forum/view.php?id=7798<br />
|maintainer = [[User:Juan Leyva|Juan Leyva]]<br />
}}<br />
<br />
The Moodle Mobile additional features plugin provides new features and web services for the Moodle Mobile app which are currently only available in the latest Moodle version.<br />
<br />
This plugin is officially developed and maintained by Moodle HQ<br />
<br />
== How it works ==<br />
<br />
Once installed the plugin creates a new service "Moodle Mobile additional features". The Mobile app checks if this service is enabled. If not, the Mobile app falls backs to the standard core Mobile app service.<br />
<br />
Please, open [[Moodle Mobile features]] to check what new features are added to your site depending on your Moodle version.<br />
<br />
== Features ==<br />
<br />
* Support for sites using SSO authentication methods (Shibboleth and CAS)<br />
* Support for sites using MNet authentication (Moodle Network authentication)<br />
* Support for push notifications in Moodle sites prior to version 2.6<br />
<br />
=== Enable authentication for sites using SSO methods (like Shibboleth and CAS) ===<br />
<br />
VERY IMPORTANT NOTE: You need to disable the "Auto login guest" option "autologinguests". This setting is not compatible with the SSO via app.<br />
<br />
SSO and MNet authentication is not supported in the Windows 8 and Windows Phone 8 apps<br />
<br />
Once the plugin is installed, you need to go to Site administration > Plugins > Local plugins > Moodle Mobile additional features<br />
<br />
There you can choose the "Type of login":<br />
; '''Via the app''' : Is the default login, the user must introduce his credentials in the app<br />
; '''Via a browser window''' : A new browser instance is open in the mobile device pointing to the login form in the Moodle site (which may again redirect to external identity providers if required). The user must introduce his credentials there. This is the option that must be selected for sites using SSO methods (or for sites that wants to force the user to authenticate in the site, not in the app)<br />
<br />
<br />
<mediaplayer>https://www.youtube.com/watch?v=cl8rsyyyg9g</mediaplayer><br />
<br />
== Installation ==<br />
<br />
# Unpack the zip file into the local/ directory. A new directory will be created called local/mobile.<br />
# Go to ''Site administration > Notifications'' to complete the plugin installation.<br />
# Go to ''Site administration > Plugins > Web services > Mobile'' and enable web services for mobile devices (Remember to save the changes)<br />
# Go to ''Site administration > Plugins > Web services > External services'', edit "Moodle Mobile additional features" and check the "Enabled" field, then save changes.<br />
# Go to ''Site administration > Users > Permissions > Define roles'', edit the Authenticated user role and allow the capability moodle/webservice:createtoken.<br />
<br />
Note: You need to have upgraded the Moodle Mobile app to version 1.4.4.<br />
<br />
If you are currently using the Moodle Mobile app, you will need to log out of all your sites in order for the app to detect the new service.<br />
<br />
== Admin users, please read ==<br />
<br />
This plugin installs a new service in your Moodle installation, the automatic token creation for this type of services is forbidden for admin users. This means that admin users will not be able to use the Mobile app.<br />
<br />
This can be solved easily, administrators must create a token manually in Moodle (''Plugins > Web Services > Manage tokens'') for the local_mobile service. '''Note:''' Be sure to toggle the default "Moodle mobile web services" setting to "Moodle mobile additional features service" before creating the token. <br />
<br />
[[de:Moodle Mobile - Zusatzfunktionen]]<br />
[[es:Características adicionales de Moodle Mobile]]<br />
[[fr:Fonctionnalités additionnelles de l'app mobile]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=Creating_mobile-friendly_courses&diff=122230Creating mobile-friendly courses2016-02-10T16:02:39Z<p>Fox: French link</p>
<hr />
<div>{{Mobile}}<br />
As more and more students access courses from their smartphones, tablets or other mobile devices, it is increasingly important to ensure your courses are mobile-friendly.<br />
<br />
Encouraging students to install the [https://download.moodle.org/mobile/ official Moodle mobile app] is one way to improve their learning experience. Below are some suggestions for optimising your course materials for students both using the app and accessing Moodle from mobile devices.<br />
<br />
==Use a mobile-friendly theme==<br />
<br />
Recent versions of Moodle allow for responsive themes, which adapt to the browser screen size. Make sure your course uses such a theme and check its contents yourself before your students start the course.<br />
<br />
==Notifications and messages==<br />
<br />
Encourage your students to enable mobile notifications so they are alerted about calendar events, forum posts, messages, assignment submissions and so on. Find out more in [[Mobile app notifications]].<br />
<br />
==Provide a 'how to' guide to Moodle on the mobile==<br />
<br />
Consider offering your students a guide (as a PDF or a page resource) on how to access your course on the app, what they can do and not (yet) do from the app. Read up on the [[Moodle Mobile features]] and what's [[New for mobile]].<br />
<br />
==Setting up your course==<br />
<br />
*Topics or weekly course format is best suited to mobile devices.<br />
*Don't use orphaned activities or direct links to activities.<br />
*If you have a mix of students accessing the course on mobile and desktop, consider asking your admin to install the [[Moodle Mobile availability plugin]] which restricts items to desktop or mobile users.<br />
<br />
==Course content==<br />
<br />
*Labels are initially collapsed, so include a short text introduction of what is inside any label.<br />
*Use responsive HTML in pages or mini-sites.<br />
*Try to use a [[Page resource|page resource]] instead of downloadable documents where possible.<br />
*Avoid uploading many documents or having numerous, text heavy pages. Think more in terms of short "information-bytes".<br />
*If you include YouTube videos, provide them also for download and offline viewing in a [[Folder resource|folder]]. Not all video formats are supported so add them in different formats. (MP4 is probably the most widely accepted format.)<br />
*Note that if you add YouTube video links or map links as URL resources, they will open automatically in the app.<br />
<br />
{|<br />
| [[File:moodlemobile_short_text_intro.png|thumb|Short text for label]]<br />
| [[File:moodlemobile_responsive_html.png|thumb|Responsive HTML]]<br />
| [[File:moodlemobile_youtube_maps_links.png|thumb|Map link]]<br />
|}<br />
<br />
=== Things to avoid===<br />
<br />
Some activities are not yet supported by the mobile app, so find alternatives.<br />
<br />
*Instead of using an [[IMS content package]], unzip the file and add it as a resource (mini-site)<br />
<br />
See [[Moodle Mobile SCORM player]] for things to avoid in SCORM packages.<br />
<br />
==Learn more==<br />
<br />
* [http://es.slideshare.net/juanleyva/tips-for-creating-moodle-mobile-friendly-courses-sites-moodlemoot-spain-2014 Tips for creating Moodle Mobile friendly courses and sites - MoodleMoot Spain 2014] - Juan Leyva, Mobile app developer, presented this in 2014. While some features have now been updated, the general principles are still useful. <br />
* An open course, about "[http://tempus-efa.proj.ac.il/moodle/course/view.php?id=102 Teaching using Mobile - Best practices]"<br />
<br />
[[es:Crear sitios amistosos para Moodle Mobile]]<br />
[[fr:Créer des cours pour appareils mobiles]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=Moodle_app_notifications&diff=122229Moodle app notifications2016-02-10T16:01:28Z<p>Fox: French link</p>
<hr />
<div>{{Mobile}}<br />
<br />
==For students and teachers==<br />
[[File:12Notifications.png|thumb|Forum post notification]]<br />
The Moodle mobile app lets you keep up to date with all that's happening in your courses and on the site. Every time you open the app, events are synchronised with the main website.<br />
<br />
You will receive [[Calendar|Moodle calendar]] event notifications automatically. If you don't want to get them, you can turn them all off in the app in ''Settings > General,'' or individually in the Calendar events options in the main menu.<br />
<br />
You will also receive notifications of messages, forum posts, submitted assignments etc (known as 'push notifications') if your site administrator has enabled these. To receive these notifications you need to enable them for your mobile on the main site, from the user menu top right >''Preferences>Messaging.''<br />
<br />
==For administrators==<br />
<br />
Push notifications can be enabled by an administrator by connecting their Moodle site to a messaging server such https://messages.moodle.net (available for [[Site registration|registered Moodle sites]] only). An access key can be obtained via ''Administration > Site administration > Plugins > Message outputs > Mobile Notifications''. (If you have problems requesting the access key, please fill in the [http://goo.gl/forms/WLwkbe8b7c Airnotifier access key manual request form]. Your site registration will be checked and you will be sent an access key in a few days if everything is correct.)<br />
<br />
Users then need to connect at least once with the latest version of the Moodle Mobile app in order to register their phones with the Moodle site.<br />
<br />
=== Event Reminders plugin===<br />
<br />
Push notifications can also include calendar event notifications, however this requires the [https://moodle.org/plugins/view/local_reminders Event Reminders plugin] to be installed on the Moodle site.<br />
<br />
The Event Reminders plugin will automatically send reminders for Moodle calendar events in a timely manner via Moodle message interface. It also allows users to control how they receive messages for each type of event in the Moodle calendar.<br />
<br />
=== Installing your own notifications infrastructure ===<br />
<br />
If you have a customized version of the Moodle Mobile app, or you want to use your own notifications infrastructure, you will have to install a private [http://airnotifier.github.io AirNotifier] (backend server for notifications).<br />
<br />
https://messages.moodle.net uses a slightly modified version of Airnotifier: https://github.com/moodlehq/airnotifier/tree/moodle2. <br />
<br />
You will have to add your app certificates - see https://github.com/airnotifier/airnotifier/wiki/Installation for further information.<br />
<br />
The Airnotifier message plugin allows you to point to your custom Airnotifier instance using your own access keys.<br />
<br />
Remember to install using GIT (repository https://github.com/moodlehq/airnotifier.git branch ''moodle2'').<br />
<br />
[[de:Moodle Mobile - Mitteilungen]]<br />
[[es:Mobile app Notificaciones Push]]<br />
[[fr:Notifications de l'app mobile]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=Moodle_app&diff=122227Moodle app2016-02-10T15:47:27Z<p>Fox: French link</p>
<hr />
<div>{{Main page}}<br />
__NOTOC__<br />
==On the move with Moodle==<br />
[[File:Mobile orientation.png|thumb|Access your Moodle course on your mobile]]<br />
Moodle Mobile is the official mobile app for Moodle.<br />
<br />
* Browse the content of your courses, even when offline<br />
* Participate in course activities from your mobile device<br />
* Receive instant notifications of messages and other events<br />
* Quickly find and contact other people in your courses<br />
* Upload images, audio, videos and other files.<br />
* View your course grades<br />
<br />
... and more - see the full list of [[Moodle Mobile features]].<br />
<br />
The Moodle Mobile app is available for free from Google Play, Apple Store, and the Windows Phone Store. See [https://download.moodle.org/mobile/ Moodle Mobile downloads] for links. You can also install the app directly from your mobile device by searching for 'Moodle Mobile' with author/owner 'Moodle Pty Ltd'.<br />
<br />
==Using the app==<br />
*To set up notifications on your app, see [[Mobile app notifications]]<br />
*For a quick guide to setting up the Moodle mobile app on your site, see [[Moodle Mobile guide for admins]].<br />
*For ideas to make your Moodle course more mobile friendly, see [[Creating Moodle Mobile friendly courses]].<br />
<br />
==Rapid development==<br />
More features are being added to Moodle Mobile all the time. See [[New for mobile|what's new in Moodle Mobile]] and the [[:dev:Moodle Mobile release notes|Moodle Mobile release notes]].<br />
<br />
==See also==<br />
* [[Moodle Mobile FAQ]]<br />
<br />
[[Category:Mobile]]<br />
<br />
[[fr:App mobile]]<br />
[[ja:モバイルアプリ]]<br />
[[de:Mobiles Moodle]]<br />
[[es:Moodle Mobile]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=Moodle_app_features&diff=122226Moodle app features2016-02-10T15:44:59Z<p>Fox: French link</p>
<hr />
<div>{{Mobile}}<br />
__NOTOC__<br />
<div class="contentblock"><br />
<div class="row-fluid"><br />
<ul class="thumbnails"><br />
<li class="span6"><br />
<div class="thumbnail"><br />
[[File:mobile01.png|600px]]<br />
<div class="caption"><br />
<h4>See your courses at glance</h4><br />
<p>Your courses are listed with easy access to contents, participants, grades and notes. A useful filter field lets you find a particular course quickly. If your token expires during a session, you're prompted to re-enter your password and continue. </p><br />
</div><br />
</div><br />
</li><br />
<li class="span6"><br />
<div class="thumbnail"><br />
[[File:02connectwithcourseparticipants.png|600px]]<br />
<div class="caption"><br />
<h4>Connect with course participants</h4><br />
<p> Infinite scrolling improves access to the participant view, with the complete user profile now displayed and available from every page. </p><br />
</div> <br />
</div><br />
</li><br />
</ul><br />
</div><br />
<br />
<div class="contentblock"><br />
<div class="row-fluid"><br />
<ul class="thumbnails"><br />
<li class="span6"><br />
<div class="thumbnail"><br />
[[File:10PulltoRefresh.png|600px]]<br />
<div class="caption"><br />
<h4>Pull to refresh</h4><br />
<p>Most screens will allow you to pull to refresh, improving the real-time participation experience.</p><br />
</div><br />
</div><br />
</li><br />
<li class="span6"><br />
<div class="thumbnail"><br />
[[File:Mobile orientation.png|600px]]<br />
<div class="caption"><br />
<h4> Orientation and resolution support </h4><br />
<p>The app displays in portrait or landscape view, whatever your screen resolution.</p><br />
</div><br />
</div><br />
</li><br />
</ul><br />
</div><br />
<br />
<div class="contentblock"><br />
<div class="row-fluid"><br />
<ul class="thumbnails"><br />
<li class="span6"><br />
<div class="thumbnail"><br />
[[File:03coursecontent.png|600px]]<br />
<div class="caption"><br />
<h4>Easily access course content</h4><br />
<p>View course activities and and download materials for offline use. Work through Books and IMS Content packages directly in the app. The downloading status of resources is preserved even when changing sections or pages.</p><br />
</div><br />
</div><br />
</li><br />
<li class="span6"><br />
<div class="thumbnail"><br />
[[File:04ActivityCompletionCheckboxes.png|600px]]<br />
<div class="caption"><br />
<h4>Activity completion</h4><br />
<p>Track progress from your device with [[Activity completion]]. Automatic completion is registered, and students can also manually mark a task complete on their mobile.</p><br />
</div><br />
</div><br />
</li><br />
</ul><br />
</div><br />
<br />
<div class="contentblock"><br />
<div class="row-fluid"><br />
<ul class="thumbnails"><br />
<li class="span6"><br />
<div class="thumbnail"><br />
[[File:05Grades.png|600px]]<br />
<div class="caption"><br />
<h4>Grades and grading</h4><br />
<p> A Grades link for each course gives fingertip access to the gradebook, and teachers can view assignment submissions on the move.</p><br />
</div><br />
</div><br />
</li><br />
<li class="span6"><br />
<div class="thumbnail"><br />
[[File:06Notes.png|600px]]<br />
<div class="caption"><br />
<h4>Notes</h4><br />
<p>Teachers can view site, course and personal notes about their students and add their own notes.</p><br />
</div><br />
</div><br />
</li><br />
</ul><br />
</div><br />
<br />
<div class="contentblock"><br />
<div class="row-fluid"><br />
<ul class="thumbnails"><br />
<li class="span6"><br />
<div class="thumbnail"><br />
[[File:07Messages.png|600px]]<br />
<div class="caption"><br />
<h4>Message participants</h4><br />
<p>Send and view private messages to colleagues and students from the Messages link in the side tab.</p><br />
</div><br />
</div><br />
</li><br />
<li class="span6"><br />
<div class="thumbnail"><br />
[[File:08Calendar.png|600px]]<br />
<div class="caption"><br />
<h4>Keep up to date with calendar events</h4><br />
<p>Site, course and user events can be viewed in the calendar.Calendar events can now be viewed offline and infinite scrolling is available.</p><br />
</div><br />
</div><br />
</li><br />
</ul><br />
</div><br />
<br />
<div class="contentblock"><br />
<div class="row-fluid"><br />
<ul class="thumbnails"><br />
<li class="span6"><br />
<div class="thumbnail"><br />
[[File:09PrivateFiles.png|600px]]<br />
<div class="caption"><br />
<h4>View and upload to your Private files</h4><br />
<p>Check the contents of your private files and upload media to them on the go. You're now allowed up to 50MB storage (depending on your SD card).</p><br />
</div><br />
</div><br />
</li><br />
<li class="span6"><br />
<div class="thumbnail"><br />
[[File:12Notifications.png|600px]]<br />
<div class="caption"><br />
<h4>Notifications</h4><br />
<p>Keep up to date with notifications. The app supports both local (calendar events) and push (messages, forum posts, submitted assignments etc) notifications. See [[Mobile app notifications]] for more details. Infinite scrolling is available and local notifications have multi-site support.</p><br />
</div><br />
</div><br />
</li><br />
</ul><br />
</div><br />
<br />
<div class="row-fluid"> <br />
<ul class="thumbnails"> <br />
<li class="span6"> <br />
<div class="thumbnail"> <br />
[[File: MobileChoice.png|600px]] <br />
<div class="caption"> <br />
<h4>Make choices</h4> <br />
<p>The app supports students making and removing choices.</p> <br />
</div> <br />
</div> <br />
</li> <br />
<li class="span6"> <br />
<div class="thumbnail"> <br />
[[File:MobileappChat.png|600px]] <br />
<div class="caption"> <br />
<h4>Engage in chat, on the move</h4> <br />
<p>Participate in a course [[Chat activity]].</p> <br />
</div> <br />
</div> <br />
</li> <br />
</ul> <br />
</div> <br />
<div class="row-fluid"> <br />
<ul class="thumbnails"> <br />
<li class="span6"> <br />
<div class="thumbnail"> <br />
[[File:MobileSurvey.png|600px]] <br />
<div class="caption"> <br />
<h4> Feed back to teachers with a survey</h4> <br />
<p>[[Survey|Surveys]] may now be taken using the app.</p> <br />
</div> <br />
</div> <br />
</li> <br />
<li class="span6"> <br />
<div class="thumbnail"> <br />
[[File: coursesearchmobile.png|600px]] <br />
<div class="caption"> <br />
<h4>Search the list of courses</h4> <br />
<p>App users can search courses to find one they wish to take.</p> <br />
</div> <br />
</div> <br />
</li> <br />
</ul> <br />
</div><br />
<div class="row-fluid"> <br />
<ul class="thumbnails"> <br />
<li class="span6"> <br />
<div class="thumbnail"> <br />
[[File:enrolmemobile.png|600px]] <br />
<div class="caption"> <br />
<h4>Enrol yourself from your smartphone</h4> <br />
<p>Found a course you like? Enrol immediately via the app.</p> <br />
</div> <br />
</div> <br />
</li> <br />
<li class="span6"> <br />
<div class="thumbnail"> <br />
[[File:scorm syncing.png|600px]] <br />
<div class="caption"> <br />
<h4>Play SCORM packages on and off-line</h4> <br />
<p>The [[Moodle Mobile SCORM player]] tracks interactions and synchronises when you're back online.</p> <br />
</div> <br />
</div> <br />
</li> <br />
</ul> <br />
</div><br />
<br />
====Features summary====<br />
<br />
* Responsive design for phone and tablets<br />
* Upload a picture into your private file area<br />
* Record an audio file and upload it into your private file area<br />
* Record a video and upload it into your private file area<br />
* Send a private message to a course participant (can be done offline)<br />
* Take a personal note about a course participant (can be done offline)<br />
* Add a course participant to your phone contact<br />
* Call a course participant touching the phone number<br />
* Locate a course participant address on Google map<br />
* Download and view some course resources<br />
* Quick access to your course contents<br />
* View calendar events<br />
* Reminder notifications for calendar events<br />
* Mobile Push notifications<br />
* Remote layout/style customization (see below)<br />
* View all your past private messages and notifications<br />
* Browse and download your private and course files<br />
* View forum discussions<br />
* Private messaging between users<br />
* Calendar integration with warning reminders as local notifications<br />
* Upload any type of file from your device to your Moodle private files area<br />
* View the book module and IMS CP<br />
* View site, course and personal users notes<br />
* Support for sites using CAS or Shibboleth as auth methods <br />
* View your activity and course total grades in a course <br />
* Participate in choices <br />
* Participate in chats <br />
* Participate in surveys<br />
* Access external tools (LTI)<br />
* Course search<br />
* Self-enrolment in courses<br />
* Access courses with guest access enrolment method enabled<br />
* [[Moodle_Mobile_SCORM_player|SCORM player]]<br />
<br />
==Comparison of features in different versions==<br />
[[File:30_moodlemobile_features.png]]<br />
<br />
=== Languages ===<br />
<br />
Over 15 languages are currently supported: Arabic, Basque, Catalan, Chinese, Czech, Dutch, English, French, German, Hebrew, Hungarian, Italian, Japanese, Mexican Spanish, Portuguese, Russian, Spanish, Swedish<br />
<br />
[[es:Características de Moodle Mobile]]<br />
[[fr:Fonctionnalités de l'app mobile]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=External_database_enrolment&diff=122223External database enrolment2016-02-10T09:34:13Z<p>Fox: French link</p>
<hr />
<div>{{Enrolment}}<br />
==Using an external database to control enrolments==<br />
<br />
You may use a external database (of nearly any kind) to control your enrolments. It is assumed your external database contains a field containing a course ID, a field containing a user ID, and optionally a field containing a role. These are compared against fields that you choose in the local course, user tables, and role tables.<br />
<br />
The following are the supported data sources, but note that you will need to have to compiled PHP with the appropriate options or through ODBC.<br />
<br />
*access<br />
*ado<br />
*mssql<br />
*borland_ibase<br />
*csv<br />
*db2<br />
*fbsql<br />
*firebird<br />
*ibase<br />
*informix72<br />
*informix<br />
*mysql<br />
*mysqlt<br />
*oci805<br />
*oci8<br />
*oci8po<br />
*odbc<br />
*odbc_mssql<br />
*odbc_oracle<br />
*oracle<br />
*postgres64<br />
*postgres7<br />
*postgres<br />
*proxy<br />
*sqlanywhere<br />
*sybase<br />
*vfp<br />
<br />
== Enrolment and unenrolment ==<br />
<br />
External database enrolment happens at the moment when a user logs into Moodle. The plugin will attempt to automatically enrol the student in all their courses according to the data in the external database and, optionally, create empty courses where they do not already exist. To check if it is working, you can log in as a student and then check that their list of courses is as you would expect. <br />
<br />
The process also unenrols users from courses if they are no longer in the database. User records are marked according to their original enrolment method. Therefore the external database plugin can only unenrol users who were enroled by the plugin in the first place.<br />
<br />
== Hidden courses ==<br />
<br />
Courses that are set to "Course is not available to students" can be ignored for enrolment purposes by setting the "enrol_db_ignorehiddencourse" to '''yes'''.<br />
<br />
== Enrolment and roles ==<br />
<br />
The "enrol_database | defaultrole" setting in the plugin settings page specifies the role that the user will take when they are added to the course. The default setting will set them to the course default setting (initially "student"). However, you can specify a field in the external table (specified in the "enrol_database | remoterolefield" setting) that contains the short name or id for the user's role. This could, for example, be used to enrol both students and teachers into courses using a suitably configured database.<br />
<br />
== Unenrolment ==<br />
<br />
The External unenrol action ("enrol_database | unenrolaction") setting in the plugin settings page defines what action should be taken when a user enrolment disappears from external enrolment source. Each setting does the following:<br />
#'''"Unenrol user from course"''' When the user disappears from the external source, the enrolment is completely removed and all the roles removed. This means some user data and settings are purged from course during course unenrolment (that usually include grades, activity attempts, etc.)<br />
#'''"Keep user enrolled"''' When the user disappears from the external source, the enrolment is kept as is, and the user is still able to enter the course and perform activities, access resources, etc. It's a "do nothing" option.<br />
#'''"Disable course enrolment"''' When the user disappears from the external source, user enrolment is suspended (the user can't access the course, but user data and settings are kept), and roles are kept as is. You might use this because in some cases the user needs a role with some capability to be visible in UI - such has in gradebook, assignments, etc.<br />
#'''"Disable course enrolment and remove roles"''' When the user disappears from the external source, the enrolment is suspended and roles assigned by enrol instance are removed. Please note that user may "disappear" from gradebook and other areas.<br />
<br />
== Creating courses ==<br />
<br />
Optionally courses that do not exist in the Moodle site can be created. Switch the "enrol_db_autocreate" option to "yes" in the plugin settings. <br />
<br />
You can additionally specify the Category into which the new course will be placed, in the '''New course category id field'''. The data in this field must be the id of a currently existing category; it will not create a new category. The id number is number assigned by Moodle in the database when the category is created (e.g. mdl_course_categories.id). <br />
<br />
* Do not confuse this ''category id'' with the new custom ''category id number'' field that you can manually assign to a category. (See Trackers http://tracker.moodle.org/browse/MDL-28518 and http://tracker.moodle.org/browse/MDL-31845). <br />
* Leaving the category id data empty means that a course will be assigned to the default category.<br />
* If you assign data to categories that do not exist already in Moodle, the courses will not be created.<br />
<br />
'''Default new course category''' is the category to which courses will be assigned and created in, unless you set up and so indicate in the data field of the "New course category id field."<br />
<br />
You may also specify a '''New course template''': a "template" course from which the new course will be copied. The data for this field should be the ''shortname'' of the template course.<br />
<br />
== Synchronization script ==<br />
<br />
A script is provided that can synchronize all your user enrollments at once - both adding and removing user enrolments (and creating courses if specified). The script is called sync.php and is found in the enrol/database/cli folder.<br />
<br />
This script is meant to be called from a system cronjob to sync moodle enrolments with enrolments in the external database. You need to make sure all the users present in the external enrolments are already created in moodle. If you are using external authentication plugins (db, ldap, etc.) you can use the scripts provided by those plugins to synchronize your users before running this script.<br />
<br />
Example cron entry<br />
# 5 minutes past 4am<br />
5 4 * * * /usr/bin/php -c /path/to/php.ini /path/to/moodle/enrol/database/cli/sync.php<br />
<br />
Notes:<br />
* If you have a large number of enrolments, you may want to raise the memory limits by passing -d memory_limit=256M<br />
* For debugging & better logging, you are encouraged to use in the command line: -d log_errors=1 -d error_reporting=E_ALL -d display_errors=0 -d html_errors=0<br />
* This only works for users that already exist in your Moodle site (see comment above)<br />
<br />
== Setting up enrolment sync (How to) ==<br />
<br />
You will need to perform (as a minimum) the following steps to enable external database enrolment - only a single table is required in the database which contains a record for every user/course combination. If the table is large it is a good idea to make sure appropriate indexes have been created:<br />
<br />
* Use an existing database or create a new one. Use an existing table or create a new one with the following minimum fields.<br />
*# A unique course identifier to match one of the following fields.<br />
*#* the "idnumber" field in Moodle's course table (varchar 100), which is manually specified as the "Course ID number" when editing a course's settings<br />
*#* the "shortname" field in Moodle's course table (varchar 255), which is manually specified as the "Course short name" when editing a course's settings<br />
*#* the "id" field in Moodle's course table (int 10), which is based on course creation order<br />
*# A unique user identifier to match one of the following fields.<br />
*#* the "idnumber" field in Moodle's user table (varchar 255), which is manually specified as the "ID number" when editing a user's profile<br />
*#* the "username" field in Moodle's user table (varchar 100), which is manually specified as the "Username" when editing a user's profile<br />
*#* the "email" field in Moodle's user table (varchar 100), which is manually specified as the "Email address" when editing a user's profile<br />
*#* the "id" field in Moodle's user table (int 10), which is based on user creation order<br />
*# (optional) A unique role identifier to match one of the following fields.<br />
*#* the "shortname" field in Moodle's role table (varchar 100), for example editingteacher, coursecreator, student, ...<br />
*#* the "name" field in Moodle's role table (varchar 255), for example Teacher, Course creator, Student, ...<br />
*#* the "id" field in Moodle's role table (int 10), which is based on initial installation and new role creation order<br />
* Populate the database table. Each user/course combination to have a record in the table.<br />
* In Moodle, go to ''Site administration > Plugins > Enrolments > Manage enrol plugins'', find External Database in the list, enable it (click the closed-eye icon) and click Settings.<br />
* In the top panel, select the database type (make sure you have the necessary configuration in PHP for that type) and then supply the information to connect to the database.<br />
* The middle panel creates the mapping between Moodle and the external database. The first three settings are for the local (Moodle) field names and the last three for the remote (external database) settings. They are in the same order.<br />
** enrol_localcoursefield / enrol_remotecoursefield - in Moodle the name of the field in the course settings the uniquely identifies the course (e.g., idnumber). In the external database the name of the matching field.<br />
** enrol_localuserfield / enrol_remoteuserfield - in Moodle the name of the field in the user profile that uniquely identified the user (e.g., idnumber). In the external database the name of the matching field.<br />
** enrol_db_localrolefield / enrol_db_remoterolefield - (optional) in Moodle the name of the field in the role edit page the uniquely identifies the role (e.g., shortname). In the external database the name of the matching field.<br />
* The Roles panel specifies the role that the user will get in the course if their role is not specified in the external database.<br />
* A new optional field enrol_database | remoteotheruserfield allows those with the role "Other users" to be added but not to be included as course participants.<br />
* The final panel enables auto creation of courses.<br />
* Save changes, and then tick the box to enable external database enrolment.<br />
<br />
== Field Mapping Example: ==<br />
Choose your fields from the Moodle database:<br />
<br />
*enrol_localcoursefield: A course identifier from mdl_course, e.g. "idnumber"<br />
*enrol_localuserfield: A user identifier from mdl_user, e.g. "idnumber"<br />
*enrol_localrolefield: (optional) A role identifier from mdl_role, e.g. "shortname"<br />
<br />
Create a view in your external database which matches the chosen field values from Moodle:<br />
<br />
*enrol_remotecoursefield: A matching course identifier from your external database table, e.g. "course_number"<br />
*enrol_remoteuserfield: A matching user identifier from your external database table, e.g. "userid"<br />
*enrol_remoterolefield: (optional) A matching role identifier from your external database table, e.g. "role_name"<br />
<br />
== Potential gotchas ==<br />
<br />
* It almost goes without saying that the integrity of the external database is important. If data is missing from the database then there is a potential for users being unenrolled from some or all of their courses. The unenrollment process will remove them from any group assignments and also poll each module type to give the module the option of removing that user's data if appropriate (for example, however, forum posts are never deleted). It is therefore prudent that you take the utmost care to ensure that the data in the external database is correct at all times.<br />
* '''Minor Security Issue''' Consider that if the ID number field you use to identify your students is editable by the students (in their profile), then there is a potential for them changing this to the id of another valid student and gaining access to resources that they should not. (However, they will still appear as themselves, they cannot impersonate the other user or otherwise gain access to their resources.) To prevent this and similar issues, you can lock the ID number as well as other fields so the user can not change them. Do this in the '''Data mapping''' section of ''Site administration > Plugins > Authentication > External database''.<br />
<br />
==Errors and diagnostics==<br />
<br />
The plugin produces a number of diagnostic messages and/or errors which are recorded to the PHP error log (as defined in the php.ini file). In addition messages about courses that are in the database for the user but that do not exist in the Moodle site will only be produced if debugging is set to ALL or DEVELOPER.<br />
<br />
You can get detailed progress information by executing the sync script with -v parameter:<br />
<br />
<code><br />
php /path/to/moodle/enrol/database/cli/sync.php -v<br />
</code><br />
<br />
==See also==<br />
*Using Moodle [http://moodle.org/mod/forum/discuss.php?d=49475 MySQL enrolment plugin doesn't seem to work] forum discussion<br />
*Using Moodle [http://moodle.org/mod/forum/discuss.php?d=74133 Someone explain external database enrolment, please??] forum discussion<br />
*Example Setup [https://docs.moodle.org/en/Talk:External_database_enrolment#Example_External_Enrollment] Example Database Enrollment Setup<br />
*[[External database authentication]]<br />
<br />
[[es:Inscripción por BasedeDatos externa]]<br />
[[fr:Inscription par base de données externe]]<br />
[[de:Einschreibung über externe Datenbank]]<br />
[[ja:外部データベース登録]]</div>Foxhttps://docs.moodle.org/39/en/index.php?title=Assign_roles&diff=122222Assign roles2016-02-10T09:13:53Z<p>Fox: French link</p>
<hr />
<div>{{Roles}}<br />
==Context and roles==<br />
<br />
*In Moodle, apart from the site administrator, users do not normally have a global, site-wide role. In other words, even though you may be a tutor offline, when you are in Moodle you could have a tutor role in the course you teach in but a student role in another course where you are studying for a diploma. There are a few exceptions but this is generally the case.<br />
*Because of the way Moodle works,assigning roles is done for a particular context. A site and course are examples of two different contexts. When you create a new role or tweak a pre-existing role via ''Administration > Site Administration > Users > Permissions > Define roles'', you are asked in which context(s) you want the role to be assigned:<br />
[[File:rolecontexttypes.png]]<br />
<br />
*Here are some examples of contexts; how to get to the assign roles screen, and when/why you would assign roles here:<br />
<br />
===System context===<br />
*''Administration > Site Administration > Users > Permissions > Assign system roles''<br />
*Any roles assigned here apply to the whole Moodle site. It makes sense therefore that only roles that need this functionality can be assigned here. The [[Manager]] role and [[Course creator]] role are examples of two such roles. Assigning a teacher or student here would result in their being able to teach/study in every single course on the site, which is not usually desirable. <br />
*If you really feel your Moodle needs to have teachers or students assigned in the system context, go to the teacher/student role in ''Administration > Site administration > Users > Permissions > Define roles'' and check the "system" box. Then search for and allow the capability [[Capabilities/moodle/course:view|moodle/course:view]]<br />
<br />
=====Assigning system roles by CSV=====<br />
<br />
Where certain custom roles are applied in the system context, it is possible to upload users to that role in bulk by adding the field ''sysrole1'' (etc) to a CSV file.<br />
<br />
[[File:GlobalRoles1.png|thumb|500px|center|sysrole column]]<br />
<br />
When previewed, there is a column indicating their system role:<br />
<br />
[[File:GlobalRoles2.png|thumb|center|500px|Preview screen]]<br />
<br />
Once uploaded, the users are present on the 'Assign system roles' screen:<br />
<br />
[[File:GlobalRoles3.png|thumb|center|500px|Assign system roles screen]]<br />
<br />
See [[Upload users]] for information on adding users to roles via CSV.<br />
<br />
===Front page context===<br />
*''Administration > Site Administration > Front Page>Users>Permissions>Assigned roles<br />
*Those with a role in the system context do not need to be assigned a role here as well.<br />
*However you might want to allow a teacher to manage items on the front page; in this instance, you would assign them the role on the Front page.<br />
<br />
===Course Category context===<br />
*See [[Category enrolments]]<br />
*Users may be enrolled in the category to save enrolling them in each individual course in that category.<br />
<br />
===Course context===<br />
[[File:enrolusers.png|thumb|Enrol users]]<br />
* Go to ''Administration > Course administration > Enrolled users''<br />
* Click the "Enrol users" button and click those users you wish to enrol<br />
<br />
The dropdown menu at the top shows roles for which you are allowed to enrol; typically those users with lower roles than you. See [[Enrolled users]] for more details.<br />
<br />
===Block context===<br />
*(Within the block) ''Administration > Assign roles''<br />
*You may wish to assign roles to a block if, for instance you want specific people to see the block but for it to be hidden from others<br />
<br />
=== Activity Module context===<br />
*(Within the activity settings) ''Administration > Locally assigned roles''<br />
*An example of this is assigning a student the teacher role locally in an individual activity like a forum so they can moderate their classmates' posts while still retaining the student role in the rest of the course.<br />
<br />
===User context===<br />
*The most common use of this is for the Parent role. <br />
*When the Parent role is created via''Administration > Site administration > Users > Permissions > Define roles'' the "user" context box is checked.<br />
*To assign a parent the role in the context of their child (so they can see their child's grades etc) click the child's profile and then go to ''Administration>Roles>Assign roles relative to this user''<br />
*See [[Parent role]] for more information.<br />
<br />
The assign roles page lists the names of users assigned to each role (unless there are more than 10 users, in which case this is stated).<br />
<br />
==Hierarchy==<br />
<br />
By assigning a role to a user in a certain context, you grant them the permissions contained in that role for the current context and all lower contexts.<br />
<br />
The list of contexts in hierarchical order is as follows:<br />
<br />
*System (no parent)<br />
*Front page (parent = system) - <br />
*Course category (parent = parent category or system)<br />
*Course (parent = category or system)<br />
*Module (parent = course or system) <br />
*Block (parent = course or system)<br />
*User (parent = system)<br />
<br />
Roles can be inherited. For example if a user is assigned a Teacher role in a specific course category then the user will have this role in ALL courses within the category. Tip: use the override feature in a specific context for exceptions.<br />
<br />
Roles will only work if the role assignment is made in the correct context. Some examples: a Teacher role should be assigned to a user in the course or course category context, a Forum moderator for a particular forum should be assigned in that specific forum.<br />
<br />
==Assigning someone the role of Site administrator==<br />
<br />
*Site administrators are assigned via a special page: ''Administration > Site Administration > Users > Permissions > Site Administrators''. Select the name from the right and move it over to the left:<br />
[[File:managesiteadmins.png]]<br />
*The original (primary) administrator cannot be deleted.<br />
<br />
==Checking a user's role assignments==<br />
<br />
A user's role assignments can be checked by going to their profile page then in the administration block under the profile settings for the user, clicking 'This user's role assignments'.<br />
<br />
==Hidden roles==<br />
<br />
If you want to provide users with access to the course, but don't want them to be visible in the participants list, use the [[Other users]] link in the course administration menu (''Administration > Course Administration > Users > Other Users''). Assigning roles here provides course access, and editing rights according to the permissions set for the role assigned without actually enrolling the user in the course. This is similar to the functionality of the "hidden user" check box in previous versions of Moodle.<br />
<br />
Note: By default, the only role which can be assigned to other users is the manager role. To enable other roles, such as teacher to be assigned, the capability [[Capabilities/moodle/course:view|moodle/course:view]] should be allowed for the role (see below).<br />
<br />
==Enabling teachers to assign the role of teacher==<br />
<br />
By default, teachers are only allowed to assign the roles of non-editing teacher, student and guest. To enable teachers to assign the role of teacher:<br />
<br />
#Access ''Site Administration > Users > Permissions > Define roles''.<br />
#Click the tab "Allow role assignments".<br />
#Click the checkbox where the teacher row and column intersect.<br />
#Click the "Save changes" button.<br />
<br />
==Beware of assignments that don't make sense==<br />
<br />
There are many role assignments that do not make sense as the underlying functionality does not exist. Just because you give someone the "right" to do something does not guarantee that the interface or facility actually exists within the context that you have assigned that right. For example, you can assign a user the right to create new categories in the category context. However there is no interface within Moodle to do that (category creation is only available at the system level).<br />
<br />
==Multiple assignments==<br />
<br />
A significant part of the roles infrastructure is the ability to assign a user into multiple roles (at the same time). The capabilities of each role are merged to produce the effective set of capabilities. For example, a user could be both a Teacher and Student in the same course. You should be careful to ensure that if you change a user's role that you remove them from any other roles as required as this will no longer be done automatically.<br />
<br />
<br />
==See also==<br />
*[[Creating custom roles]]<br />
*[[Enrolment]]<br />
*[[Managing roles]] - for administrators<br />
*[[Useful things a teacher can do with roles]]<br />
<br />
Using Moodle forum discussions:<br />
*[http://moodle.org/mod/forum/discuss.php?d=59900 Discrepancies between Assign Roles lists and Participants list]<br />
*[http://moodle.org/mod/forum/discuss.php?d=66782 What happens if a user has multiple roles in a course?]<br />
<br />
[[Category:Roles]]<br />
<br />
[[de:Rollen zuweisen]]<br />
[[es:Asignar_roles]]<br />
[[eu:Rolak_esleitu]]<br />
[[fr:Attribution des rôles]]<br />
[[ja:ロールの割り当て]]</div>Fox