SQL 查询 - 双重否定
Posted
技术标签:
【中文标题】SQL 查询 - 双重否定【英文标题】:SQL query - double negation 【发布时间】:2015-03-20 00:38:29 【问题描述】:我有下表,里面有一些学术小测验的答案记录:
回复
-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);
但这是一个作业,我们也被要求使用双重否定策略来解决它,我似乎无法理解如何达到预期的结果。
【问题讨论】:
可能重复? ***.com/questions/15681935/double-negation-sql-query @JoelGregory 真实的故事,看到了,但不幸的是没有解决方案(至少使用双重否定)。看来任务还是一样的,我不是第一个遇到困难的人:)谢谢。 你能定义一下“双重否定策略”吗?这不是我以前听过的术语。你可以把semestre_id = 21
变成not( semestre_id != 21)
——这是双重否定,但这可能不是你被要求的。
@JustinCave 我真的觉得很奇怪,Google 对此也不太了解 xD 它在查询中使用了两次NOT IN
。
【参考方案1】:
这看起来像一个关系除法查询(如果我没记错的话),您正在寻找的双重否定示例是下面的查询。基本上它可以被解读为向我展示所有不存在问题的科目,而不是在分数为 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
)
)
关于这方面的一篇好文章是:Divided We Stand: The SQL of Relational Division,作者是 Joe Celko。非常值得一读。
编辑:
我认为由于缺少连接,上面的查询执行得非常糟糕。这个版本的性能应该会好很多:
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
)
【讨论】:
由于某种原因,这个查询似乎是无限的什么的,它并没有停止执行。我明天再仔细看看。 @HugoSousa 我没有测试它,因为我没有时间设置合适的测试数据,所以它可能有一些错误 - 当我做这种类型的时候我会感到困惑查询,因为它非常不直观。如果您在问题中添加一些测试数据,我可以对其进行测试。 它实际上似乎在工作 (sqlfiddle.com/#!4/5fad4/2),但在我的环境中它并没有停止执行。这很奇怪...... 知道它可能是什么吗?我的猜测是这可能是一个巨大的性能问题,因为数据比示例中的要多得多。我让查询运行了一个多小时没有结果。 这个赋值的目的实际上是分析执行计划,但我什至不能确定这个查询会提供正确的结果。这在某处似乎是错误的!或者也许这正是预期的行为,我觉得这很奇怪。无论如何,请接受我的 +1。我有带索引和不带索引的相同表,并尝试了两者(RESPOSTA
、SEMESTRE_ID
、DISCIPLINA_ID
和 PERGUNTA_ID
列上的索引)。以上是关于SQL 查询 - 双重否定的主要内容,如果未能解决你的问题,请参考以下文章