2012-08-08 22 views
1

我有一種在我的網站的Facebook式的喜歡/不喜歡系統和現在用的是下面的查詢搶到喜歡的特定崗位+好惡:如何形成2種不同的順序MySQL查詢BY語句

SELECT DISTINCT * FROM posts WHERE cid='$cid' AND pid=".implode(" OR pid=",$pids)." ORDER BY time DESC 

$pid是要搜索的post ID的數組。

zbid是當前正在訪問該頁面的用戶的ID。現在,如果該用戶評價(喜歡/不喜歡)該帖子,他的結果應該首先返回,然後在那之後通過time DESC訂購結果。

我該如何去修改查詢來做到這一點?

如果posts表具有以下數據:

 
+----+-----+------+-----+--------+------+ 
| id | cid | zbid | pid | rating | time | 
+----+-----+------+-----+--------+------+ 
| 1 | 1 | 1 | 1 | 1  | 1 | 
+----+-----+------+-----+--------+------+ 
| 2 | 1 | 2 | 1 | -1  | 4 | 
+----+-----+------+-----+--------+------+ 
| 3 | 1 | 3 | 2 | 1  | 2 | 
+----+-----+------+-----+--------+------+ 
| 4 | 2 | 4 | 1 | -1  | 3 | 
+----+-----+------+-----+--------+------+ 
| 5 | 1 | 5 | 1 | 1  | 8 | 
+----+-----+------+-----+--------+------+ 
| 6 | 1 | 6 | 1 | -1  | 7 | 
+----+-----+------+-----+--------+------+ 

目前的select語句(上圖)將返回以下信息(與$pid = array(1);):

 
+----+-----+------+-----+--------+------+ 
| id | cid | zbid | pid | rating | time | 
+----+-----+------+-----+--------+------+ 
| 5 | 1 | 5 | 1 | 1  | 8 | 
+----+-----+------+-----+--------+------+ 
| 6 | 1 | 6 | 1 | -1  | 7 | 
+----+-----+------+-----+--------+------+ 
| 2 | 1 | 2 | 1 | -1  | 4 | 
+----+-----+------+-----+--------+------+ 
| 4 | 2 | 4 | 1 | -1  | 3 | 
+----+-----+------+-----+--------+------+ 
| 1 | 1 | 1 | 1 | 1  | 1 | 
+----+-----+------+-----+--------+------+ 

但是,如果人用zbid=4正在訪問該頁面,它應該將該結果(如果存在)提升至頂端,如下所示:

 
+----+-----+------+-----+--------+------+ 
| id | cid | zbid | pid | rating | time | 
+----+-----+------+-----+--------+------+ 
| 4 | 2 | 4 | 1 | -1  | 3 | 
+----+-----+------+-----+--------+------+ 
| 5 | 1 | 5 | 1 | 1  | 8 | 
+----+-----+------+-----+--------+------+ 
| 6 | 1 | 6 | 1 | -1  | 7 | 
+----+-----+------+-----+--------+------+ 
| 2 | 1 | 2 | 1 | -1  | 4 | 
+----+-----+------+-----+--------+------+ 
| 1 | 1 | 1 | 1 | 1  | 1 | 
+----+-----+------+-----+--------+------+ 

變量$zbid設置爲正在訪問該頁面的用戶的zbid

+0

請再次編輯你的問題,並添加一些sammple數據和數據的查詢後所需要的輸出,所以這是一個更清楚你想要做什麼。謝謝。 :-) – 2012-08-08 17:28:56

回答

1

這是一個相當粗糙的解決方案,我可以拿出,使用您提供的信息:

解決方案1 ​​ - 便攜式方式

-- This query will return User's posts and give it a higher priority in ordering, via post_order field 
SELECT 
    posts.* 
    ,0 as post_order 
FROM posts 
WHERE 
    (cid='$cid' AND pid=".implode(" OR pid=",$pids).") AND 
    (zbid = $user_zbid) 

UNION ALL 

-- This query will return everything BUT User's posts and give it a lower priority in ordering 
SELECT 
    posts.* 
    ,1 as post_order 
FROM posts 
WHERE 
    (cid='$cid' AND pid=".implode(" OR pid=",$pids).") AND 
    (zbid <> $user_zbid) 
ORDER BY 
    post_order -- This clause will put User's posts before the others 
    ,time DESC 

解決方案2 - 將更多的表演方式(學分cbranch您的建議)

SELECT 
    posts.* 
    ,IF(zbid = $user_zbid, 0, 1) as post_order 
FROM posts 
WHERE 
    (cid='$cid' AND pid=".implode(" OR pid=",$pids).") 
ORDER BY 
    post_order -- This clause will put User's posts before the others 
    ,time DESC 

筆記
- 正如您可能已經注意到的那樣,我從SELECT中刪除了DISTINCT,因爲我看不到它們的原因。既然你只是從一個表中提取數據,你不應該有重複。顯然,你仍然可以將它們添加回去,但是除非真的需要,否則請記住不要使用這樣的子句。
- 第二個查詢運行起來非常昂貴,因爲它使用「不等於」子句。這意味着它不會使用索引,並且不適合大量的數據。如果你不得不處理一個大桌子,這個解決方案將不得不被審查。

+0

我想你可以用一個查詢來做同樣的事情並避免使用'UNION ALL'。 'SELECT IF(zbid = $ user_zbid,0,1)AS post_order' – cbranch 2012-08-08 18:52:05

+0

確實如此,但它的便攜性會降低。我傾向於儘可能地堅持使用ANSI SQL。:) 但是,'IF()'子句將避免討厭的「不等於」子句,這將是一個很大的優勢。 – Diego 2012-08-08 18:58:10

+0

@cbranch我編輯了答案,加上你的建議,連同應有的學分。 – Diego 2012-08-08 19:01:32

0

審查迭戈的建議後,我想出了以下的答案已工作:

SELECT zbid,pid,rating,0 as post_order,time 
    FROM posts 
    WHERE cid='$cid' 
     AND (pid=".implode(" OR pid=",$pids).") 
     AND zbid!='$zbid' 
UNION 
SELECT zbid,pid,rating,1 as post_order,time 
    FROM posts 
    WHERE cid='$cid' 
     AND (pid=".implode(" OR pid=",$pids).") 
     AND zbid='$zbid' 
ORDER BY 
    post_order DESC, 
    time DESC