2010-11-18 109 views
4

我有一个名为votes的数据库表,其中包含三列“时间戳”,“选民”和“voteed_for”。如何计算MySQL中的投票?

表中的每个条目代表一票。我想在某些条件下为每个“投票”选出所有选票。

的条件如下:

  • 每个选民可以通过一个单一的选民最近的投票数只能投票一次,在多票的情况。

  • 只有在指定时间之前进行的选票才会被统计。

+0

您的标准不作完整意义上的。你想如何计票?你在做简单的计数或其他吗?如果只是一个计数,那么为什么你需要最近从选民那里得到的数据,而不是仅仅统计一次选民。 – 2010-11-18 20:35:59

+0

@Alison:据我了解,用户可能已经改变了他们的投票,所以OP想要得到他们最后投票的东西。 @johndbritton:为什么当用户更新他的投票而不是创建一个新的投票时,你不能重新使用同一行?这样,用户的投票总是最新的。 – 2010-11-18 22:09:17

+0

@musicfreak,你完全正确。我本可以更新这一行,但为了简单起见,我只记录了每一票。我认为能够看到谁改变了他们的投票会很有趣。 – johndbritton 2010-11-18 22:36:35

回答

4

试试这个:

SELECT voted_for, count(*) 
FROM votes v 
INNER JOIN (SELECT Voter, Max(timestamp) as lastTime from votes group by Voter) A 
on A.Voter = v.voter and a.lasttime = v.timestamp 
WHERE timestamp < {date and time of last vote allowed} 
Group by voted_for 
+0

谢谢,这看起来是正确的,虽然我得到一个错误“#1054 - 在'条款'中的未知列'a.lasttime'。” – johndbritton 2010-11-19 21:25:19

+0

也许是因为别名是A,而a.lasttime是小写......我总是忘记了MySQL的大小写敏感性! – Leslie 2010-11-19 21:45:22

0
SELECT voted_for,COUNT(DISTINCT voter) 
FROM votes 
WHERE timestamp < '2010-11-18 21:05:00' 
GROUP BY voted_for 
+0

这很接近,但我不认为这是完全正确的。查询需要确保统计不止一次投票的选民的最新投票。您的查询确保只计算每个选民的一票,但不能确定它是最新的投票。 – johndbritton 2010-11-18 20:21:52

+2

为什么不这样做,让不止一次投票的用户简单地覆盖他们现有的投票,而不是创建第二个条目来减少数据库中的行数? – Webnet 2010-11-18 20:31:07

+0

这将统计所有的选民不是所有的投票人! – Leslie 2010-11-18 21:03:43

0

下面可能证明是有益的:

drop table if exists users; 
create table users 
( 
user_id int unsigned not null auto_increment primary key, 
username varbinary(32) not null, 
unique key users_username_idx(username) 
)engine=innodb; 

insert into users (username) values 
('f00'),('foo'),('bar'),('bAr'),('bish'),('bash'),('bosh'); 

drop table if exists picture; 
create table picture 
( 
picture_id int unsigned not null auto_increment primary key, 
user_id int unsigned not null, -- owner of the picture, the user who uploaded it 
tot_votes int unsigned not null default 0, -- total number of votes 
tot_rating int unsigned not null default 0, -- accumulative ratings 
avg_rating decimal(5,2) not null default 0, -- tot_rating/tot_votes 
key picture_user_idx(user_id) 
)engine=innodb; 

insert into picture (user_id) values 
(1),(2),(3),(4),(5),(6),(7),(1),(1),(2),(3),(6),(7),(7),(5); 


drop table if exists picture_vote; 
create table picture_vote 
( 
picture_id int unsigned not null, 
user_id int unsigned not null,-- voter 
rating tinyint unsigned not null default 0, -- rating 0 to 5 
primary key (picture_id, user_id) 
)engine=innodb; 

delimiter # 

create trigger picture_vote_before_ins_trig before insert on picture_vote 
for each row 
proc_main:begin 

declare total_rating int unsigned default 0; 
declare total_votes int unsigned default 0; 

if exists (select 1 from picture_vote where 
    picture_id = new.picture_id and user_id = new.user_id) then 
     leave proc_main; 
end if; 

select tot_rating + new.rating, tot_votes + 1 into total_rating, total_votes 
    from picture where picture_id = new.picture_id; 

-- counts/stats 
update picture set 
    tot_votes = total_votes, 
    tot_rating = total_rating, 
    avg_rating = total_rating/total_votes 
where picture_id = new.picture_id; 

end proc_main # 

delimiter ; 

insert into picture_vote (picture_id, user_id, rating) values 
(1,1,5),(1,2,3),(1,3,3),(1,4,2),(1,5,1), 
(2,1,1),(2,2,2),(2,3,3),(2,4,4),(2,5,5),(2,6,1),(2,7,2), 
(3,1,5),(3,2,5),(3,3,5),(3,4,5),(3,5,5),(3,6,5),(3,7,5); 

select * from users order by user_id; 
select * from picture order by picture_id; 
select * from picture_vote order by picture_id, user_id; 
+2

我认为这是设想回答一个不同的问题.... – Leslie 2010-11-18 20:44:43

+0

使用一个触发器和理货,你插入与hmmmm选择计数..内部加入... 1000万行后 - 打哈欠。 – 2010-11-18 20:57:54

+0

我不会投这个票,因为我不认为这是最好的答案。但从提出一种完全有效的方式来完成提问者想要的角度来看,这无疑是有帮助的。 – 2010-11-18 22:40:24