Search code examples
mysqlsqlratingvote

Rating system : How to select the next item for which the user didn't vote yet


I have 3 tables with the following columns :

* users : user_id
* votes : user_id, creation_id
* creations : creation_id, creation_points

Each user can vote one time for each creation. When a user vote, this happens :

  • Table votes : Insert a new line with user_id and creation_id (so we can check if the user has already voted for this creation)
  • Table creations : Add +1 to row creation_points for the concerned creation

But now, I want that when the user has successfully voted for a creation, it displays him the next creation for which he didn't vote yet. How can I achieve that ?

I tried this way :

  1. Select the next creation_id from creations table (where creation_id is bigger than the current creation_id)
  2. Check if the couple creation_id & user_id already exists in the votes table. If it exists, retry from 1).

The problem with this method is that it needs a lot of queries if the user has already voted for the next creation. It also create an infinite loop if he has already voted for all the creations. Is there others alternatives ?


Solution

  • If I understand how you are handling it, you seem to be on the right track by storing votes as a user_id and creation_id. To get the next available creation, use a LIMIT 1 query that excludes the already voted-for creations:

    This method uses a NOT IN() subquery:

    SELECT 
     creations.*
    FROM creations 
    WHERE creation_id NOT IN (
      SELECT creation_id FROM votes WHERE user_id = <the user_id>
    )
    ORDER BY creation_id ASC 
    LIMIT 1
    

    Similar thing using NOT EXISTS instead:

    SELECT 
     creations.*
    FROM creations 
    WHERE NOT EXISTS (
      SELECT creation_id 
      FROM votes 
      WHERE 
       user_id = <the user_id>
       AND creations.creation_id = votes.creation_id
    )
    ORDER BY creation_id ASC 
    LIMIT 1