Post List

2015년 1월 9일 금요일

GROUP BY 와 HAVING 절

WHERE 필터를 통한 후 파생된 입력 테이블 GROUP BY 절에 그룹화하고 또한 HAVING 절을 사용하여 필요없는 그룹을 제거할 수 있습니다.
SELECT select_list
    FROM ...
    [WHERE ...]
    GROUP BY grouping_column_reference [, grouping_column_reference]...
 GROUP BY 절 은 테이블에서 선택된 모든 열에서 같은 값을 소유한 행을 그룹화하는 데 사용됩니다. 열의 열거 순서는 상관 없습니다. 이것은 일반적인 값을 가지는 각각의 행 집합을 그룹 내의 모든 행을 대표하는 1 개의 그룹 행에 정리 효과가 있습니다. 그러면 출력 중복을 제거하고, 또한 이들 그룹에 적용되는 집계가 계산됩니다. 예를 들면 다음과 같습니다.
=> SELECT * FROM test1;
 x | y
---+---
 a | 3
 c | 2
 b | 5
 a | 1
(4 rows)

=> SELECT x FROM test1 GROUP BY x;
 x
---
 a
 b
 c
(3 rows)

2 번째 질의는 SELECT * FROM test1 GROUP BY x로 쓸 수 없습니다. 각 그룹에 관련된 열 y의 값이 없기 때문입니다. 그룹마다 하나의 값을 가지므로, 선택 목록에서 GROUP BY에 지정된 열을 참조할 수 있습니다.
일반적으로 테이블이 그룹화되는 경우, GROUP BY에 열거되지 않은 열은 집계 식을 제외하고 볼 수 없습니다. 집계식의 예는 다음과 같습니다.
=> SELECT x, sum(y) FROM test1 GROUP BY x;
 x | sum
---+-----
 a |   4
 b |   5
 c |   2
(3 rows) 
위에서 sum()은 그룹 전체에 대해 단일 값을 계산하는 집계 함수입니다. 사용할 수 있는 집계 함수에 대한 자세한 내용은 섹션 9.18 을 참조하십시오.
Tip : 집계식을 사용하지 그룹화는 열의 중복되지 않는 값의 집합을 효율적으로 계산합니다. 이것은 DISTINCT 절의 사용과 동일합니다 ( 섹션 7.3.3 을 참조하십시오).
다른 예입니다. 이것은 각 제품의 총 매출을 계산합니다 (모든 제품의 총 매출이 아닙니다.)
SELECT product_id, p.name, (sum(s.units) * p.price) AS sales
    FROM products p LEFT JOIN sales s USING (product_id)
    GROUP BY product_id, p.name, p.price; 
이 예제에서는 product_id 열, p.name 열, p.price 열은 반드시 GROUP BY 절에 지정해야 합니다. 왜냐하면 이들은 문의 선택 목록에서 사용되고 있기 때문입니다.  (products 테이블을 어떻게 설정 하느냐에 따라 이름과 가격을 전부 product ID에 종속시킬 수 있으므로 이론적으로 이들을 그룹화 할 필요를 없앨 수 있습니다. 그러나, 이것은 구현 되지 않았습니다.) s.units 열은 GROUP BY로 지정할 필요가 없습니다. 이것은 각 제품의 매출 계산 집약 식 ( sum(...) ) 안에서만 사용되기 때문입니다. 이 질문은 각 제품에 대해  제품의 전체 판매에 관한 전체 행을 반환합니다.
제한된 SQL에서 GROUP BY는 원본 테이블의 열에 의해서만 그룹화할 수 있지만, PostgreSQL에서는 선택 목록의 열 그룹화도 할 수 있게 확장되어 있습니다. 단훈한 열 이름 대신 평가 식에서 그룹화 할 수 있습니다.
GROUP BY를 사용하여 그룹화된 테이블에서 특정 그룹만 필요한 경우, 결과에서 불필요한 그룹을 제거하기 위하여, WHERE 절과 같이 HAVING 절을 사용할 수 있습니다. 구문은 다음과 같습니다.
 SELECT select_list FROM ... [WHERE ...] GROUP BY ... HAVING boolean_expression 
HAVING 절의 식은 그룹화된 식과 그룹화되지 않은 식 (이 경우에는 집계 함수가 필요합니다)을 모두 볼 수 있습니다.
예 입니다.
=> SELECT x, sum(y) FROM test1 GROUP BY x HAVING sum(y) > 3;
 x | sum
---+-----
 a |   4
 b |   5
(2 rows)

=> SELECT x, sum(y) FROM test1 GROUP BY x HAVING x < 'c';
 x | sum
---+-----
 a |   4
 b |   5
(2 rows) 

이제 더 현실적인 예입니다.
SELECT product_id, p.name, (sum(s.units) * (p.price - p.cost)) AS profit
    FROM products p LEFT JOIN sales s USING (product_id)
    WHERE s.date > CURRENT_DATE - INTERVAL '4 weeks'
    GROUP BY product_id, p.name, p.price, p.cost
    HAVING sum(p.price * s.units) > 5000;
위의 예에서, WHERE 절은 그룹화되지 않은 열을 기준으로 행을 선택하고 있는 (이 식은 최근 4 주간의 매출만이 참입니다) 반면, HAVING 은 출력을 매출이 5000 초과의 그룹으로 제한하고 있습니다. 집계식이 문의에서 항상 같을 필요가 없다는 것에주의하십시오.
몇몇 질문이 집계 함수를 포함하고 있으면 GROUP BY 절이 없어도, 그룹화는 여전히 발생합니다. 결과는 단일 그룹 행 (또는 HAVING에서 단일 행이 삭제되면 행이 아마 완전히 없어지는)입니다. HAVING 절을 포함하는 경우, 어떤 집계 함수 호출 또는 GROUP BY 절이 존재하지 않더라도 마찬가지입니다.

출처 카빙's 세상살이 | 카빙
원문 http://kngt13.blog.me/80129263749
 

댓글 없음:

댓글 쓰기