2012-05-10 13 views
7

私は、レポートを見やすくするためにSQLクエリを改良しようとしています。私のクエリは、1つのテーブルからデータを読み取り、いくつかの列でグループ化し、いくつかの集計フィールド(カウントと合計)を計算します。SQLで空の集計結果を生成する方法

SELECT A, B, C, COUNT(*), SUM(D) FROM T 
GROUP BY A, B, C 
ORDER BY A, B, C 

それでは、BとC列がいくつか定義された定数文字列である、例えば、 Bは'B1'または'B2'ことができると仮定しましょう、Cは'C1'または'C2'ことができます。私はすべての4つの可能性(B、C)の組み合わせを持っている'A1'ため

A | B | C | COUNT(*) | SUM(D) 
-------------------------------- 
A1 | B1 | C1 |  34 | 1752 
A1 | B1 | C2 |  4 | 183 
A1 | B2 | C1 |  199 | 8926 
A1 | B2 | C2 |  56 | 2511 
A2 | B1 | C2 |  6 |  89 
A2 | B2 | C2 |  12 | 231 
A3 | B1 | C1 |  89 | 552 
... 

あなたが見ることができるように、それは'A2'のために真実ではない:だから、例の結果セットです。私の質問は:どのように(B、C)の組み合わせのサマリー行も、実際には、特定のテーブルに存在しない生成することができますか?

A | B | C | COUNT(*) | SUM(D) 
-------------------------------- 
A2 | B1 | C1 |  0 |  0 
A2 | B2 | C1 |  0 |  0 

私が見ることができる唯一のソリューションは、すべての(B、C)の値をいくつかauxiliarityテーブルを作成し、RIGHT OUTERがでJOINをすることです:それは私が印刷することができ、例えば、また、これらの行か、ありますその補助テーブル。しかし、私はよりクリーンな方法を探しています...

ありがとうございます。

+0

あなたはmssql、oracel、mysqlを使っていますか?オラクル社 – Arion

+0

。しかし、クエリは現時点では標準的な方法で書かれています(MySQL上でも実行されますが、質問には関係のない理由でDBのMySQLコピーがあります)。 –

+0

[this](http://www.techrepublic.com/article/group-by-grouping-sets-for-custom-rollups-in-oracle/6134424)が役立つかもしれません。グループ化セットは、SQL ServerとOracleの両方で使用できます。 MySQLについてはわかりません。 –

答えて

2

補助テーブルは実際のテーブルである必要はありません。少なくとも、テーブル自体からすべての可能な値(または興味があるものすべて)を取得できる場合は、共通のテーブル式にすることができます。あなたが表にではないかもしれない値を修正した場合、それはとにかくもう少し複雑な(または醜悪だ、と悪化し

WITH CTE AS (
    SELECT * FROM (SELECT DISTINCT a FROM T) 
    JOIN (SELECT DISTINCT b, c FROM T) ON (1 = 1) 
) 
SELECT CTE.A, CTE.B, CTE.C, 
    SUM(CASE WHEN T.A IS NULL THEN 0 ELSE 1 END), NVL(SUM(T.D),0) 
FROM CTE 
LEFT JOIN T ON T.A = CTE.A AND T.B = CTE.B AND T.C = CTE.C 
GROUP BY CTE.A, CTE.B, CTE.C 
ORDER BY CTE.A, CTE.B, CTE.C; 

:すべての可能な組み合わせを生成する@Bob Jarvisのクエリを使用して、あなたのような何かを行うことができます

WITH CTE AS (
    SELECT * FROM (SELECT DISTINCT a FROM T) 
    JOIN (SELECT 'B1' AS B FROM DUAL 
     UNION ALL SELECT 'B2' FROM DUAL) ON (1 = 1) 
    JOIN (SELECT 'C1' AS C FROM DUAL 
     UNION ALL SELECT 'C2' FROM DUAL) ON (1 = 1) 
) 
SELECT CTE.A, CTE.B, CTE.C, 
    SUM(CASE WHEN T.A IS NULL THEN 0 ELSE 1 END), NVL(SUM(T.D),0) 
FROM CTE 
LEFT JOIN T ON T.A = CTE.A AND T.B = CTE.B AND T.C = CTE.C 
GROUP BY CTE.A, CTE.B, CTE.C 
ORDER BY CTE.A, CTE.B, CTE.C; 

しかし、あなたは「行方不明」の値を知っている何かに参加する必要があります。)以上の可能な値を持ちます。他の場所で同じロジックが必要で、値が固定されている場合は、永久的なテーブルがきれいになるかもしれません。どちらかの方法でメンテナンスが必要な場合があります。パイプライン関数を代理テーブルとして機能させることも考えられますが、おそらくボリュームに依存します。

+1

テーブル自体にはすべての可能性が含まれています。明らかに、私はDBエンジンがそれらを "推測"するとは期待していませんでした。 +1は面白い使い方 'WITH'のために、私は前にtを見たことがない。 –

1

データベースに特定の組み合わせがない場合、その組み合わせを結果に含める方法をエンジンがどのように知っていますか?結果にすべての組み合わせを含めるには、メインテーブルまたは参照用に使用される他のテーブルのいずれであれ、すべての組み合わせを使用できるようにする必要があります。

A | B | C 
------------ 
A1 | B1 | C1 
A1 | B1 | C2 
A1 | B2 | C1 
A1 | B2 | C2 
A2 | B1 | C1 
A2 | B1 | C2 
A2 | B2 | C1 
A2 | B2 | C2 
A3 | B1 | C1 
A3 | B1 | C2 
A3 | B1 | C1 
A3 | B2 | C2 
... 

そしてあなたのクエリは次のようになります:あなたが組み合わせに対して0 | 0にしたいと

SELECT r.*, COUNT(t.d), coalesce(SUM(t.d), 0) 
FROM r LEFT OUTER JOIN t on (r.a=t.a and r.b=t.b and r.c=t.c) 
GROUP BY r.a, r.b, r.c 
ORDER BY r.a, r.b, r.c 

これは、あなたのセットを返します。たとえば、あなたはそうのようなデータを持つ別のテーブルRを作成することができますメインテーブルには存在しません。これは、含める可能性のあるすべての組み合わせがわかっている場合にのみ可能であり、常にそうであるとは限りません。

一方、あなたのAに、B、Cは数値であり、あなただけの範囲内のすべての数字を含めたい場合は、これに対処する別の方法があるかもしれない、このような何か:

SELECT a.n, b.n, c.n, COUNT(t.d), coalesce(SUM(t.d), 0) 
FROM (SELECT (rownum) "n" FROM DUAL WHERE LEVEL >= start_a CONNECT BY LEVEL <= end_a) a, 
    (SELECT (rownum) "n" FROM DUAL WHERE LEVEL >= start_b CONNECT BY LEVEL <= end_b) b, 
    (SELECT (rownum) "n" FROM DUAL WHERE LEVEL >= start_c CONNECT BY LEVEL <= end_c) c, 
    t 
WHERE a.n = t.a(+) AND b.n = t.b(+) AND c.n = t.c(+) 
GROUP BY a.n, b.n, c.n 
ORDER BY a.n, b.n, c.n 

最後の行は、エンジンが最終的なものに何を含める必要があるかを知る必要があることです(これは、テストするのに便利なOracleインスタンスを持っていません)。結果 - 一方的または別のもの

+0

これは私が今やっている方法です。私の質問の最後の段落を参照してください。 –

+0

@ lorenzo-s主な問題は、すべての有効な組み合わせを指定しなければ、エンジンは知ることができないため、この一時テーブルを持つ必要があるということです。 –

+0

テーブル自体(すべての行を考慮)に(B、C)値のすべての組み合わせが含まれています。 –

0

あり、これを行うにはきれいな方法は、おそらくですが、次はあなたが何をしたい方に始める必要があります。

SELECT * FROM 
    (SELECT DISTINCT a FROM T) 
JOIN 
    (SELECT DISTINCT b, c FROM T) 
    ON (1 = 1) 
ORDER BY a, b, c 

は、これはあなたにBとCの存在するすべての組み合わせを与える、すべてのAの存在と一緒になって、類似して

A1 B1 C1 
A1 B1 C2 
A1 B2 C1 
A1 B2 C2 
A2 B1 C1 
A2 B1 C2 
A2 B2 C1 
A2 B2 C2 

と共有し、楽しんでください。

+0

私は何かを探しています(そして、私はそれをexixtsと仮定していません!)。これは、参加かそうでないのですか?私は現在あなたが結果を達成するために書いたもののようなテーブルを使用しています。私の質問の最後の段落を参照してください。 –

+0

ここでの問題は異なります。テーブルTにすべての可能な組み合わせが含まれていればOKですが、そうでない場合は正方形に戻ります。どうやらDBエンジンは、すべての可能な組み合わせが何であるかを知る必要があります。 –

+0

@AleksGオクラホマ、この問題はありません。すべての行を考慮した表自体に(B、C)値のすべての組み合わせが含まれています。明らかに、私はDBエンジンがそれらを "推測"するとは期待していませんでした。 –

関連する問題