【问题标题】:Null value returned on Count Distinct (pl sql)在 Count Distinct (pl sql) 上返回 Null 值
【发布时间】:2009-06-18 17:17:47
【问题描述】:

对这些查询中无意义的表/列名称先发制人地道歉。如果您曾经使用过 Remedy 的数据库后端,您就会明白。

当我怀疑实际值应该在 20 的某个位置(我相信是 23)时,我遇到了 Count Distinct 返回空值的问题。下面是一系列查询及其返回值。

SELECT count(distinct t442.c1)
      FROM t442, t658, t631
     WHERE t442.c1 = t658.c536870930
       AND t442.c200000003 = 'Network'
       AND t442.c536871139 < 2
       AND t631.c536870913 = t442.c1
       AND t658.c536870925 = 1
       AND (t442.c7 = 6 OR t442.c7 = 5)
       AND t442.c536870954 > 1141300800
       AND (t442.c240000010 = 0)

结果 = 497。

添加表 t649 并确保它具有链接回表 t442 的记录:

 SELECT COUNT (DISTINCT t442.c1)
              FROM t442, t658, t631, t649
             WHERE t442.c1 = t658.c536870930
               AND t442.c200000003 = 'Network'
               AND t442.c536871139 < 2
               AND t631.c536870913 = t442.c1
               AND t658.c536870925 = 1
               AND (t442.c7 = 6 OR t442.c7 = 5)
               AND t442.c536870954 > 1141300800
               AND (t442.c240000010 = 0)
               AND t442.c1 = t649.c536870914

结果 = 263。

过滤掉表 t649 中的记录,其中列 c536870939

SELECT COUNT (DISTINCT t442.c1)
          FROM t442, t658, t631, t649
         WHERE t442.c1 = t658.c536870930
           AND t442.c200000003 = 'Network'
           AND t442.c536871139 < 2
           AND t631.c536870913 = t442.c1
           AND t658.c536870925 = 1
           AND (t442.c7 = 6 OR t442.c7 = 5)
           AND t442.c536870954 > 1141300800
           AND (t442.c240000010 = 0)
           AND t442.c1 = t649.c536870914
           AND t649.c536870939 > 1

结果 = 24。

过滤 HAVING 语句:

SELECT COUNT (DISTINCT t442.c1)
          FROM t442, t658, t631, t649
         WHERE t442.c1 = t658.c536870930
           AND t442.c200000003 = 'Network'
           AND t442.c536871139 < 2
           AND t631.c536870913 = t442.c1
           AND t658.c536870925 = 1
           AND (t442.c7 = 6 OR t442.c7 = 5)
           AND t442.c536870954 > 1141300800
           AND (t442.c240000010 = 0)
           AND t442.c1 = t649.c536870914
           AND t649.c536870939 > 1
        HAVING COUNT (DISTINCT t631.c536870922) =
                                              COUNT (DISTINCT t649.c536870931)

结果 = null。

如果我运行以下查询,我在结果列表中看不到任何可以解释为什么我没有得到任何类型的返回值的内容。即使我从 SELECT 中删除了 DISTINCT,也是如此。 (我分别得到 25 和 4265 行数据)。

SELECT DISTINCT t442.c1, t631.c536870922, t649.c536870931
          FROM t442, t658, t631, t649
         WHERE t442.c1 = t658.c536870930
           AND t442.c200000003 = 'Network'
           AND t442.c536871139 < 2
           AND t631.c536870913 = t442.c1
           AND t658.c536870925 = 1
           AND (t442.c7 = 6 OR t442.c7 = 5)
           AND t442.c536870954 > 1141300800
           AND (t442.c240000010 = 0)
           AND t442.c1 = t649.c536870914
           AND t649.c536870939 > 1

我在其他几个地方设置了与返回空值的查询完全相同的查询,并且它工作得非常好——返回正确值的可用数字。我必须假设在这种情况下任何独特之处都与数据有关,而不是与实际查询有关,但我不确定在数据中寻找什么来解释它。在聚合之前,我无法在原始数据中找到任何空值。我不知道还有什么会导致这种情况。

任何帮助将不胜感激。

【问题讨论】:

  • 在 HAVING 语句中 t631 的计数实际上是否等于 t649 的计数?
  • 将两个不同的计数放在选择中并运行。计数是否匹配?如果不是这就是为什么你没有得到任何结果。

标签: sql oracle null count distinct


【解决方案1】:

我现在明白了。您在原始查询中的问题是,在没有 GROUP BY 子句的情况下使用 HAVING 子句是非常不寻常的(如果不是,实际上是错误的)。答案在于执行查询的各个部分的操作顺序。

在原始查询中,您可以这样做:

SELECT COUNT(DISTINCT t442.c1)
  FROM ...
 WHERE ...
HAVING COUNT(DISTINCT t631.c536870922) = COUNT(DISTINCT t649.c536870931);

数据库将执行您的连接和约束,此时它将执行任何分组和聚合操作。在这种情况下,您没有进行分组,因此 COUNT 操作跨越整个数据集。根据您在上面发布的值,COUNT(DISTINCT t631.c536870922) = 25 和 COUNT(DISTINCT t649.c536870931) = 24。现在应用了 HAVING 子句,导致没有匹配项 - 您询问总数的情况set(即使有多个 c1)是相等的,但它们不是。 DISTINCT 被应用到一个空的结果集,你什么也得不到。

您真正想要做的只是您在示例中发布的内容的一个版本,它会吐出行数:

SELECT count(*)
  FROM (SELECT t442.c1     
          FROM t442
             , t658
             , t631
             , t649
         WHERE t442.c1 = t658.c536870930
           AND t442.c200000003 = 'Network'
           AND t442.c536871139 < 2
           AND t631.c536870913 = t442.c1
           AND t658.c536870925 = 1
           AND (   t442.c7 = 6
                OR t442.c7 = 5)
           AND t442.c536870954 > 1141300800
           AND (t442.c240000010 = 0)
           AND t442.c1 = t649.c536870914
           AND t649.c536870939 > 1
         GROUP BY t442.c1
        HAVING COUNT(DISTINCT t631.c536870922) = COUNT(DISTINCT t649.c536870931)
       );

这将为您提供具有相同数量的 631 和 649 表条目的 c1 列的列表。注意:您应该非常小心在查询中使用 DISTINCT。例如,在您发布上述结果的情况下,完全没有必要;通常,它充当一种墙纸,以覆盖由于 WHERE 子句中缺少约束而无法以您想要的方式返回结果的查询中的错误(“嗯,我的查询正在返回所有这些值的欺骗。嗯,一个DISTINCT 将解决这个问题”)。

【讨论】:

  • 编辑:修复了我的最终查询以返回您最初寻找的计数。
  • 好的,我想我明白了。它看起来确实像查询工作的地方(在那些地方有不同的 WHERE 子句集),结果集在有或没有 HAVING 的情况下是相同的。您刚刚提供的查询提供了各个行,而不仅仅是计数,但是如果我将该查询包装在 SELECT COUNT(*) FROM (query) 中,我会得到我需要的结果。
  • +1,干得好。这个让我很困扰。我只是想不通。谢谢你的课:D
【解决方案2】:

结果是什么:

SELECT COUNT (DISTINCT t631.c536870922),
       COUNT (DISTINCT t649.c536870931)
          FROM t442, t658, t631, t649
         WHERE t442.c1 = t658.c536870930
           AND t442.c200000003 = 'Network'
           AND t442.c536871139 < 2
           AND t631.c536870913 = t442.c1
           AND t658.c536870925 = 1
           AND (t442.c7 = 6 OR t442.c7 = 5)
           AND t442.c536870954 > 1141300800
           AND (t442.c240000010 = 0)
           AND t442.c1 = t649.c536870914
           AND t649.c536870939 > 1

如果那里的两列永远不会有相等的值,那么添加 HAVING 子句将消除结果集中的所有行是有意义的。

【讨论】:

  • 4 和 3,分别。请参阅下一条评论。
  • 另外,即使 HAVING 子句确实消除了所有行,我不应该得到 0 而不是 null 吗?我使用此查询的其他地方之一确实正确返回 0。
  • 您的查询在功能上等同于 SELECT x FROM (SELECT 3 AS x, 4 as y FROM dual) WHERE x = y。您的结果集有一行(count() 结果),有两列,您是说向我展示它们相等的行。如果它们不相等,则不返回任何行。如果你在一个地方得到一个 0,那一定是因为这两个列的 count() 都是 0。
【解决方案3】:

COUNT(DISTINCT column) 不计算 NULL 值:

SELECT  COUNT(DISTINCT val1)
FROM    (
        SELECT  NULL AS val1
        FROM    dual
        )

---
0

会是这样吗?

【讨论】:

    【解决方案4】:

    我会尝试将 HAVING 子句条件放在 WHERE 子句中。你选择HAVING有什么理由吗?仅供参考,HAVING 是在返回结果集后完成的过滤器,这可能会导致意外结果。它也不用于优化查询。如果您不必使用 HAVING,我建议您不要使用它。

    我建议将计数添加到 SELECT 子句中,然后将它们加入到 WHERE 子句中。

    【讨论】:

    • (A) 他正在使用 HAVING,所以他可以对聚合函数做一个条件,即 COUNT。 (B) 我不知道您的信息是否基于其他 DBMS,但在 Oracle 中,HAVING 子句肯定是查询的一部分,它与其他所有内容一起被解析和优化。
    • 在 ORACLE 中,SQL 语句可以使用 WHERE 子句和 Oracle HAVING 子句。 WHERE 子句将过滤从表中选择的行,在分组之前,Oracle HAVING 子句将过滤分组后的行。
    • 另外,HAVING用于聚合,不用于MySQL或ORACLE中的查询优化。
    • 将 HAVING 子句放在 WHERE 中会引发错误。 ORA-00934: 此处不允许使用组功能
    • 不,我的意思是把 HAVING 全部删除并使用 SELECT 和 WHERE 子句来处理它
    【解决方案5】:

    如果我这样做:

    SELECT distinct t442.c1, count(distinct t631.c536870922), 
        count (distinct t649.c536870931)
              FROM t442, t658, t631, t649
             WHERE t442.c1 = t658.c536870930
               AND t442.c200000003 = 'Network'
               AND t442.c536871139 < 2
               AND t631.c536870913 = t442.c1
               AND t658.c536870925 = 1
               AND (t442.c7 = 6 OR t442.c7 = 5)
               AND t442.c536870954 > 1141300800
               AND (t442.c240000010 = 0)
               AND t442.c1 = t649.c536870914
               AND t649.c536870939 > 1
               group by t442.c1
               having count(distinct t631.c536870922)= 
                             count (distinct t649.c536870931)
    

    我看到应该计算的 23 行。删除 HAVING 语句将返回 24 行,即不符合 HAVING 条件的额外行。

    编辑: 根据 Steve Broberg 的要求,查询结果:

    行 | t442.c1 | cnt t631 | cnt 649 ------------------------------------------ 1 | CHG000000230378 | 2 | 1 2 | CHG000000230846 | 1 | 1 3 | CHG000000232562 | 1 | 1 4 | CHG000000232955 | 1 | 1 5 | CHG000000232956 | 1 | 1 6 | CHG000000232958 | 1 | 1 7 | CHG000000233027 | 1 | 1 8 | CHG000000233933 | 1 | 1 9 | CHG000000233934 | 1 | 1 10 | CHG000000233997 | 1 | 1 11 | CHG000000233998 | 1 | 1 12 | CHG000000233999 | 1 | 1 13 | CHG000000234001 | 1 | 1 14 | CHG000000234005 | 1 | 1 15 | CHG000000234009 | 1 | 1 16 | CHG000000234012 | 1 | 1 17 | CHG000000234693 | 1 | 1 18 | CHG000000234696 | 1 | 1 19 | CHG000000234730 | 1 | 1 20 | CHG000000234839 | 1 | 1 21 | CHG000000235115 | 1 | 1 22 | CHG000000235224 | 1 | 1 23 | CHG000000235488 | 1 | 1 24 | CHG000000235847 | 1 | 1

    如果我包含 HAVING 子句,第一行将被正确过滤掉。

    【讨论】:

    • 鉴于只有 23 行,您能否包含该查询的结果?
    • 或者只是这个编辑过的帖子...还在学习如何使用这个网站。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-04
    • 2013-05-06
    • 2015-02-21
    相关资源
    最近更新 更多