2009-06-18 9 views
1

これらのクエリで無意味な表/列名が使用されていることを前向きにお詫び申し上げます。あなたがRemedyのDBバックエンドで作業したことがあるなら、あなたは理解するでしょう。Count Distinct(pl sql)でヌル値が返される

私は実際の値が20のどこかにあるはずだと思うとCount Distinctがnull値を返すという問題があります(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 < = 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 
HAVINGステートメントの

結果= 24

フィルタ:= nullを

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 

私は正確にnull値を返すと、それは完全に正常に動作しているもののようクエリを設定している他のいくつかの場所がある - 正しい値であり、使用可能な番号を返します。私は、この状況で一意であるものは、実際のクエリではなくデータに関連していると仮定しなければならないと思いますが、データで何を調べて説明するのかはわかりません。私は、集計前に生データ内にヌル値を見つけることができませんでした。他に何が起こるか分からない。

ご協力いただければ幸いです。

+1

HAVINGステートメントのt631のカウントは、実際にはt649のカウントと同じですか? – northpole

+0

選択と実行の両方のカウントの区別を入れます。カウントは一致しますか?そうでなければ結果が得られません。 – xQbert

答えて

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) 
     ); 

これはあなたの同じ番号を持っているのC1列のリストを与えます631 & 649テーブルエントリ。注:問合せでDISTINCTを使用する場合は、非常に注意が必要です。たとえば、上記の結果を投稿した場合は、まったく必要ありません。 WHERE句の制約が逸脱したために望むように結果を返さないクエリのエラーをカバーする壁紙の一種として機能することがよくあります(「うーん、私のクエリはこれらすべての値に対してダブを返しています。 DISTINCTはその問題を解決します ")。

+0

編集:あなたが元々探していたカウントを返すために私の最終的なクエリを修正しました。 –

+0

さて、私は理解していると思います。クエリが動作していた場所(WHERE句の異なるセット)のように見えますが、結果セットはHAVINGの有無と同じです。 あなたが提供したばかりのクエリは、カウントだけでなく個々の行を与えますが、SELECT COUNT(*)FROM(クエリ)にそのクエリをラップすると、必要な結果が得られます。 – Dave

+0

ハ。それに私を打つ。 :-) – Dave

0

COUNT(DISTINCT column)NULL値はカウントされません。

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

--- 
0 

それはケースだろうか?

0

代わりにWHERE節にHAVING節条件を入れてみます。 HAVINGを選択した理由はありますか?ちょうどFYI、HAVINGは結果セットが返された後に行われるフィルターであり、予期しない結果を引き起こす可能性があります。また、クエリの最適化にも使用されません。 HAVINGを使用する必要がない場合は、使用しないことをお勧めします。

私は、SELECT句にカウントを追加し、WHERE句にそれらを追加することをお勧めします。

+0

(A)HAVINGを使用しているので、集計関数の条件、つまりCOUNTを実行できます。 (B)あなたが他のDBMSにあなたの情報を載せているのかどうかは分かりませんが、OracleではHAVING節が他のものと一緒に解析され、最適化されたクエリの一部です。 –

+0

ORACLEでは、SQL文はWHERE句とOracle HAVING句の両方を使用できます。 WHERE句は、表から選択された行をフィルタリングし、グループ化する前に、Oracle HAVING句はグループ化後の行をフィルタ処理します。 – northpole

+0

さらに、HAVINGは集約用であり、MySQLまたはORACLEでのクエリの最適化には使用されません。 – northpole

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句は、結果セットからすべての行を排除するという意味があります。

+0

4および3である。次のコメントを参照してください。 – Dave

+1

また、HAVING節がすべての行を削除したとしても、nullではなく0が返されるべきですか? – Dave

+1

クエリは機能的にはSELECT x FROM(SELECT 3 AS x、4 y y FROM dual)のようなものと等価です。結果セットには2つの列を持つ1つの行(count(*)の結果)があり、それらが等しい行を表示するとします。等しくなければ、行は返されません。 1つの場所で0を取得している場合は、両方の列のカウント(*)がそれぞれ0であるためである必要があります。 –

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ステートメントを削除すると、HAVING基準を満たさない追加の行が24行戻されます。

EDIT:スティーブ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句が含まれている場合、最初の行が適切に除外されます。

+0

23行しかない場合、そのクエリの結果を含めることはできますか? –

+0

以下の回答を参照してください。 – Dave

+0

またはこの編集されたポスト...まだこのサイトを使用する方法を学ぶ。 – Dave

関連する問題