2013-10-08 130 views
0

在我的论坛上的帖子都有一个人的固定链接。确定页面从帖子固定链接分页论坛

帖子分页,用户可以按日期和评分排序。

访问固定链接时,由于分页,需要计算帖子所在的页面。

帖子存储在一个MySQL innodb表中自动递增的id。

在我使用下面的计算时的职位是由他们的分数(等级)排序的时刻:

<?php 

    // These variables originate from the corresponding uri segments 
    // For example: http://domain.tld/topics/[ID]/[SLUG]/[POST_ID] 
    $post_id = $uri->segment(4); 
    $topic_id = $uri->segment(2); 

    $post_per_page = 10; 

    $query = $db->query('SELECT id FROM topic_posts WHERE topic_id = ' . $topic_id . ' ORDER BY score desc'); 

    foreach ($query as $key => $post) 
    { 
     if ($post->id == $post_id) 
     { 
      $postOnPage = ceil(($key + 1)/$post_per_page); 
      break; 
     } 
    } 

然而,帖子的数量会不断增加,并获取所有帖子似乎很尴尬。

对于日期排序我使用下面的查询,但它不工作的等级排序的职位ID是那么不递增顺序:

SELECT CEIL((COUNT(*) + 1)/$posts_per_page) FROM topic_posts WHERE topic_id = $topic_id AND id < $post_id; 

所以...我如何避免PHP foreach循环,并实现与db查询相同?

+0

我相信你应该重新思考你的问题。使用两种排序模式的帖子*是否重要?我会考虑一个选项来简化事情,并且在处理永久链接时总是使用order-by-date。 –

+0

强迫排序为'日期'是我想要解决问题的一件事。但是,这些回复位于每个包含原始帖子的_permalink_的帖子下方。所以当访问这样的固定链接时需要保持排序。 StackOverflow与他们的排序_tabs_具有相同的功能。不过谢谢你的建议! –

回答

1

我刚刚有一个完全不同的方法的想法,所以我把它添加为第二个答案,而不是编辑第一个。

为了达到预期的效果,您总是必须在排序中至少包含一个唯一列作为决胜者。我假设你的许多帖子实际上会有相同的评级,所以也许你应该例如ORDER BY score DESC, id DESC额外订购与最新第一次相同评级的帖子(我认为这对于论坛来说可能是有意义的)。

那么对于上面提到的排序顺序,就可以得到职位数排序之前的帖子中的问题与下面的查询:

SELECT COUNT(1) FROM topic_posts 
    WHERE topic_id = $topic_id 
     AND ((score > $post_score) OR (score = $post_score AND id > $post_id)); 

这是可以优化使用indizes等查询如所须。

+0

我喜欢你的热情:-)这似乎会带来解决方案。我会看看它,并告诉你它是否有帮助。 –

+0

太棒了!这按预期工作。顺便说一句:'COUNT(1)'实际上与'COUNT(*)'相同 - 更多细节在这里http://stackoverflow.com/q/1221559/2493918。 –

1

可以在查询中生成一个虚假的“行号”,然后可以用它来计算帖子将出现在的页面。但是,根据您的架构和表大小,此查询可能会变得非常昂贵,因此请务必检查性能。

我认为这是最好的一个示范描述:

一表的结构和一些测试数据:

mysql> CREATE TABLE foo (a VARCHAR(10)); 
mysql> INSERT INTO foo VALUES ("foo"), ("bar"), ("baz"); 

连接返回与他们的行号的一些订单的所有结果的查询:

mysql> SELECT f.*, @rownum := @rownum+1 AS rank FROM foo f, (SELECT @rownum := 0) r ORDER BY f.a; 
+------+------+ 
| a | rank | 
+------+------+ 
| bar | 1 | 
| baz | 2 | 
| foo | 3 | 
+------+------+ 
3 rows in set (0.00 sec) 

然后,您可以使用此只选择特定的行:

mysql> SELECT * FROM (SELECT f.*, @rownum := @rownum+1 AS rank FROM foo f, (SELECT @rownum := 0) r ORDER BY f.a) t WHERE a = "foo"; 
+------+------+ 
| a | rank | 
+------+------+ 
| foo | 3 | 
+------+------+ 
1 row in set (0.00 sec) 

实质上,您正在将内部编号查询包装在只选择想要的结果行的外部查询中。正如你所看到的rank仍然和“所有结果”一样,所以现在可以使用这个行号来计算你的结果页面。

如果你想分页上只有所有记录的子集在表中(例如,在一个特定的论坛所有帖子),对应WHERE子句进入内选取的ORDER BY是:

mysql> SELECT * FROM (SELECT f.*, @rownum := @rownum+1 AS rank FROM foo f, (SELECT @rownum := 0) r WHERE a != "baz" ORDER BY f.a) t WHERE a = "foo"; 
+------+------+ 
| a | rank | 
+------+------+ 
| foo | 2 | 
+------+------+ 
1 row in set (0.00 sec) 

缺点是它实际上必须迭代所有记录(以及与内部WHERE子句匹配的所有记录),所以对于大型表来说它变得非常慢。

+0

**感谢您的详细回答,'+ 1'。**这实际上回答了我如何将PHP foreach循环移动到mysql查询中的问题。然而,我期待的主要事情是具有大量数据库数据的性能。您在说自己这个解决方案对大型表格而言是资源密集型的。我能否以某种方式改变我的存储或提取帖子数据的概念,以减少重复/重复的处理,从而提高整体性能? *顺便说一句:*我有两个论坛帖子的表格 - 1)所有主题元的主题作为枢纽2)topic_posts,包含所有帖子。 –

相关问题