2010-11-18 7 views
4

Ich habe eine Datenbanktabelle votes mit drei Spalten 'Zeitstempel', 'Voter' und 'voted_for'.Wie stimme ich Stimmen in MySQL?

Jeder Eintrag in der Tabelle entspricht einer Stimme. Ich möchte alle Stimmen für jeden 'voted_for' mit einigen Bedingungen zusammenrechnen.

Die Bedingungen sind wie folgt:

  • Jeder Wähler nur einmal wählen kann, im Falle mehrerer Stimmen durch einen einzelnen Wähler die jüngsten Stimme zählt.

  • Nur die vor einer bestimmten Zeit abgegebenen Stimmen werden gezählt.

+0

Ihre Kriterien machen keinen vollständigen Sinn. Wie möchten Sie Stimmen abstimmen? Machst du eine einfache Zählung oder sonst? Wenn es sich nur um eine Zählung handelt, macht es keinen Sinn, warum Sie die aktuellste Person von einem Wähler brauchen, anstatt nur einmal einen Wähler zu zählen. –

+0

@Alison: Wie ich es verstehe, könnte ein Benutzer seine Stimme geändert haben, so dass das OP bekommen will, was immer sie zuletzt gewählt haben. @johnbritton: Warum kannst du nicht einfach dieselbe Zeile wieder verwenden, wenn der Nutzer seine Stimme aktualisiert, anstatt eine neue zu erstellen? Auf diese Weise ist die Stimme des Benutzers immer auf dem neuesten Stand. –

+0

@musicfreak, du bist genau richtig. Ich hätte die Reihe aktualisieren können, aber der Einfachheit halber habe ich nur jede Stimme aufgezeichnet. Ich dachte, es wäre interessant zu sehen, wer ihre Stimme geändert hat. – johndbritton

Antwort

4

try this:

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

Danke, das sieht gut aus, obwohl ich einen Fehler bekomme "# 1054 - Unbekannte Spalte 'a.lasttime' in 'on clause'." – johndbritton

+0

vielleicht weil der Alias ​​A ist und die a.lasttime in Kleinbuchstaben ist ... ich vergesse immer die Groß- und Kleinschreibung von MySQL! – Leslie

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

Das ist knapp, aber ich denke nicht, dass es völlig korrekt ist. Die Abfrage muss sicherstellen, dass die letzte Stimme der Wähler, die mehr als einmal gewählt haben, gezählt wird. Ihre Abfrage stellt sicher, dass jeder Wähler nur eine Stimme zählt, stellt jedoch nicht sicher, dass es sich um die letzte Stimme handelt. – johndbritton

+2

Warum sollte man es nicht einfach so machen, dass ein Benutzer, der mehr als einmal abstimmt, einfach seine vorhandene Stimme überschreibt anstatt einen zweiten Eintrag zu erstellen, um die Anzahl der Zeilen in der Datenbank zu reduzieren? – Webnet

+0

das wird alle Wähler zählen, nicht alle Leute gewählt! – Leslie

0

das Folgende als hilfreich erweisen:

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

Ich denke, das war eine andere Frage zu beantworten .... – Leslie

+0

Verwenden Sie einen Trigger und Tally, wie Sie vs. hmmmm Anzahl einfügen einfügen .. innere beitreten ... 10 Millionen Zeilen später - gähnen. –

+0

Ich werde das nicht abstimmen, weil ich nicht glaube, dass es die beste Antwort ist.Aber es ist sicherlich hilfreich, um einen anderen und vollkommen gültigen Weg zu zeigen, was der Fragesteller will. –

Verwandte Themen