Reputation: 1500
So I have two tables. One is questions table and another one is the answers table with the below mentioned schema.
Question:
id
title
category_id
active
Answer:
id
question_id
player_id
active
Basically, what I need is a query to get the number of questions remaining grouped together for each player for a particular category_id
SELECT * FROM questions WHERE id NOT IN (SELECT DISTINCT(s.question_id) FROM answers s)
It returns me the remaining questions, but its not grouped together for particular player and if it is joined with the same answers table, then the result set is empty.
Query that I have tried:
SELECT g.player_id, COUNT(questions.question_id) as Count
FROM `questions` JOIN answers g ON g.id = questions.id
WHERE g.question_id NOT IN
(
SELECT DISTINCT(question_id)
FROM answers
) GROUP BY g.player_id
I have already got the desired result using PHP and used multiple loops to get the required set and it is not optimized solution and takes a lot of time. So, want to solve it by writing a proper query.
Thanks for your time and appreciate if anyone can guide me.
Table Data:
Questions:
id title category_id active
1 A 1 1
2 B 1 1
3 C 1 1
4 D 1 1
5 E 1 1
Answers:
id question_id player_id active
1 1 1 1
1 3 1 1
1 2 2 1
1 4 3 1
Expected Output:
player_id Count_of_Remaining_Questions Category ID
1 3 1
2 4 1
3 4 1
Upvotes: 0
Views: 86
Reputation: 9022
Let's assume a players
table with this simplified schema:
id | name
Now you can join this table with your questions table:
SELECT
p.id AS player_id,
q.id AS question_id
FROM
players p
CROSS JOIN
questions q
That would result in a list of all possible player-question combinations. Now, you could join that to the answers using a LEFT JOIN and filter out the answered ones:
SELECT
p.id AS player_id,
q.id AS question_id
FROM
players p
CROSS JOIN
questions q
LEFT JOIN
answers a
ON a.question_id = q.id
AND a.player_id = p.id
WHERE
a.id IS NULL
This will reduce the former list to all unanswered questions. Now, just group that by player and category to get the final list:
SELECT
p.id AS Player,
COUNT(q.id) AS Remaining,
q.category_id AS Category
FROM
players p
CROSS JOIN
questions q
LEFT JOIN
answers a
ON a.question_id = q.id
AND a.player_id = p.id
WHERE
a.id IS NULL
GROUP BY
p.id,
q.category_id
Update: To get a list of players who already answered all questions we need to change the logic. Instead of checking for unanswered questions (WHERE a.id IS NULL
) we will now compare the sum of question ids in both tables questions
(to get the reference for all questions) and answers
(to calculate the score for each player/category). Only if both values are equal (HAVING SUM(a.question_id) = SUM(q.id)
), the individual player did answer all questions (assuming there is only one answer row per player and question.
SELECT
p.id AS Player,
COUNT(q.id) AS Remaining,
q.category_id AS Category
FROM
players p
CROSS JOIN
questions q
LEFT JOIN
answers a
ON a.question_id = q.id
AND a.player_id = p.id
GROUP BY
p.id,
q.category_id
HAVING
SUM(a.question_id) = SUM(q.id)
Upvotes: 2
Reputation: 133370
You could use a cross join for get all the possible question for each user then with a not in the asnwer of each user you could obtain the value for your stats
select player_id, count(*), category_id
from (
select a2.player_id, q.id, q.category_id
from answer a2
cross join question q
where (a2.player_id, q.question_id ) not in (
select a.question_id, a.player_id
from Answers a )
) t
group by player_id, category_id
Upvotes: 1
Reputation: 350345
You could cross join the answers
and questions
tables and then outer join the answers
table again to find the missing answers:
select a.player_id,
count(distinct q.id) as count
from answers a
cross join questions q
left join answers a2
on a2.question_id = q.id
and a2.player_id = a.player_id
where a2.question_id is null
and q.category_id = 1
and q.active = 1
group by a.player_id
Upvotes: 1