2013-10-08 105 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,包含所有帖子。 –

相關問題