如何使用2个不同的ORDER BY语句形成MySQL查询

时间:2012-08-08 16:47:51

标签: mysql sql-order-by

我的网站上有一种Facebook式的喜欢/不喜欢的系统,并使用以下查询来获取特定帖子的喜欢和不喜欢:

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

$pid是要搜索的帖子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

2 个答案:

答案 0 :(得分: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,因为我看不出它们的原因。由于您只是从单个表中提取数据,因此您不应该有重复项。显然,您仍然可以添加它们,但请记住不要使用此类条款,除非确实需要它 - 第二个查询运行起来非常昂贵,因为它使用&#34;不等于&#34;条款。这意味着它不会使用索引,并且它不适合大量数据。如果您必须处理大表,则必须审查此解决方案。

答案 1 :(得分: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