0

我有一个 SQL 问题。首先,我想知道仅使用 SQL 是否有可能,如果没有,是否有人知道一个好的解决方法。

我们正在建立一个网站,用户可以在其中为视频投票。
用户可以通过短信方式投票,也可以在Facebook认证后直接现场投票。
我们必须列出所有视频的顶部列表,并计算每个视频在列表中的“位置”。

到目前为止,我们已经通过一个简单的子查询完成了这项工作,如下所示:

SELECT v.video_id AS id, 
    (SELECT (COUNT(*)+1) FROM videos AS v2 
        WHERE (v2.SMS_votes + v2.facebook_votes) > (v.SMS_votes + v.facebook_votes)) AS total_position 
FROM videos AS v

SMS_votes并且facebook_votes是聚合字段。每种投票都有单独的表格,每个投票都有记录,包括投票的时间。

这很好用,位置是计算出来的......如果 2 个或更多视频具有相同的票数,他们会“分享”该位置。

不幸的是,不能共享位置,我们必须通过以下规则来解决它:

  • 如果两个视频的票数相同,短信票数多的视频有优势
  • 如果他们也有相同数量的短信投票,最后一小时短信投票多的有优势
  • 如果最后一小时的短信投票数也相同,则按前一小时进行比较,并如此递归,直到两者之间存在差异

是否可以仅在 SQL 中进行这种递归排序,或者我们必须在代码中手动解决这个问题?欢迎所有想法。请注意,性能在这里很重要,因为整个站点都在使用顶部列表。

4

1 回答 1

0

我认为用递归计算(这可能是无限的)执行这种排序是不可行的,但如果你愿意限制回顾的时间,有一些方法可以做到。

这是一种可能性。

SELECT video_id,
  SMS_votes + facebook_votes AS total_votes,
  SMS_votes,
  COUNT(CASE WHEN time > NOW() - INTERVAL 1 HOUR THEN 1 END) AS h1,
  COUNT(CASE WHEN time > NOW() - INTERVAL 2 HOUR THEN 1 END) AS h2,
  COUNT(CASE WHEN time > NOW() - INTERVAL 3 HOUR THEN 1 END) AS h3
FROM videos
JOIN SMS_votes USING(video_id)
GROUP BY video_id
ORDER BY total_votes DESC, SMS_votes DESC, h1 DESC, h2 DESC, h3 DESC;

这假设您有一个名为SMS_votes的表来跟踪每个投票,其中包含一个video_id字段和一个时间字段。

对于每个视频,它会计算过去一小时、过去两小时和过去三小时的总票数、短信票数、短信票数。然后它对ORDER BY所有这些值执行一个以获得正确的位置。

将其扩展到包括更广泛的时间范围是相当容易的,但您可能还想考虑在时间倒退时使用增加的时间范围。例如,您首先查看过去一小时内的投票,然后是过去一天,然后是过去一周等。我怀疑这会降低您获得相同投票的视频的机会,而无需添加尽可能多的额外计算。

SQL 小提琴示例

于 2013-07-04T17:38:49.717 回答