简体   繁体   中英

SQL query - double negation

I have the following table, which has the records of the answers to some academic quizzes:

Respostas

-SEMESTRE_ID (foreign key for semester of the quiz)

-PERGUNTA_ID (foreign key for the question of the quiz)

-DISCIPLINA_ID (foreign key for the subject being evaluated)

-DOCENTE_ID (foreign key for the teacher being evaluated)

-QUIZ_ID (each person answering a quiz has an unique quiz_id)

-TIPOAULA (type of class, doesn't matter for this context)

-DATA (date, doesn't matter for this context)

-ID (unique id of an answer)

-RESPOSTA (value of the answer, from 1 to 5)

So, a quizz of a given semester has multiples questions of different subjects, which can be evaluated by people (don't need to necessarily vote on all the questions).

The query I want to achieve is:

What's the id and acronym of the subjects that had at least a 5 in each one of the questions of the quiz of semester of id 21?

I've solved it using the counting strategy:

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);

But this is for an assignment and we're asked to also solve it by using the double negation strategy, which I can't seem to understand how to achieve the expected result.

This looks like a relational division query (if I'm not mistaken) and an example of the double negation that you're looking for is the query below. Basically it can be read as show me all subjects for which there exists no question not also in the set of question with a score of five or more

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
    )
)

An good article on this is: Divided We Stand: The SQL of Relational Division by Joe Celko. It's well worth reading.

EDIT:

I think the query above was performing really bad due to a missing join. This version should perform a lot better:

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
    )
)

Another way to achieve the same result that seem to perform a whole lot better:

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
    )

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM