Reputation: 5212
I have 2 MySQL tables, something like this:
categories:
+---------------+--------------------+
| id | category_name |
+---------------+--------------------+
| 1 | Category 1 |
| 2 | Category 2 |
+---------------+--------------------+
tasks:
+---------------+---------------------------+-----------------+
| id | task_name | category_id |
+---------------+---------------------------+-----------------+
| 1 | First task of the day | 1 |
| 2 | Then do this | 1 |
+---------------+---------------------------+-----------------+
This is a simplified version of my database, but you get the idea.
I want to display the category as a title followed the tasks below, for example:
Category 1
- First task of the day
- Then do this
Category 2
no tasks here :)
I'd be inclined to do something like this...
$query = $this->db->query("SELECT * FROM categories");
foreach($query->result() as $cat){
echo '<h1>'. $cat->category_name . '</h1>';
$tasks_query = $this->db->query("SELECT * FROM tasks WHERE category_id='{$cat->id}'");
foreach($tasks_query->result() as $task){
echo $task->task_name;
}
}
I know this would work, but it seems like it would be quite resource intensive with all those queries. So, I was wondering if this is the right way of doing this or is there a better, more efficient way. What would be the best practice way of doing this?
Hope all this makes sense.
Upvotes: 0
Views: 64
Reputation: 108500
You are quite right that there is some overhead with each query. The operations of sending the SQL text to the database server, the server parsing the statement for syntax, and then for semantics, developing an execution plan, then actually running the statement (obtaining locks, accessing blocks, releasing locks), preparing the resultset to send back to the client. And on the client side, checking the status, and retrieving the result.
In terms of just the database, it is usually more efficient to run a single statement to return a single resultset. (There are cases when it isn't, such as when the large query is inefficient, like when the resultset is really, really big, and requires an expensive sort operation.)
Example of how to get the result in one statement:
SELECT c.category_name
, t.task_name
FROM categories c
LEFT
JOIN tasks t
ON t.category_id = c.id
ORDER
BY c.category_name
, t.task_name
The flip side of that is there is some "extra" work that needs to be one on the client to process that.
initialize a variable to hold "previous" category_name
loop fetching rows (until no more rows)
if category_name is not equal to previous category_name
emit category e.g. output "<h1>category_name"
save new category_name as previous
end if
if task_name is not null
emit task e.g. output "<br>task_name"
end if
end loop
Upvotes: 1
Reputation: 5212
Thanks all for your answers and help. I looked more into MySQL joins and this is what I come up with and it works!...
$query = $this->db->query("
SELECT c.category_name, t.task_name
FROM categories c
INNER JOIN tasks t
ON c.id = t.category_id");
$categories = array();
foreach($query->result() as $result)
{
if ( !in_array($result->category_name, $categories) )
{
$categories[] = $result->category_name;
echo '<h3>' . $result->category_name . '</h3>';
}
echo "<div>" . $result->task_name . "</div>";
}
Upvotes: 0
Reputation: 306
If you use a join
in your SQL query it will put more of the burden on the database rather than the PHP engine (it'll be quicker and less resource-intensive, since you're running one query rather than many within a loop).
$query = $this->db->query(
'SELECT *
FROM tasks t
INNER JOIN categories c
ON t.category_id = c.id');
foreach ( $query->result() as $result) {
echo $result->category_name . ' ' . $result->task_name;
}
Upvotes: 1