1

对这些查询中无意义的表/列名称先发制人地道歉。如果您曾经使用过 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 <= 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)

结果 = 空。

如果我运行以下查询,我在结果列表中看不到任何可以解释为什么我没有得到任何类型的返回值的内容。即使我从 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

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

任何帮助,将不胜感激。

4

5 回答 5

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(即使有多个 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 将解决这个问题”)。

于 2009-06-18T18:52:41.977 回答
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 子句将从结果集中删除所有行是有意义的。

于 2009-06-18T17:34:28.063 回答
0

COUNT(DISTINCT column) doesn't count NULL values:

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

---
0

Could it be the case?

于 2009-06-18T17:23:47.157 回答
0

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

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

于 2009-06-18T17:33:46.957 回答
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 条件的额外行。

编辑:查询的结果,根据史蒂夫布罗伯格的要求:

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

于 2009-06-18T17:45:01.697 回答