2010-11-18 150 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