lights_on_me
lights_on_me

Reputation: 53

mysql query logic for fetching data from 3 related tables on certain condition

I'm building a programming contest controller on web platform, which has some tables, including 'contest', 'problem' and 'relation' tables, which I'm having the trouble with.

structure of 'contest' table: contest_id, contest_name (for simplicity)

============================
|contest_id | contest_name |
|-----------|--------------|
|          1|  Test Contest|
|-----------|--------------|
|          2|   Another One|
============================

structure of 'problem' table: problem_id, problem_name (for simplicity)

============================
|problem_id | problem_name |
|-----------|--------------|
|          1|     A Problem|
|-----------|--------------|
|          2| Other Problem|
============================

structure of 'relation' table: rel_id, contest_id, problem_id

===========================================
|   rel_id  | contest_id   |  problem_id  |
|-----------|--------------|--------------|
|          1|             1|             1|
|-----------|--------------|--------------|
|          2|             1|             2|
|-----------|--------------|--------------|
|          3|             1|             8|
|-----------|--------------|--------------|
|          4|             2|             5|
|-----------|--------------|--------------|
|          5|             2|             8|
===========================================

I'm planning to allow the admin to set up the system once then have as many contests as s/he wants, so the same 'problem_id' can be assigned to multiple 'contest_id'.

For a single contest, I'm fetching all the 'problem_id's for that contest with all the content of that problem with this query:

SELECT * FROM `problem` JOIN `relation` on `relation`.`problem_id` = `problem`.`problem_id` WHERE `contest_id` = 3 // say the id is 3

But when editing the contest and adding some more problems in it, I need to fetch ONLY those problems to show which are NOT ALREADY in the same contest.

I tried this but didn't work, gave me some duplicates and other contest problems:

SELECT * FROM `problem` LEFT JOIN `relation` on `relation`.`problem_id` != `problem`.`problem_id` WHERE `contest_id` != 3

I can do the same thing inside php, using two loops, one for iterating through all the 'problem_id's in the whole system and inside that loop, another loop for iterating through all the 'problem_id's of that contest only, or vice versa. But it'll cost me an O(n^2) complexity which I'm sure can be avoided using mysql query. Any idea to do it in php more efficiently will be also good for me. Any help is appreciated.

Upvotes: 4

Views: 51

Answers (1)

Tristan
Tristan

Reputation: 3321

You can use MYSQL NOT IN() to remove the problems that are already in the relation table for the selected contest.

SELECT * FROM problem WHERE 
    problem.problem_id NOT IN (SELECT problem_id FROM relation WHERE contest_id = 2)

NOT IN() makes sure that the expression proceeded does not have any of the values present in the arguments.

Upvotes: 2

Related Questions