Voting system using PHP+MySql? - php

We have to make a ballot system that makes users vote for various candidates on different positions. There's a login for voters. How do you store a vote of one voter and then get that vote added to the previous votes? The only possible way is to store every vote on a database right? But what would the structure of the database look like? And how do you count it?
edit:
The voting system doesnt only have one group of candidates to vote. It has mayor, vice-mayor, senator, etc. There are too many. that's why I'm confused. If only it was just a voting system of a president, it would be easier. So if I have a table for the voter, with a column of his/her voted candidate, it's not possible since the voter votes for many candidates.

A better way would be to have a different table to store Votes. And that table will have two attributes (VoterId, CandidateId)
And you can fetch the Vote Count if you are allowing multiple votes from this table..
But it would be better to make VoterId a Primary key in this table.. To avoid multiple voting
CandidateType: - (TypeId(PK), typeName, maxVotePerVoterForThisType)
Voter Table: - (voterId(PK), voterName, otherInfo)
Candidate Table: - (candidateId(PK), candidateName, constituency,
otherInfo, TypeId(FK))
Votes:- (voterId(PK, FK), TypeId(PK, FK), candidateId(FK))
*EDIT:- Schema edited with changed requirement in original post
*EDIT: - Added a field in CandidateType table to allow multiple votes.(E.g.: Now a voter can vote for 10 Senators, if maxVotePerVoter for this type is set to 10..)

You should e store each candidate in a table, positions in another table then make relations based on ID, the voting system is relatively simple:
database:
id, position_id, candidate_id, votes
then PHP
$query = "UPDATE `votes` SET `votes`=`votes`+1 WHERE `position_id`=1 AND candidate_id=1"; // adds 1 vote where position_id is 1 and candidate_id is 1

These 3 tables are required for your accounts (the voters) and candidates.
Account: Id (PK), Name, Password
Candidates: Id (PK), Name
Votes: AccountId (PK), CandidateId (PK)
Insert a row into votes when a vote is cast. This prevents duplicate voting due to the PK's.

I simple language i can say you are storing voting users in a table called users and you can use a field vaotecount (int) type initilize with zero and track their ip and vote for topic id on which they have voted for and when they vote you can check with IP and topic_id that they are not voting twice and if they passed you can increment the vaotecount field by one
and while you are counting for votes count the users with topic id for which you counting votes. Simple :D

From the explanation of problem, I can suggest you the following database structure:
tlbUserVote:
UserID(PK) | UserName | Vote | CandidateId(FK)
tlbCandidate:
CandidateId(PK) | CandidateName | TotalVotes
By this structure you can add the current votes with previous ones (by taking previous votes first and adding it to the current).
Total votes of the candidates will get updated, too.

Related

Select from database with count and count based conditions?

I have a table with data relating to a user, and two important columns:
refer_count, which is updated when a new entry is made in the table with the referred_by column set to that users user_id, and referred_by which is the user_id of the of the user that referred them.
I want to select the users from the table that have the highest number of referrals after a certain date.
For example:
If there are 3 users, one of which referred the other 2 (lets say users 2 and 3), however user 2 was referred on the 2/12/14, whereas user 3 was referred on the 3/1/15.
If the cutoff is 1/12/14, then user 1 is returned with refer_count set to 2, but if the cutoff is after 2/12/14, then user 1 is returned with refer_count set to 1.
I've been thinking of how to do this, but I can't think of a way that would work. Is there a way?
This is via MySQL.
EDIT: I think I may need to provide for information.
The date registered (register_date) is used as the refer date. I need the refer_count to be updated with the number of users referred after the cutoff, however I need to get the actual user. This is for a 'top referrers' table. I can't figure out why I'm having so much trouble thinking of a way to do this.
SELECT user_id FROM usertable WHERE (referal_date BETWEEN '2014-12-2' AND CURDATE())ORDER BY refer_count DESC;
That's the rough idea.
You should look into normalizing your tables if you're keeping that all in the same table, though. It'd be better to keep referals in a seperate table.
Get the row with the maximum in refer_count with a Date condition for your referal_date such that it's after the certainDate:
SELECT user_id FROM table WHERE refer_count = (SELECT MAX(refer_count) FROM table) AND referal_date>certainDate;
Note that WHERE is before SELECT so it will not get the highest count first, but will filter with the date condition then get the highest count.
Edit: Updated query based on edited question.

PHP/MySQL multiple votes

Hello I have voting system on my website but I would like to disable multiple voting from users. If the user votes he/she cannot vote again. Here is one solution which I have but is not good imo.
I created a column in users table: users_avoted where I would store the IDs of articles which he/she voted like tihs:
1|2|5|6
From this I would be able to check whether the user had already voted. But the thing is there will be a lot of articles so VARCHAR(255) will not be enough to store all of those IDs. Any other solutions?
Thanks
Don't denormalize it like that. Just have a two column table, userVotes, with a composite Key for UserID and ArticleID.
example data:
userid | articleid
1 1
1 2
1 67
2 1
This is better than something like
userID | articleID
1 1,2,67
Which is what it looks like you are suggesting. Please don't do this, and keep it normalized unless you want to do gymnastics every time you query. To elaborate, implementing what you suggested would defeat the purpose of using a RDBMS, in order to 'cheat' on one specific query.
You could instead make a table like:
users_avoted {
article_id,
user_id,
answer_id
}
Make a unique index out of article_id and user_id. That would only allow a single record to be input for that.
So, say they choose option 5 on article 2, and they are user 1.
Now, when you attempt to insert into the table:
INSERT INTO users_avoted VALUES (2, 1, 5)
You can't because the user already voted.
The benefit of this approach is that you don't have to check if they voted already first.
Store the votes in a table layed out like: id,username,voteid,vote for example.
Then when the user votes, check that table for matching rows.
For example:
if ($username == $dbusername && $voteid == $dbvoteid){
$disallowed = true;
}

Storing user activity? PHP, MySQL and Database Design

Ok so a user comes to my web application and gets points and the like for activity, sort of similar (but not as complex) as this site. They can vote, comment, submit, favorite, vote for comments, write description etc and so on.
At the moment I store a user action in a table against a date like so
Table user_actions
action_id - PK AI int
user_id - PK int
action_type - varchar(20)
date_of_action - datetime
So for example if a user comes along and leaves a comment or votes on a comment, then the rows would look something like this
action_id = 4
user_id = 25
action_type = 'new_comment'
date_of_action = '2011-11-21 14:12:12';
action_id = 4
user_id = 25
action_type = 'user_comment_vote'
date_of_action = '2011-12-01 14:12:12';
All good I hear you say, but not quite, remember that these rows would reside in the user_actions table which is a different table to the ones in which the comments and user comment votes are stored in.
So how do I know what comment links to what row in the user_actions?
Well I could just link to the unique comment_id in the comments table to a new column, called target_primary_key in the user_actions table?
Nope. Can't do that because the action could equally have been a user_comment_vote which has a composite key (double key)?
So the thought I am left with is, do I just add the primary keys in a column and comma deliminate them and let PHP parse it out?
So taking the example above, the lines below show how I would store the target primary keys
new_comment
target_primary_keys - 12 // the unique comment_id from the comments table
user_comment_vote
target_primary_keys - 22,12 // the unique comment_id from the comments table
So basically a user makes an action, the user_actions is updated and so is the specific table, but how do I link the two while still allowing for multiple keys?
Has anyone had experience with storing user activity before?
Any thoughts are welcome, no wrong answers here.
You do not need a user actions table.
To calculate the "score" you can run one query over multiple tables and multiply the count of matching comments, ratings etc. with a multiplier (25 points for a comment, 10 for a rating, ...).
To speed up your page you can store the total score in an extra table or the user table and refresh the total score with triggers if the score changes.
If you want to display the number of ratings or comments you can do the same.
Get the details from the existing tables and store the total number of comments and ratings in an extra table.
The simplest answer is to just use another table, which can contain multiple matches for any key and allow great indexing options:
create table users_to_actions (
user_id int(20) not null,
action_id int(20) not null,
action_type varchar(25) not null,
category_or_other_criteria ...
);
create index(uta_u_a) on users_to_actions(user_id, action_id);
To expand on this a bit, you would then select items by joining them with this table:
select
*
from
users_to_actions as uta join comments as c using(action_id)
where
uta.action_type = 'comment' and user_id = 25
order by
c.post_date
Or maybe a nested query depending on your needs:
select * from users where user_id in(
select
user_id
from
users_to_actions
where
uta.action_type = 'comment'
);

Preventing second votes in Comment Voting

Hi I have a question regarding a method to prevent second voting in a website where people can vote up or vote down a comment. Like Stackoverflow!! :)
The question is how I can keep track of whether a comment has already been voted by a logged in user. Lets assume this is for a online ecommerce store with reviews on products. Here's what I think:
All reviews data is stored in a table called 'reviews'
Field names: review_id, product_id, user_id, title, description, time_created, up_votes, down_votes, up_voters, down_voters
up_votes and down_votes contain the number of votes voting it up or down
up_voters and down_voters contain the user_id of the people who voted up or down in the format 1101.1102.1103 for users with user_id 1101, 1102 and 1103.
When a person clicks on the up vote button, the system will check if the current user's user_id matches anyone in up_voters. An explode function will turn 1101.1102.1103 into an array and in_array() will be used to check if the user has already voted.
Is there a better way to go about doing this?
That table will give you nightmares down the line. Just think of a hit product with 1K up_voters, your field will be 10K*4 characters long! Not just that, it will hinder your ability to make reports and study the data etc.
I don't know much about your needs but from what I can see in your table, I'd suggest the below.
review
user_id, product_id, type_of_vote, title, description, time_created
Use above table and use user_id, product_id as the key
OR
review
review_id, product_id, title, description, time_created
vote
review_id, user_id, type_of_vote
There are n number of ways to design tables for this. If it is an Operational Data Store(ODS) then you might want to normalize your design. If it's a warehouse then you may consider first table I mentioned above.

Rating System in PHP and MySQL

If we look at the stackoverflow website we have votes. But the question is what is the bestway to store who has voted and who has not. Lets also simplify this even more and say that we can only vote Up, and we can only Remove the Up vote.
I was thinking having the table to be in such form
question - Id(INT) | userId(INT) | title(TEXT) | vote(INT) | ratedBy(TEXT)
Thre rest is self explanitory but ratedBy is a Comma Seperated Id values of the Users.
I was thinking to read the ratedBy and compare it with the userId of the current logged in User. If he dosent exist in the ratedBy he can vote Up, otherwise he can remove his vote. Which in turn will remove the value from ratedBy
I think to make another table "vote" is better. The relationship between users and votes is n to n, therefore a new table should be created. It should be something like this:
question id (int) | user id (int) | permanent (bool) | timestamp (datetime)
Permanent field can be used to make votes stay after a given time, as SO does.
Other fields may be added according to desired features.
As each row will take at least 16B, you can have up to 250M rows in the table before the table uses 4GB (fat32 limit if there is one archive per table, which is the case for MyISAM and InnoDB).
Also, as Matthew Scharley points out in a comment, don't load all votes at once into memory (as fetching all the table in a resultset). You can always use LIMIT clause to narrow your query results.
A new table:
Article ID | User ID | Rating
Where Article ID and User ID make up the composite key, and rating would be 1, indicating upvote, -1 for a downvote and 0 for a removed vote (or just remove the row).
I believe your design won't be able to scale for large numbers of voters.
The typical thing to do is to create to tables
Table 1: question - Id(INT) | userId(INT) | title(TEXT)
Table 2: question - ID(INT) | vote(INT) | ratedBy(TEXT)
Then you can count the votes with a query like this:
SELECT t1.question_Id, t1.userId, t1.title, t2.sum(vote)
FROM table1 t1
LEFT JOIN table2 t2 ON t1.question_id = t2.question_id

Categories