個別カウントで返されるNULL値(PL SQL)
質問
これらのクエリの無意味なテーブル/列名に対する先制的な謝罪。 RemedyのDBバックエンドを使用したことがあれば、理解できます。
実際の値が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。
列c536870939 <!> lt; = 1:の表t649のレコードをフィルターで除外します
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値を返すクエリとまったく同じようにクエリを設定する場所がいくつかあり、完全に正常に動作します。正しい値である使用可能な数値を返します。この状況でユニークなものはすべて、実際のクエリではなくデータに関連していると仮定する必要がありますが、それを説明するためにデータで何を探すべきかわかりません。集計する前に、生データでnull値を見つけることができませんでした。他に何がこれを引き起こすのか分かりません。
ご協力いただければ幸いです。
解決
わかりました。元のクエリの問題は、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 <!> ampの数が等しいc1列のリストが表示されます。 649個のテーブルエントリ。注:クエリでDISTINCTを使用する場合は、十分に注意する必要があります。たとえば、上記の結果を投稿した場合、それは完全に不要です。多くの場合、WHERE句で制約が欠落しているために結果を返さないクエリのエラーをカバーする一種の壁紙として機能します(<!> quot;うーん、私のクエリはこれらすべての値の重複を返します。まあ、DISTINCTはその問題を解決します<!> quot;)。
他のヒント
次の結果:
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
2つの列の値が等しくない場合、HAVING句を追加すると結果セットからすべての行が削除されることになります。
COUNT(DISTINCT column)
はNULL
値をカウントしません:
SELECT COUNT(DISTINCT val1)
FROM (
SELECT NULL AS val1
FROM dual
)
---
0
それは事実ですか?
代わりに、WHERE句にHAVING句の条件を入れてみます。 HAVINGを選んだ理由はありますか?参考までに、HAVINGは、結果セットが返された後に実行されるフィルターであり、予期しない結果を引き起こす可能性があります。また、クエリの最適化にも使用されません。 HAVINGを使用する必要がない場合は、使用しないことをお勧めします。
SELECT句にカウントを追加してから、WHERE句で結合することをお勧めします。
これを行う場合:
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句を含めると、最初の行が適切に除外されます。