按两个字段数的总和排序

时间:2011-03-22 12:08:49

标签: php mysql group-by sql-order-by

好的,我在这里遇到了一个有趣的问题。我有两个表,提示和投票。提示看起来像这样:

tip_id, challenge_id, user_id, ip_address, tip_date, tip_text

投票看起来像这样:

tip_id, ip_address, vote_date, vote

用户可以发布挑战提示,然后其他用户可以用拇指向上或向下对提示进行投票。投票中的投票字段是bool,0表示拇指向下,1表示拇指向上。挑战可以有任意数量的提示。

我一直绞尽脑汁,我无法让它发挥作用。我需要一个查询,可以获得特定提示的上下投票数,这两个数字的差异(因此如果有2个投票和1个投票,差异将是1)作为评级,还有从提示表中提示数据,然后先按最高评级对其进行排序。假设我们有两个提示,a和b:

a:3 up,2 down(diff:1) b:4上,1下(差异:3)

在这种情况下,b会首先出现,因为它的评级高于a,上下票数差异较大。

所以,例如,假设我有一个id为1的小费,其中有4个投票和2个投票,这意味着相差2,这个小贴士与挑战ID 5相关联,我的回报可能看起来像这样:

up | down | rating | tip_id | tip_date | user_id | tip_text
------------------------------------------------------------
3  | 2    | 1      | 1      | 12345678 | 1       | "this is a tip"

现在我已经能够做到这一点,但是如果有多个挑战提示,我遇到问题就是获得多行。假设挑战ID 5有两个提示,那么我应该得到这样的结果:

up | down | rating | tip_id | tip_date | user_id | tip_text
------------------------------------------------------------
3  | 2    | 1      | 1      | 12345678 | 1       | "this is a tip"
4  | 1    | 3      | 1      | 87654321 | 2       | "this is also a tip"

每个提示在结果中都有自己的行。现在正在发生的事情是我得到一行,其中上下值是该挑战的上下投票总数,而不是小费。因此,使用上面的第二个示例,而不是两个单独的行,我将得到一行,其值为7,向下为3,即该挑战的所有提示的向上和向下投票的总数。

我确信这将涉及加入和排序,以及分组,但我不关心查询有多复杂,我只是不想在PHP中这样做。最后,我想向查询提供挑战ID并让它获得X行,其中X是该挑战ID的提示数量,每行包含该提示ID的计数。

任何帮助都会受到赞赏,因为我的头发已用完了。不幸的是,这是我的项目的定义点,更高评级的提示需要在列表中显得更高。

编辑:这是我当前的,几乎正常工作的查询。经过一夜安眠后,我对它进行了一些调整,并使其大部分都有效,但仍然有一个我无法解释的问题:

SELECT
  COUNT(CASE WHEN V.vote = 1 THEN 'up' ELSE NULL END) AS up,
  COUNT(CASE WHEN V.vote = 0 THEN 'down' ELSE NULL END) AS down,
  (COUNT(CASE WHEN V.vote = 1 THEN 'up' ELSE NULL END)-COUNT(CASE WHEN V.vote = 0 THEN 'down' ELSE NULL END)) AS rating,
  T.*
  FROM votes V, tips T
  WHERE T.challenge_id = 10
  GROUP BY V.tip_id
  ORDER BY rating DESC

这可以获得我需要的一切,特定挑战的所有提示和投票,每个提示都有一个新行(而不是像以前那样的聚合计数)。问题是,我的上下投票,以及评级,是它应该是的两倍。因此,如果我有一个有3个投票和1个投票的小费,所以等级为2,这个查询将显示我有6个投票和2个投票评级为4.我想我可以简单地划分使用PHP编号为2,但这不能解决问题,它只是一个绑定。任何人都可以看到我为什么得到两倍的数量?我会继续搞乱它,也许尝试LEFT JOIN,希望我能弄明白,但是再多几双眼睛会很好。

2 个答案:

答案 0 :(得分:2)

这样的事情怎么样:

SELECT v.up, v.down, (v.up - v.down) AS rating, t.tip_id, t.tip_date, t.user_id, t.tip_text
FROM tips AS t
INNER JOIN votes AS v
ON t.tip_id = v.tip_id
WHERE challenge_id=1
ORDER BY rating DESC;

然后,您可以在将PHP传递给mysql之前在PHP中设置WHERE子句的challenge_id值。我认为这应该会给你你想要的东西,虽然因为我使用了INNER JOIN你需要确保“提示”中的每一行都有一行“投票”或者它会被忽略。

编辑:

基于新信息(对不起,我之前没有正确阅读过这个问题,希望这次我能说得对!):

 SELECT
  COUNT(CASE WHEN V.vote = 1 THEN 'up' ELSE NULL END) AS up,
  COUNT(CASE WHEN V.vote = 0 THEN 'down' ELSE NULL END) AS down,
  (COUNT(CASE WHEN V.vote = 1 THEN 'up' ELSE NULL END)-COUNT(CASE WHEN V.vote = 0 THEN 'down' ELSE NULL END)) AS rating,
  T.*
  FROM votes V
  INNER JOIN tips AS T
  ON T.tip_id = V.tip_id
  WHERE T.challenge_id = 1
  GROUP BY V.tip_id
  ORDER BY rating DESC;

我刚刚在SQLite3中测试了这个(在简化表上),它似乎工作正常。我使用的数据是:

sqlite> select * from votes
   ...> ;
tip_id      vote      
----------  ----------
2           1         
2           1         
2           1         
2           0         
2           0         
3           0         
3           0         
3           0         
3           1         
4           0         
4           0         
4           1         
4           1         
4           1         
4           1    

结果如下:

up          down        rating      tip_id      challenge_id  user_id   
----------  ----------  ----------  ----------  ------------  ----------
4           2           2           4           1             4         
3           2           1           2           1             2         
1           3           -2          3           1             3         

答案 1 :(得分:-1)

好的,我最终改变了ianhales provided并获得我想要的查询。随着他更新的wuery,我得到了正确的数量,但由于INNER JOIN,我没有获得没有投票的提示。我的改变很简单,但它们完美地运作:

SELECT
  COUNT(CASE WHEN V.vote = 1 THEN 'up' ELSE NULL END) AS up,
  COUNT(CASE WHEN V.vote = 0 THEN 'down' ELSE NULL END) AS down,
  (COUNT(CASE WHEN V.vote = 1 THEN 'up' ELSE NULL END)-COUNT(CASE WHEN V.vote = 0 THEN 'down' ELSE NULL END)) AS rating,
  T.*
  FROM tips T
  LEFT JOIN votes V
  ON T.tip_id = V.tip_id
  WHERE T.challenge_id = 10
  GROUP BY T.tip_id
  ORDER BY rating DESC

这会获得所有提示,即使他们没有投票,也会按降序排列 rating ,以便在列表中首先显示评分较高的提示。

你太棒了,你可以期待你的名字出现在我项目的学分中。非常感谢你。