SQL查询 - 双重否定

时间:2015-03-20 00:38:30

标签: sql oracle notin negation

我有下表,其中包含一些学术测验答案的记录:

Respostas

-SEMESTRE_ID(测验学期的外键)

-PERGUNTA_ID(测验问题的外键)

-DISCIPLINA_ID(正在评估的主题的外键)

-DOCENTE_ID(正在评估的教师的外键)

-QUIZ_ID(每个回答测验的人都有一个独特的quiz_id)

-TIPOAULA(类的类型,对于此上下文无关紧要)

-DATA(日期,对于此上下文无关紧要)

-ID(答案的唯一ID)

-RESPOSTA(答案的值,从1到5)

因此,一个学期的一个问题是不同科目的问题,可以由人们评估(不需要对所有问题进行投票)。

我想要实现的查询是:

在id 21的学期测验中,每个问题至少有5个的主题的id和首字母缩写是什么?

我用计数策略解决了这个问题:

SELECT DISCIPLINA.DISCIPLINA_ID, SIGLA
FROM RESPOSTAS, DISCIPLINA
WHERE RESPOSTAS.DISCIPLINA_ID = DISCIPLINA.DISCIPLINA_ID AND SEMESTRE_ID = 21 AND RESPOSTA = 5
GROUP BY DISCIPLINA.DISCIPLINA_ID, SIGLA
HAVING COUNT(DISTINCT PERGUNTA_ID) = (SELECT COUNT(DISTINCT PERGUNTA_ID) FROM RESPOSTAS WHERE SEMESTRE_ID = 21);

但这是一项任务,我们也要求通过使用双重否定策略来解决它,我似乎无法理解如何达到预期结果。

1 个答案:

答案 0 :(得分:3)

这看起来像是一个关系除法查询(如果我没有记错的话),你正在寻找的双重否定的一个例子就是下面的查询。基本上它可以被解读为向我显示所有主题,在问题集中不存在任何问题,分数为5或更多

SELECT DISCIPLINA_ID, SIGLA 
FROM XDISCIPLINA XD
WHERE NOT EXISTS ( -- there can not be any questions ...
    SELECT 1 FROM XRESPOSTAS XR
    WHERE SEMESTRE_ID = 21 
    AND NOT EXISTS ( -- that are not in the set of 5+
       SELECT 1 FROM XRESPOSTAS 
       WHERE PERGUNTA_ID = XR.PERGUNTA_ID 
         AND SEMESTRE_ID = 21
         AND RESPOSTA >= 5
         AND XD.DISCIPLINA_ID = DISCIPLINA_ID
    )
)

关于此的一篇好文章是:Joe Celko的Divided We Stand: The SQL of Relational Division。这非常值得一读。

编辑:

我认为由于缺少连接,上面的查询执行得非常糟糕。这个版本的表现要好得多:

SELECT DISCIPLINA_ID, SIGLA 
FROM XDISCIPLINA XD
WHERE SEMESTRE_ID = 21 
  AND NOT EXISTS (
    SELECT 1 FROM XRESPOSTAS XR
    WHERE SEMESTRE_ID = 21 AND
    XD.DISCIPLINA_ID = DISCIPLINA_ID AND
      NOT EXISTS (
       SELECT 1 FROM XRESPOSTAS 
       WHERE PERGUNTA_ID = XR.PERGUNTA_ID 
         AND SEMESTRE_ID = 21
         AND RESPOSTA > 4
         AND XD.DISCIPLINA_ID = DISCIPLINA_ID
    )
)

实现相同结果的另一种方法似乎表现得更好:

SELECT DISCIPLINA_ID, SIGLA 
FROM XDISCIPLINA XD
WHERE NOT EXISTS (
  SELECT PERGUNTA_ID FROM XRESPOSTAS XR 
    WHERE SEMESTRE_ID = 21 AND XD.DISCIPLINA_ID = DISCIPLINA_ID 
  INTERSECT
  SELECT PERGUNTA_ID FROM XRESPOSTAS XR 
    WHERE SEMESTRE_ID = 21 AND XD.DISCIPLINA_ID = DISCIPLINA_ID AND RESPOSTA < 5
    )