Tutorial
A Solution to Group Limit Problem, PHP/MySQL
by Void | in PHP | posted October 19, 2006
![]()
![]()
![]()
![]()
(1 vote) | 1584 views
Using relational summary table to track posts per category simulating a group limit clause in MySQL.
Add to del.icio.us |
Digg this |
Dot This
One solution to this problem is to load arrays of limited categories within PHP, presenting them one after another on some summary page. Sometimes that is not adequate and another solution is required using temporary summary tables. Such tables can be in memory only, created each time a summary is created, or can be permanent, updated with each change to the tables that contain data for such summary table. The later is recommended for heavy production environments that cannot afford summary table creation on each summary page view.
These summary tables are relational and can be made of fixed size reducing overhead and speed degradation with many updates to such tables.
How does one such table look? Let's say for example that you have a table of blog posts and you need to create a summary of last 10 posts per each category.
table_posts
- primary_key
- category_id
- author_id
- post_title
- post_body
- time_stamp
- ... other fields relevant for the post
The relational summary table would then look like this:
table_posts_summary
- category_id
- post_id (primary_key in table_posts)
- time_stamp (timestamp of the post)
Now, each time an author submits new post, you need to do a couple of things, in steps:
- Insert entire post into table_posts, with given category
- If there are any rows for given category in table_posts_summary, delete them
- Select last 10 posts from table_posts, with given category, ordered by timestamp descending
- Insert category_id, post_id and timestamp for each of the last 10 posts you just selected
With this we recreate last ten entries, sorted by descending timestamp, in the table_posts_summary. At first glance it may appear expensive with so many queries per new post, but consider how often do your authors make new posts? And then consider how many views per second you may have on your summary page?
Finally, when you need to select last 10 posts for each category, you simply select all rows in tbl_posts_summary and present them in your summary page. You can add simple joins on category_id and post_id to fetch category and post titles or other relevant data.
A more concrete example in form of a function. Since this is just an example, it stores limited information per post:
PHP:
<?php
function addPost($author_id, $category_id, $title, $body) {
$title= mysql_real_escape_string ($title);
$body= mysql_real_escape_string ($body);
//First, let's insert the post into main table
$res= mysql_query ("INSERT INTO table_posts
(category_id, author_id, time_stamp, post_title, post_body) VALUES
($category_id, $author_id, UNIX_TIMESTAMP(), '$title', '$body')";
// First, let's dump any entries for given category in the summary table
$res=mysql_query("DELETE FROM table_posts_summary WHERE category_id=$category_id");
//Now, let's select primary keys and timestamps of last ten posts in the category
$res= mysql_query ("SELECT primary_key, time_stamp FROM table_posts
ORDER BY time_stamp DESC LIMIT 10";
$num= mysql_num_rows($res);
//And insert the fresh batch of last ten posts selected at the beginning
for ($i=0; $i<$num; $i++) {
$row= mysql_fetch_row ($res);
$res2= mysql_query("INSERT INTO table_posts_summary (category_id, post_id, time_stamp)
VALUES ({$category_id}, {$row[0]}, {$row[1]})");
}
}
?>
Eventually, the code to retrieve last 10 posts per category is very simple. Example given here joins tables to retrieve category name and post title as well:
PHP:
<?php
// ...
$res= mysql_query('SELECT t1.*, t2.category_name, t3.post_title
FROM tbl_posts_summary AS t1
LEFT JOIN table_categories AS t2 ON t2.primary_key=t1.category_id
LEFT JOIN table_posts AS t3 ON t3.primary_key=t1.post_id
ORDER BY t2.category_name, t1.time_stamp');
$num= mysql_num_rows($res);
for ($i=0; $i<$num; $i++) {
// fetch rows and echo data
}
// ...
?>

