how to write the SQL queries in moodle friendly code

how to write the SQL queries in moodle friendly code

by Mark Lloyd -
Number of replies: 28

I’m a newbie to Moodle and PHP so forgive me if I’m not making much sense

I want to create a block which will search a table in the database (which I have already created) and display the results from the search in a new page.

I have created some PHP code (from phpMyAdmin) of the queries that I wish to run but i don’t know how to write these queries within Moodle

The first one is

$sql = 'SELECT * FROM `mdl_block_archive` WHERE `title` LIKE \'%HTML%\' LIMIT 0, 30 ';

Where the LIKE clause is (\'%HTML%\) I would want to refer to the data from the form that the user has input

The second one is

$sql = 'SELECT * FROM `mdl_block_archive` WHERE `category` = \'Computing\' LIMIT 0, 30 ';

Any help please

Many thanks

Mark

Average of ratings: -
In reply to Mark Lloyd

Re: how to write the SQL queries in moodle friendly code

by Leo Dil -
you can use the Moodle Libraries like: dmllib.php
In reply to Mark Lloyd

Re: how to write the SQL queries in moodle friendly code

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers
You need to use the functions is lib/dmllib.php.

For example your second query is

$archives = get_records('block_archive', 'category', 'Computing', '', '*', 0, 30);

By the way, doing LIMIT 0, 30 is going to return 30 records at random. Shouldn't you be specifying an order-by?

So, get_records gets records with a WHERE like x = y.

For your first query, you need something more complex, so you use

$archives = get_records('block_archive', "title LIKE '%HTML%'", '', '*', 0, 30);


By the way, don't put backticks around the column and table names. That is MySQL-only, and Moodle code should work on all our supported databases.

To help that, there are a bunch of functions whose name start with sql_, for example sql_concat, which creates bits of SQL syntax that differ between databases.


Finally, if you want a really complex query like a JOIN, then you need to user get_records_sql. With that, you need to give the full SQL, and then you need to use {$CFG->prefix} for the mdl_ bit, which is set in config.php.


dmllib.php has pretty good PHPdoc comments. The other way to work out how to use these functions is to search the code for other places where they are used, and copy what you see there.
Average of ratings: Useful (1)
In reply to Tim Hunt

Re: how to write the SQL queries in moodle friendly code

by Mark Johnson -
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers
Should that second "get_records()" be a "get_records_select()" ?
In reply to Mark Johnson

Re: how to write the SQL queries in moodle friendly code

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers
Oops! yes. Copy and paste error. Thank you for noticing.
In reply to Tim Hunt

Re: how to write the SQL queries in moodle friendly code

by Mark Lloyd -
Hi Guy's,

Thanks for your replies. Ill try what you said and update later what i find.

Forgive me if im asking help for such a basic question but i'd rather find out now than work on somethng and be wrong.

Another question is that i am creating a block with a search box, which the user can input a search a criteria. that block then redirects you to the search code page, now can i have the code to search the database and the output on the same page or is it best to have the search page code redirecting you to an output page.

Tim i was not sure what the LIMIT 0, 30 bit of the SQL meant, that was just created when i was using phpMyAdmin to build the SQL code. so if this means to limit 30 random records can this just be left out compleatly. so the queries would be

$archives = get_records('block_archive', 'category', 'Computing', '', '*');

and

$archives = get_records_select('block_archive', "title LIKE '%HTML%'", '', '*');

if i can leave the limit bit off have i cut the code off in the correct place.

Again thanks for the replies

Mark
In reply to Mark Lloyd

Re: how to write the SQL queries in moodle friendly code

by Mark Lloyd -
sorry the second query should be
get_records_select('block_archive', "title LIKE '%HTML%'", '', '*')

One more thing is that the second query where the %HTML% is will be the search criteria that the user inputs, which in the block is $searchcriteria. so am i correct in saying that this would then be

get_records_select('block_archive', "title LIKE '% "$searchcriteria" %'", '', '*')

again many thanks

Mark
In reply to Mark Lloyd

Re: how to write the SQL queries in moodle friendly code

by sam marshall -
Picture of Core developers Picture of Peer reviewers Picture of Plugin developers
your syntax is a little wrong with extra quotes but otherwise looks ok:

get_records_select('block_archive', "title LIKE '%$searchcriteria%'", '', '*')

IF you are certain that you have already restricted the input value so that it does not contain, or escapes, SQL special characters such as ' and in this case %. (This could be done with moodle require_param with PARAM_something_appropriate, or a regular expression in addition to a require_param check.)

Make sure to test that it works with these characters ('works' = rejects input, or otherwise behaves correctly); otherwise you might be introducing a critical security flaw.

--sam


In reply to sam marshall

Re: how to write the SQL queries in moodle friendly code

by Peter Lai -
Good to know that get_records_select does not perform sanity checking to prevent SQL injection. Ahh PHP, how I loathe thee....
In reply to Mark Lloyd

Re: how to write the SQL queries in moodle friendly code

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers
The LIMIT 0, 30 bit tells the database to only return no more than 30 records. Useful protection against a query returning millions or records and filling the server's memory. Anyway, safe to omit it if you know the most data that could be returned.

If you are omitting those, you can shorten the line even more, to

$archives = get_records('block_archive', 'category', 'Computing');

because '' and '*' are the default values of the next two parameters.
In reply to Tim Hunt

Re: how to write the SQL queries in moodle friendly code

by Mark Lloyd -
Hi all,

Thanks for the replys.

so if i use the $archives = get_records('block_archive', 'category', 'Computing'); code to get the data from the table. how do i then display the records from that search.
In reply to Mark Lloyd

Re: how to write the SQL queries in moodle friendly code

by sam marshall -
Picture of Core developers Picture of Peer reviewers Picture of Plugin developers
print_object($archives);

JOB DONE

seriously do stick that in first so you can see what you're getting back. once you get to that point, if you don't know it already you basically just need to go away and learn enough php to be able to print them out how you want - there isn't anything Moodle-specific unless you want to use Moodle UI elements (eg Moodle has a feature for doing tables, and for printing help buttons, and stuff like that - see weblib.php).

--sam
In reply to sam marshall

Re: how to write the SQL queries in moodle friendly code

by Mark Lloyd -
thanks for the reply sam.

Ill try that then work on the layout after.

mark
In reply to Mark Lloyd

Re: how to write the SQL queries in moodle friendly code

by Mark Lloyd -
Hi all,

I’m new to Moodle, and have little coding experience resulting in my struggle to develop anything.

I was wondering if you could give me some pointers on where I’m going wrong. I have been trying different things out but don’t understand exactly what I’m doing.

Basically I have a block which has a text box for the user to input search criteria, this form is linking to a search.php page which should run the query and display the results. As far as I can tell the input from the form is being passed to the search.php page as it is displayed URL.

before I put my code in I thought that I’d just say that i may have little or no code that actually does what I think it should be doing but I am still trying to learn so if you could give me any advice I will be very grateful.

The code for my block is as follows

<?php

class block_moodle_archive extends block_base {

function init() {
$this->title = get_string('formaltitle', 'block_moodle_archive');
$this->version = 2010042000;
}

function instance_allow_config() {
return true;
}


function get_content() {
global $CFG, $THEME;

if($this->content !== NULL) {
return $this->content;
}

$this->content = new stdClass;
$this->content->footer = '';

if (empty($this->instance)) {
$this->content->text = '';
return $this->content;
}

$button = get_string('go', 'block_moodle_archive');
$search = get_string('search', 'block_moodle_archive');


$this->content->text = '<div class="searchform">';
$this->content->text .= '<form action="'.$CFG->wwwroot.'/blocks/moodle_archive/search.php" method="post"><fieldset class="invisiblefieldset">';
$this->content->text .= '<input name="id" type="hidden" value="'.$this->instance->pageid.'" />'; // course id
$this->content->text .= '<label class="accesshide" for="searchform_search">'.$titlesearch.'</label>'.
'<input id="searchform_search" name="search" type="text" size="16" />';
$this->content->text .= '<button id="searchform_button" type="submit" title="'.$titlesearch.'">'.$button.'</button><br />';
$this->content->text .= '</fieldset></form></div>';

return $this->content;
}


function applicable_formats() {
return array('site' => true, 'course' => true);
}

}
?>



then the code from my search.php page is

<?php

// includes and requires
require_once('../../config.php');

$titlesearch = trim(optional_param('search', '', PARAM_NOTAGS)); // search string

$sSQL = get_record('block_archive', 'title', '%$titlesearch%');



$rsarchive = $sSQL;

if(!$rsarchive->EOF)
{
while (!$rsarchive->EOF)
{
$str_id = $rsarchive->Fields("id")->value;
$str_courseid = $rsarchive->Fields("courseid")->value;
$str_title = $rsarchive->Fields("title")->value;
$str_category = $rsarchive->Fields("category")->value;
$str_description = $rsarchive->Fields("description")->value;
$str_url = $rsarchive->Fields("url")->value;

?>

<table width="100%" cellpadding="2" cellspacing="2" border="0">
<tr valign="top">
<td width="25%"><h3>.: Title</h3></td>
<td colspan="25"><h3>.: Category</h3></td>
<td width="25%"><h3>.: Description</h3></td>
<td width="25%"><h3>.: URL</h3></td>
</tr>
</table>

<table width="100%" cellpadding="2" cellspacing="2" border="0">
<tr valign="top">
<td width="25%" height="23"><?php echo $str_title?></td>
<td colspan="25"><?php echo $str_category?></td>
<td width="25%"><?php echo $str_description?></td>
<td width="25%"><?php echo $str_url?></td>
</tr>
</table>


any pointers please (apart from the obvious GIVE UP!!)

thanks

Mark

In reply to Mark Lloyd

Re: how to write the SQL queries in moodle friendly code

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers
$sSQL = get_record('block_archive', 'title', '%$titlesearch%');

is definitely wrong. You need to understand the difference between "" and '' in PHP, and you need to use get_records_select (correctly).

You also need to do the right thing with the result you get from that. Is is not a recordset, or anything like that, so any sort of while ->EOF is just plain wrong.

Try doing print_object, or var_dump, or what you get back from get_records_select to find out what you have got. (It should be a PHP array of objects.)
In reply to Mark Lloyd

Re: how to write the SQL queries in moodle friendly code

by Hubert Chathi -
For starters, it would help if you tell us what problems you are having.

Secondly, get_record returns an array, so you don't check $rsarchive->EOF, since that is undefined. (Also, doing $rsarchive = $sSQL; doesn't accomplish much -- just use $sSQL directly -- although you should use a more descriptive name.) To iterate through an array, you want to do a foreach loop.
In reply to Hubert Chathi

Re: how to write the SQL queries in moodle friendly code

by Mark Lloyd -
Thanks for the replys.

Hi Tim,
The line that is wrong what i was trying to do is assign the value of the text box from the block. how would i do this??
$sSQL = get_record('block_archive', 'title', '%$titlesearch%');


Hi Hubert,
Im getting a blank white page when i press the button on the block.


so for the for each loop would this be something like

foreach ($archives as $archive) {
$action = print_action('title', $archive->title) .
print_action('category', $archive . $archive->category) .
print_action('description', $archive . $archive->description);
print_action('url', $archive . $archive->url);
}

Thanks again for any help.
In reply to Mark Lloyd

Re: how to write the SQL queries in moodle friendly code

by Hubert Chathi -
Turn on developer debugging, and see if it spits out any error messages. Go to the Site Administration block, under Server > Debugging, and set "Debug messages" to DEVELOPER, and set "Display debug messages" to Yes.
In reply to Mark Lloyd

Re: how to write the SQL queries in moodle friendly code

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers
$archives = get_records_select('block_archive', "title LIKE '%$titlesearch%'");

The foreach looks about right.

By the way, have you found http://dev.moodle.org/?
In reply to Tim Hunt

Re: how to write the SQL queries in moodle friendly code

by Mark Lloyd -

Hi all

this is the foreach loop that i have in my code

foreach ($archives as $archive) {
    $action = print_action('title', $archive->title) .
    print_action('category', $archive . $archive->category) .
    print_action('description', $archive . $archive->description);
    print_action('url', $archive . $archive->url);

but this loop is giving me an error

Fatal error: Call to undefined function print_action() in C:\Moodle\ on line 28

line 28 is the red line

can enyone help please

thanks

mark

In reply to Mark Lloyd

Re: how to write the SQL queries in moodle friendly code

by Hubert Chathi -
PHP doesn't know about the print_action function (and it doesn't seem to be a standard Moodle function), so you either need to define the function, or use a different function.
In reply to Hubert Chathi

Re: how to write the SQL queries in moodle friendly code

by Mark Lloyd -

Thanks hubert, how do i define the function for print then. im not sure what you need to do.

Is there not a print function already defined within a moodle lib page anywhere??

Thanks

Mark

In reply to Mark Lloyd

Re: how to write the SQL queries in moodle friendly code

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers
I think you should read a basic PHP tutorial about how to output HTML. There are plenty on the web. For example http://www.php.net/manual/en/tutorial.php
In reply to Tim Hunt

Re: how to write the SQL queries in moodle friendly code

by Lavanya Manne -
Picture of Plugin developers

Hi Tim Hunt,

I have a table 'course' with field 'fullname' and I want to import this fullname into select tag by passing with an array and upto this its working, but i want the fullname to get displayed in alphabetical order and here is my code

$courseoptions = array();
$courseoptions[0] = get_string('All','block_configurable_reports');

if(!empty($courselist))
{
$courses = get_records_select('course',$sort='fullname','id in ('.(implode(',',$courselist)).')');

foreach($courses as $c)
{
$courseoptions[$c->id] = format_string($c->fullname);               
}
}

$mform->addElement('select', 'filter_courses', get_string('course'), $courseoptions);
$mform->setType('filter_courses', PARAM_INT);

I think we need to modify the above green color line of code

In reply to Tim Hunt

Re: how to write the SQL queries in moodle friendly code

by Lavanya Manne -
Picture of Plugin developers

Hi Tim Hunt,

I want my query to sort by alphabetical order and here is my query

$courses = get_records_select('course','id in ('.(implode(',',$courselist)).')');

In reply to Lavanya Manne

Re: how to write the SQL queries in moodle friendly code

by Justin Wyllie -

Hi Lavanya

I'm not Tim Hunt. I'm sure he won't mind my replying in his stead.

According to the function definition it is the 4th param so something like:

$courses = get_records_select('course','id in ('.(implode(',',$courselist)).')', null, 'fullname'); //or shortname

It's just me but personally I'd construct my IN clause on a separate line - just to make it easier to see what is going on. (But that may just be me).

Justin Wyllie

 

 

 

In reply to Justin Wyllie

Re: how to write the SQL queries in moodle friendly code

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

get_records_list is even better for this sort of query. Look at the full API docs. There should be a $orderby parameter.

In reply to Justin Wyllie

Re: how to write the SQL queries in moodle friendly code

by Lavanya Manne -
Picture of Plugin developers

Hi Justin Wyllie,

not an issue, but need suggestions!!!!

I didn't get your syntax exactly???

I have two tables 'course' and 'enroll' where i have a field (courseid) in enroll table matching with the field (id) in the course table and all the course names in Alphabetical order and my query looks like this

'SELECT c.fullname FROM mdl_reenroll r, mdl_course c WHERE r.courseid = c.id GROUP BY c.id ORDER BY c.fullname'

but the same query, to implement in moodle under the code line with green color.

here is my code

$courseoptions = array();
$courseoptions[0] = get_string('All','block_configurable_reports');

if(!empty($courselist))
{
$courses = get_records_select('course',$sort='fullname','id in ('.(implode(',',$courselist)).')');

foreach($courses as $c)
{
$courseoptions[$c->id] = format_string($c->fullname);               
}
}

$mform->addElement('select', 'filter_courses', get_string('course'), $courseoptions);
$mform->setType('filter_courses', PARAM_INT);

I think we need to modify the above green color line of code with conditions as well as in alphabeticla order.

In reply to Lavanya Manne

Re: how to write the SQL queries in moodle friendly code

by Justin Wyllie -

Hi Lavanya

Ah. i didn't realise you were doing a join on two tables. AFAIK that means you'll need to use a generic type functiion basically to pass your own sql e.g.

get_records_sql($sql);

Try that and var_dump the result to see what structure it is in.

I'm not sure why your SQL has a group by on it? You are not trying to use any aggregate functions I think? But I may well be missing something here.

Note that that function requires you return a unique col so tentatively I'd try this:

$sql = 'SELECT c.id, c.fullname FROM mdl_reenroll r, mdl_course c WHERE r.courseid = c.id ORDER BY c.fullname'

$result = get_records_sql($sql);

But I'm no expert on Moodle & there may be a method for doing JOINS on tables. If so it'd be better to use that.

regards

Justin