Count Distinct返回空值(pl sql)

时间:2009-06-18 17:17:47

标签: sql oracle null count distinct

对这些查询的无意义的表/列名称进行抢先道歉。如果你曾经使用过Remedy的数据库后端,你就会理解。

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

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&lt; = 1:

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

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

任何帮助都将不胜感激。

5 个答案:

答案 0 :(得分:2)

我现在明白了。您在原始查询中的问题是,在没有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(即使有多个c1s)是相等的,但它们不是。 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&amp;的c1列的列表。 649个表条目。注意:在查询中使用DISTINCT应该非常小心。例如,在您发布上述结果的情况下,完全没有必要;通常它会作为一种壁纸来覆盖查询中的错误,这些错误不会因为WHERE子句中的错过约束而以您希望的方式返回结果(“嗯,我的查询正在为所有这些值返回dupes。嗯,a DISTINCT将解决这个问题“)。

答案 1 :(得分:1)

结果是什么:

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子句就会消除结果集中的所有行。

答案 2 :(得分:0)

COUNT(DISTINCT column)不计算NULL值:

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

---
0

可能是这样吗?

答案 3 :(得分:0)

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

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

答案 4 :(得分:0)

如果我这样做:

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的要求,查询结果如下:

row | 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子句,第一行就会被正确过滤掉。