【问题标题】:SQL get polls that specified user is winningSQL 获取指定用户获胜的民意调查
【发布时间】:2010-06-23 11:42:28
【问题描述】:

大家好,提前致谢 我有表accountsvotescontests
投票由作者 ID、获胜者 ID 和竞赛 ID 组成,以防止人们重复投票
我想为任何给定帐户显示他们赢得比赛的次数、获得第二的次数以及获得第三的次数
最快(执行时间)的方法是什么? (我用的是 MySQL)

【问题讨论】:

  • 您应该添加这 3 个表的确切方案。这样可以更轻松地帮助进行所需的查询。例如,尚不清楚获胜者是否保存在比赛表中,或者是否只能通过投票来确定。
  • 我可能会考虑将获胜者存储在contest 表中并定期更新,但现在我只想知道用户成为第一、第二和第三的次数(纯粹由计票)

标签: mysql sql count


【解决方案1】:

在使用 MySQL 很长时间后,我得出的结论是,几乎任何使用 GROUP BY 对性能都非常不利,所以这里有一个包含几个临时表的解决方案。

CREATE TEMPORARY TABLE VoteCounts (
  accountid INT,
  contestid INT,
  votecount INT DEFAULT 0
);

INSERT INTO VoteCounts (accountid, contestid)
  SELECT DISTINCT v2.accountid, v2.contestid
  FROM votes v1 JOIN votes v2 USING (contestid)
  WHERE v1.accountid = ?; -- the given account

确保您在votes(accountid, contestid) 上有一个索引。

现在您有一个表格,其中包含您的给定用户参加的每个比赛,以及参加相同比赛的所有其他帐户。

UPDATE Votes AS v JOIN VoteCounts AS vc USING (accountid, contestid)
SET vc.votecount = vc.votecount+1;

现在您可以计算每场比赛中每个帐户的票数。

CREATE TEMPORARY TABLE Placings (
  accountid INT,
  contestid INT,
  placing INT
);

SET @prevcontest := 0;
SET @placing := 0;
INSERT INTO Placings (accountid, placing, contestid)
  SELECT accountid, 
    IF(contestid=@prevcontest, @placing:=@placing+1, @placing:=1) AS placing,
    @prevcontest:=contestid AS contestid
  FROM VoteCounts
  ORDER BY contestid, votecount DESC;

现在您有一个表格,其中每个帐户与他们在每场比赛中的各自名次配对。很容易获得给定位置的计数:

SELECT accountid, COUNT(*) AS count_first_place
FROM Placings
WHERE accountid = ? AND placing = 1;

您可以使用 MySQL 技巧来完成所有三合一查询。布尔表达式在 MySQL 中总是返回整数值 0 或 1,因此您可以使用 SUM() 来计算 1。

SELECT accountid, 
  SUM(placing=1) AS count_first_place,
  SUM(placing=2) AS count_second_place,
  SUM(placing=3) AS count_third_place
FROM Placings
WHERE accountid = ?; -- the given account

你的评论:

是的,无论从您拥有的标准化数据到您想要的结果如何,这都是一项复杂的任务。您希望它再次聚合(求和)、排名和聚合(计数)。那是一堆工作! :-)

此外,单个查询并不总是完成给定任务的最快方式。程序员普遍认为较短的代码意味着更快的代码。

请注意,我尚未对此进行测试,因此您的里程可能会有所不同。


关于更新的问题:

在不使用 GROUP BY 的情况下,获取每个帐户的 COUNT() 投票是一种棘手的方法。我添加了表别名 v 和 vc,所以现在可能更清楚了。在votes 表中,给定帐户/竞赛有 N 行。在votescount 表中,每个帐户/比赛有一行。当我加入时,UPDATE 会针对 N 行进行评估,因此如果我为这 N 行中的每一行添加 1,我会在与每个相应帐户/比赛对应的行中获得存储在 votescount 中的 N 的计数。

【讨论】:

  • 所以我是否正确地假设这将是非常密集的,无论我如何做,并且没有办法在单个查询中做到这一点?还是您认为这是最快的方法?再次感谢
  • 干杯,它工作得很好,虽然我不明白语法以及它到底是做什么的:UPDATE Votes JOIN VoteCounts USING (accountid, contestid) SET votecount = votecount+1; 这是否将表 votes 上的投票计数设置为表 VoteCounts 的投票计数?我注意到 votes 没有再次被引用,所以我把这两行去掉了,没有它似乎也能正常工作
【解决方案2】:

如果我的解释正确,为了阻止人们两次投票,我认为您只需要按作者(帐户?) ID 和比赛 ID 在投票表上创建唯一索引。它不会阻止人们拥有多个账户并投票两次,但它会阻止任何人从同一个账户两次投票。为了防止欺诈(sock puppet 账户),您需要检查投票模式并检测一个账户何时更频繁地投票给另一个账户,而不是统计上的可能性。除非你有很多实际上可能很难的比赛。

【讨论】:

  • 是的,我已经将它们按作者索引并比赛感谢 :) 非常感谢比尔,我马上试试看
猜你喜欢
  • 2020-01-20
  • 1970-01-01
  • 2017-02-04
  • 1970-01-01
  • 2017-12-30
  • 1970-01-01
  • 1970-01-01
  • 2012-01-23
  • 2020-05-31
相关资源
最近更新 更多