使用JOIN和嵌套NOT IN

时间:2018-01-29 10:18:47

标签: mysql

所以我有两张桌子。 一个是问题表,另一个是带有下面提到的模式的答案表。

问题:

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

3 个答案:

答案 0 :(得分:2)

让我们假设一个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中的问题ID总和(以获取所有问题的参考)和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)

答案 1 :(得分:1)

您可以使用交叉联接为每个用户获取所有可能的问题,然后使用不在每个用户的asnwer中获取您的统计信息的值

   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

答案 2 :(得分:1)

您可以交叉加入answersquestions表格,然后再次加入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