2016-12-22 16 views
1

OUTER JOINを使用するクエリでPostgreSQLのCUBEを使用すると、キューブ自身の「すべてが結合された」全NULL結果と区別できない余分なすべてのNULL行が生成されます。CUBE +外部結合=余分なNULL行

CREATE TABLE species 
    (id SERIAL PRIMARY KEY, 
    name TEXT); 

CREATE TABLE pet 
    (species_id INTEGER REFERENCES species(id), 
    is_adult BOOLEAN, 
    number  INTEGER) 
; 

INSERT INTO species VALUES 
    (1, 'cat'), (2, 'dog'); 

INSERT INTO pet VALUES 
    (1, true, 3), (1, false, 1), (2, true, 1), (null, true, 2); 

OK、そう7匹のペットがあるが合計:

SELECT * FROM (
     SELECT name, is_adult, SUM(number) 
     FROM pet p 
     JOIN species s ON (p.species_id = s.id) 
     GROUP BY CUBE (name, is_adult)) subq 
WHERE name IS NULL 
AND is_adult IS NULL; 

name | is_adult | sum 
------+----------+----- 
     |   | 5 
(1 row) 

5ペット:

SELECT SUM(number) FROM pet; 
sum 
----- 
    7 
(1 row) 

は今、キューブの合計行を見て?ああ、そうです。種のないペットは含まれていないからです。私は外部結合が必要です。

SELECT * FROM (
     SELECT name, is_adult, SUM(number) 
     FROM pet p 
     LEFT OUTER JOIN species s ON (p.species_id = s.id) 
     GROUP BY CUBE (name, is_adult)) subq 
WHERE name IS NULL 
AND is_adult IS NULL; 

name | is_adult | sum 
------+----------+----- 
     |   | 2 
     |   | 7 
(2 rows) 

マイキューブには2つの全ヌル行があります。 2番目は私が望む答えです。

私はここで何が起こっているのか理解しています:NULL値は、2つの異なることを伝えるために使用されます(「キューブはこの列の値をすべてロールアップしました」または「この行には右側テーブルに子がありません」) 。私はちょうどそれを修正する方法を知らない。

答えて

2

NULL値が(「キューブが はすべてこの列の値をロールアップしている」または「この列は 右サイドテーブルの子を持たない」)は、2つの異なるものを知らせるために使用されています。 (引数...)整数ビットマスクを示すをグループ化https://www.postgresql.org/docs/9.6/static/functions-aggregate.html#FUNCTIONS-GROUPING-TABLE

を:

他のヌルから1つのヌルを区別するために、あなたはここで表9-55を参照してください、grouping(...)機能を使用することができます引数 が現在のグループ化セットに含まれていない

グループ化 操作は、結果セットを区別するためにグループ化セット(セクション 7.2.4を参照)と組み合わせて使用​​されます。 GROUPING操作の引数は実際には評価されませんが、関連するクエリ レベルのGROUP BY句に指定された式 と正確に一致する必要があります。ビットは、最も右の引数が 最下位ビットで割り当てられます。対応する式 が、結果行である を生成するグルーピングセットのグループ化基準に含まれている場合は0になり、そうでない場合は1になります。


name | is_adult | sum 
------+----------+----- 
     |   | 2 
     |   | 7 

もう一つは、私が望んでいた答えです。

これを試してみてください:

SELECT name, is_adult, SUM(number) 
FROM pet p 
LEFT OUTER JOIN species s ON (p.species_id = s.id) 
GROUP BY CUBE (name, is_adult) 
HAVING grouping(name,is_adult) = 3 

name |is_adult |sum | 
-----|---------|-----| 
    |   |7 | 

grouping機能がどのように動作するかを学ぶために、このクエリを検討してください

SELECT name, is_adult, SUM(number), grouping(name,is_adult) 
FROM pet p 
LEFT OUTER JOIN species s ON (p.species_id = s.id) 
GROUP BY CUBE (name, is_adult) 

name |is_adult |sum |grouping | 
-----|---------|----|---------| 
cat |false |1 |0  | 
cat |true  |3 |0  | 
cat |   |4 |1  | 
dog |true  |1 |0  | 
dog |   |1 |1  | 
    |true  |2 |0  | 
    |   |2 |1  | 
    |   |7 |3  | 
    |false |1 |2  | 
    |true  |6 |2  | 
関連する問題