Итак, у меня есть две таблицы. Одна из них - таблица вопросов, а другая - таблица ответов с приведенной ниже схемой.
Вопрос:
id
title
category_id
active
Ответ:
id
question_id
player_id
active
В принципе, мне нужен запрос, чтобы получить количество вопросов, оставшихся сгруппированными для каждого игрока для определенной category_id
SELECT * FROM questions WHERE id NOT IN (SELECT DISTINCT(s.question_id) FROM answers s)
Он возвращает мне оставшиеся вопросы, но он не сгруппирован для конкретного игрока, и если он соединен с одной и той же таблицей ответов, то набор результатов пуст.
Запрос, который я пробовал:
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
Я уже получил желаемый результат с помощью PHP и использовал несколько циклов для получения требуемого набора, и это не оптимизированное решение и занимает много времени. Итак, вы хотите решить это, написав правильный запрос.
Спасибо за ваше время и оцените, если кто-нибудь может вести меня.
Данные таблицы:
Вопросы:
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
ответы:
id question_id player_id active
1 1 1 1
1 3 1 1
1 2 2 1
1 4 3 1
Ожидаемый результат:
player_id Count_of_Remaining_Questions Category ID
1 3 1
2 4 1
3 4 1
Предположим, что таблица players
с этой упрощенной схемой:
id | name
Теперь вы можете присоединиться к этой таблице со своей таблицей вопросов:
SELECT
p.id AS player_id,
q.id AS question_id
FROM
players p
CROSS JOIN
questions q
Это приведет к списку всех возможных комбинаций игроков и вопросов. Теперь вы можете присоединиться к этим ответам с помощью LEFT JOIN и отфильтровать ответы:
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
Это уменьшит прежний список до всех оставшихся без ответа вопросов. Теперь просто заполните группу игроком и категорией, чтобы получить окончательный список:
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
Обновление. Чтобы получить список игроков, которые уже ответили на все вопросы, нам нужно изменить логику. Вместо того, чтобы проверять ответы на оставшиеся без ответа вопросы (WHERE a.id IS NULL
), мы теперь сравним сумму идентификаторов вопросов в обоих табличных questions
(чтобы получить ссылку на все вопросы) и answers
(чтобы рассчитать баллы для каждого игрока/категории). Только если оба значения равны (HAVING SUM(a.question_id) = SUM(q.id)
), индивидуальный игрок ответил на все вопросы (при условии, что на игрока есть только одна строка ответа и вопрос.
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)
WHERE a.id IS NULL
мы специально перечисляем игроков, у которых остался хотя бы один вопрос. Не могли бы вы указать требования? То есть теперь вам нужен список игроков, которые ответили на все вопросы?
Вы можете перейти к answers
и таблицам questions
а затем снова присоединиться к таблице 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
Вы можете использовать кросс-соединение, чтобы получить все возможные вопросы для каждого пользователя, а затем не в каждом из пользователей, которые могли бы получить значение для вашей статистики
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