我的votes
表格如下:
id: integer
vote: boolean
voteable_id: integer
voteable_type: string
voter_id: integer
voter_type: string
vote
列确定该行是代表“向上投票”(vote = true
)还是“向下投票”(vote = false
)。
voteable_type
是被投票的内容的类,voteable_id
是被投票的内容的ID,voter_type
是选民的类,{{1}是投票人的身份。
我需要的是通过“投票得分”按降序排列顶部 n voter_id
的查询,其中“投票得分”定义为(该职位的票数) - (该职位的票数)。
如果您的解决方案不需要我诉诸posts
(我在Rails工作),那么奖励积分
如果您的解决方案在SQLite和PostgreSQL中以相同的方式工作,那么会获得更多奖励(尽管在PostgreSQL中工作更重要)。
答案 0 :(得分:3)
select
voteable_id,
sum(case
when vote then 1
else -1
end) as vote_score
from
votes
group by
voteable_id
请注意,这是ANSI SQL,因此可以跨SQLite,MySQL,Postgres,Oracle,SQL Server,DB2等工作。
要获得前N个帖子,您只需附加上述查询:
order by
vote_score desc
limit 10
Postgres和SQLite使用 limit
(在MySQL中略有不同),而不是在Oracle或SQL Server中,作为FYI。
所以,要获得与此相关的帖子信息:
select
p.title,
p.author,
p.createdate,
sum(case
when v.vote then 1
else -1
end) as vote_score
from
posts p
inner join votes v on
p.post_id = v.voteable_id
group by
p.title,
p.author,
p.createdate
order by
vote_score desc
limit 10
答案 1 :(得分:2)
SQLite和PostgreSQL(以及其他符合ANSI标准的SQL实现)通用的条件函数是CASE
- 参见例如PostgreSQL为here,SQLite为here。所以“计数+1 / -1票数”的内部部分必须是
SUM(CASE WHEN vote THEN 1 ELSE -1 END)
并且您也不可避免地需要GROUP BY voteable_id
才能使SUM
正常工作。
这需要在ORDER BY
进行排序(使用DESC);不确定你是否也想在结果中使用它,但我会假设你这样做,在这种情况下它也需要在SELECT
中(你可以在ORDER BY
中引用它的别名) 。最后,LIMIT n
适用于两个引擎。
所以,把它们放在一起:
SELECT voteable_id,
SUM(CASE WHEN vote THEN 1 ELSE -1 END) AS vote_score
FROM votes
GROUP BY voteable_id
ORDER BY vote_score DESC
LIMIT 10
应满足您的所有要求。
答案 2 :(得分:0)
如果您正在使用VoteFu(它看起来像你),那么我建议您转换为使用Integers来存储投票值而不是:boolean。
将VoteFu中的投票存储为布尔值的唯一原因是我觉得我需要保持与Acts_As_Voteable的向后兼容性。我现在已经决定我过分重视这个问题了。
我将发布一个新版本的VoteFu插件,为你处理转换,但在那之前,我认为自己改变这一点是明智之举。方法如下:
class VoteFuIntegerMigration < ActiveRecord::Migration
def self.up
add_column :votes, :vote_int, :integer
Vote.find(:all).each do |vote|
vote.vote_int = vote.vote? ? 1 : -1
vote.save!
end
remove_column :vote, :vote
rename_column :vote, :vote_int, :vote
end
end
然后:
module Juixe
module Acts
module Voteable
module InstanceMethods
def votes_for
Vote.sum(:vote, :conditions => [
"voteable_id = ? AND voteable_type = ? AND vote > 0",
id, self.class.name])
end
def votes_against
Vote.sum(:vote, :conditions => [
"voteable_id = ? AND voteable_type = ? AND vote < 0",
id, self.class.name])
end
def votes_total
Vote.sum(:vote, :conditions => [
"voteable_id = ? AND voteable_type = ?",
id, self.class.name])
end
end
end
end
end
将模块更改作为monkeypatch引入可能是个好主意。新的VoteFu将集成此代码(也有测试。)