2010-11-18 2 views
4

У меня есть таблица базы данных, называемая votes с тремя столбцами «timestamp», «voter» и «voted_for».Как мне подсчитывать голоса в MySQL?

Каждая запись в таблице представляет собой один голос. Я хочу подсчитать все голоса за каждый «voted_for» с некоторыми условиями.

условия заключаются в следующем:

  • Каждый избиратель может голосовать только один раз, в случае нескольких голосов от одного избирателя самые последние подсчета голосов.

  • Учитываются только голоса, произведенные до указанного времени.

+0

Ваши критерии не делают полный смысл. Как вы хотите подсчитать голосов? Вы делаете простой счет или иначе? Если это просто счет, то не имеет смысла, почему вам нужен самый последний из избирателя, а не просто подсчет голосов. –

+0

@Alison: Насколько я понимаю, пользователь мог изменить свой голос, поэтому OP хочет получить то, что они проголосовали за последнее. @johndbritton: Почему вы не можете повторно использовать ту же строку, когда пользователь обновляет свой голос вместо создания нового? Таким образом, голосование пользователя всегда актуально. –

+0

@musicfreak, ты совершенно прав. Я мог бы обновить строку, но ради простоты я только что записал все голоса. Я подумал, что было бы интересно узнать, кто изменил свой голос. – johndbritton

ответ

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 »в разделе« on ».» – johndbritton

+0

возможно потому, что псевдоним A и a.lasttime - это нижний регистр ... я всегда забываю о чувствительности к регистру MySQL! – Leslie

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

Это близко, но я не думаю, что это абсолютно правильно. Запрос должен быть уверен, чтобы подсчитать последний голос избирателей, которые голосовали более одного раза. Ваш запрос обязательно учитывает только один голос от каждого избирателя, но не гарантирует, что это последнее голосование. – johndbritton

+2

Почему бы просто не сделать так, чтобы пользователь, который голосует более одного раза, просто перезаписывает свое существующее голосование вместо создания второй записи, чтобы уменьшить количество строк в базе данных? – Webnet

+0

, который будет считать всех избирателей не всеми, за кого проголосовали! – Leslie

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

+0

использовать триггер и подсчет, когда вы вставляете vs. hmmmm select count .. внутреннее соединение ... 10 миллионов строк позже - зевать. –

+0

Я не собираюсь голосовать за это, потому что я не думаю, что это лучший ответ.Но это, безусловно, полезно с точки зрения представления другого и совершенно правильного способа делать то, что хочет пользователь. –

Смежные вопросы