NOT HAVING (inverse HAVING) 子句与 Oracle 中的聚合
NOT HAVING (inverse HAVING) clause with aggregation in Oracle
我正在尝试使用 HAVING
子句过滤 GROUP BY CUBE
的结果。但是我需要保留不满足条件组合的行。
我凭直觉尝试过:
SELECT [...]
FROM [...]
NOT HAVING (flag_1 = 1 AND flag_2 = 1 AND flag_3 = 1)
GROUP BY CUBE [...]
遗憾的是 Oracle 无法将 NOT HAVING
识别为有效语法。
从数学的角度来看,反转每个单独的条件不会产生相同的结果:
HAVING (flag_1 != 1 AND flag_2 != 1 AND flag_3 != 1)
如何实现 NOT HAVING
的逻辑等效?
注意:我发现了一个有点相关的现有问题,但它特定于 Microsoft Access,目标也不相同,因此提出了这个新问题。
好吧,我考虑过根据我有时在 WHERE
中使用的基于 CASE
的类似方法进行改编。
CASE
似乎也在 HAVING
内工作!
解决方案:
SELECT [...]
FROM [...]
HAVING
CASE
WHEN flag_1 = 1 AND flag_2 = 1 AND flag_3 = 1
THEN 0
ELSE 1
END = 1
GROUP BY CUBE [...]
您的 HAVING 子句的数学逆运算要求您将 AND 更改为 OR,并且如果列可以为空,还需要进行空值检查。
EG(如果可能为空):
HAVING (nvl(flag_1,1) != 1 OR NVL(flag_2,1) != 1 OR NVL(flag_3,1) != 1)
我认为最简单的解决方案就是将其更改为 HAVING NOT ...
SELECT [...]
FROM [...]
HAVING NOT (flag_1 = 1 AND flag_2 = 1 AND flag_3 = 1)
GROUP BY CUBE [...]
但我经常发现 NOT (...)
不直观;作为替代方案,@MichaelBroughton 的回答解释了如何将逻辑从 NOT (x AND y)
反转为 NOT x OR NOT y
这与 Michael Broughton 的回答相同,我不想重复,但我认为它可以更清楚。如果他想将其中的任何内容合并到他的答案中,我很乐意删除这个。
要确定 NOT (boolean_expression) 的逻辑等价物,您可以应用德摩根定律。参见:https://en.wikipedia.org/wiki/De_Morgan%27s_laws
基本上,您将每个术语的逻辑颠倒过来,将所有 AND 更改为 OR,将所有 OR 更改为 AND。所以,
NOT (A AND B AND C) ==> (NOT A OR NOT B OR NOT C)
但是您也需要跟踪空值。过程如下:
开始于...
HAVING NOT (flag_1 = 1 AND flag_2 = 1 AND flag_3 = 1)
首先,添加关于起始表达式中存在的 NULL 的隐式假设。例如,如果 flag_1=1
,那么它当然不是 NULL。
HAVING NOT (flag_1 = 1 AND flag_1 IS NOT NULL
AND flag_2 = 1 AND flag_2 IS NOT NULL
AND flag_3 = 1 AND flag_3 IS NOT NULL)
现在,应用德摩根定律的第一部分并反转每一项的逻辑。因此,例如,flag_1 = 1
变为 flag_1 != 1
...
HAVING (flag_1 != 1 AND flag_1 IS NULL
AND flag_2 != 1 AND flag_2 IS NULL
AND flag_3 != 1 AND flag_3 IS NULL)
最后,应用 De Morgan 定律的第二部分并切换所有 AND->OR,反之亦然...
HAVING (flag_1 != 1 OR flag_1 IS NULL
OR flag_2 != 1 OR flag_2 IS NULL
OR flag_3 != 1 OR flag_3 IS NULL)
这就是你的答案。
NOT (flag_1 = 1 AND flag_2 = 1 AND flag_3 = 1)
怎么样?
这是行不通的,因为它没有像人们预期的那样处理空值。在 Oracle 中,任何与 null 的比较都是错误的。所以,
(1 = NULL) ... false
NOT (1 = NULL) ... also false
因此 flag_1
和 flag_2
都等于 1 但 flag_3
null 的行不会显示在您的结果中。
我正在尝试使用 HAVING
子句过滤 GROUP BY CUBE
的结果。但是我需要保留不满足条件组合的行。
我凭直觉尝试过:
SELECT [...]
FROM [...]
NOT HAVING (flag_1 = 1 AND flag_2 = 1 AND flag_3 = 1)
GROUP BY CUBE [...]
遗憾的是 Oracle 无法将 NOT HAVING
识别为有效语法。
从数学的角度来看,反转每个单独的条件不会产生相同的结果:
HAVING (flag_1 != 1 AND flag_2 != 1 AND flag_3 != 1)
如何实现 NOT HAVING
的逻辑等效?
注意:我发现了一个有点相关的现有问题,但它特定于 Microsoft Access,目标也不相同,因此提出了这个新问题。
好吧,我考虑过根据我有时在 WHERE
中使用的基于 CASE
的类似方法进行改编。
CASE
似乎也在 HAVING
内工作!
解决方案:
SELECT [...]
FROM [...]
HAVING
CASE
WHEN flag_1 = 1 AND flag_2 = 1 AND flag_3 = 1
THEN 0
ELSE 1
END = 1
GROUP BY CUBE [...]
您的 HAVING 子句的数学逆运算要求您将 AND 更改为 OR,并且如果列可以为空,还需要进行空值检查。
EG(如果可能为空):
HAVING (nvl(flag_1,1) != 1 OR NVL(flag_2,1) != 1 OR NVL(flag_3,1) != 1)
我认为最简单的解决方案就是将其更改为 HAVING NOT ...
SELECT [...]
FROM [...]
HAVING NOT (flag_1 = 1 AND flag_2 = 1 AND flag_3 = 1)
GROUP BY CUBE [...]
但我经常发现 NOT (...)
不直观;作为替代方案,@MichaelBroughton 的回答解释了如何将逻辑从 NOT (x AND y)
反转为 NOT x OR NOT y
这与 Michael Broughton 的回答相同,我不想重复,但我认为它可以更清楚。如果他想将其中的任何内容合并到他的答案中,我很乐意删除这个。
要确定 NOT (boolean_expression) 的逻辑等价物,您可以应用德摩根定律。参见:https://en.wikipedia.org/wiki/De_Morgan%27s_laws
基本上,您将每个术语的逻辑颠倒过来,将所有 AND 更改为 OR,将所有 OR 更改为 AND。所以,
NOT (A AND B AND C) ==> (NOT A OR NOT B OR NOT C)
但是您也需要跟踪空值。过程如下:
开始于...
HAVING NOT (flag_1 = 1 AND flag_2 = 1 AND flag_3 = 1)
首先,添加关于起始表达式中存在的 NULL 的隐式假设。例如,如果 flag_1=1
,那么它当然不是 NULL。
HAVING NOT (flag_1 = 1 AND flag_1 IS NOT NULL
AND flag_2 = 1 AND flag_2 IS NOT NULL
AND flag_3 = 1 AND flag_3 IS NOT NULL)
现在,应用德摩根定律的第一部分并反转每一项的逻辑。因此,例如,flag_1 = 1
变为 flag_1 != 1
...
HAVING (flag_1 != 1 AND flag_1 IS NULL
AND flag_2 != 1 AND flag_2 IS NULL
AND flag_3 != 1 AND flag_3 IS NULL)
最后,应用 De Morgan 定律的第二部分并切换所有 AND->OR,反之亦然...
HAVING (flag_1 != 1 OR flag_1 IS NULL
OR flag_2 != 1 OR flag_2 IS NULL
OR flag_3 != 1 OR flag_3 IS NULL)
这就是你的答案。
NOT (flag_1 = 1 AND flag_2 = 1 AND flag_3 = 1)
怎么样?
这是行不通的,因为它没有像人们预期的那样处理空值。在 Oracle 中,任何与 null 的比较都是错误的。所以,
(1 = NULL) ... false
NOT (1 = NULL) ... also false
因此 flag_1
和 flag_2
都等于 1 但 flag_3
null 的行不会显示在您的结果中。