2016-12-22 8 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); 

좋아, 그럼 거기에 7 애완 동물 총 :

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

이제 큐브의 전체 행을보고 :

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 * 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 개의 모두 null 행이 있습니다. 두 번째 것은 내가 원했던 대답이다.

여기에 무슨 일이 일어나고 있는지 잘 알고 있습니다. NULL 값은 두 가지 다른 것을 알려주는 데 사용됩니다 ("큐브가이 열의 값을 모두 굴림"또는 "이 행에 오른쪽 테이블에 자식이 없음"). . 나는 그것을 고치는 법을 모른다.

답변

2

NULL 값 ("이 행은 에는 아이들 오른쪽 테이블이 없습니다" "큐브 이 모든 열 값을 올리고있다"또는) 다른 두 가지 신호하는 데 사용됩니다. 나타내는 https://www.postgresql.org/docs/9.6/static/functions-aggregate.html#FUNCTIONS-GROUPING-TABLE

GROUPING (인수 ...) 정수 비트 마스크 :

다른 널에서 하나의 널 (null)을 구별하기 위해

, 여기 표 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  |