● 관심 그룹(Focus group)
그룹 안에서 다시 특정 조건을 만족하는 세부 그룹이다. 세부 그룹을 구성하기 위한 조건을 HAVING 절을 사용하여 지정해 줄 수 있다.
문법: SELECT <컬럼, 표현식> FROM <테이블 이름> [WHERE <검색 조건>] [GROUP BY <컬럼 이름>, ] [HAVING <세부 그룹 구성 조건>]
예를 통해 HAVING 절이 어떻게 사용되는지 살펴보자.
예) 연주 그룹 중 재즈Jazz 스타일 연주를 하는 3명 이상으로 구성된 그룹을 알고 싶다.
연주 그룹 데이터는 entertainers 테이블에, 음악 스타일 데이터는 musical_styles 테이블에 각각 저장되어 있다. 그리고 연주 그룹과 연주하는 음악 스타일 사이의 관계가 '연주 그룹 - 음악 스타일' 테이블인 entertainer_styles 테이블에 저장되어 있다. 따라서 연주 그룹 정보와 연주 스타일 정보를 알기 위해서는 entertainers, musical_styles, 그리고 entertainer_styles 테이블을 연결해서 살펴보아야 한다.
① 연주 그룹 중 재즈 스타일 연주를 하는 그룹
SELECT entertainers.EntertainerID, EntStageName, StyleName
FROM (entertainers LEFT OUTER JOIN entertainer_styles ON entertainers.EntertainerID=entertainer_styles.EntertainerID)
LEFT OUTER JOIN musical_styles ON entertainer_styles.StyleID=musical_styles.StyleID
WHERE StyleName='Jazz'
② 그룹 중 구성원이 3명 이상인 그룹
②-ⓐ: 그룹 및 구성원 수를 출력한다.
SELECT entertainer_members.EntertainerID, COUNT(entertainer_members.MemberID)
FROM entertainer_members LEFT OUTER JOIN members ON entertainer_members.MemberID=members.MemberID
GROUP BY entertainer_members.EntertainerID;
②-ⓑ: ②-ⓐ 결과를 가상 테이블로 하여 구성원 수가 3보다 크거나 같은 그룹 출력한다.
SELECT EntertainerID
FROM (SELECT entertainer_members.EntertainerID, COUNT(entertainer_members.MemberID) AS numOfMembers FROM entertainer_members LEFT OUTER JOIN members ON entertainer_members.MemberID=members.MemberID GROUP BY entertainer_members.EntertainerID) AS entertainer_numofmembers
WHERE entertainer_numofmembers.numOfMembers >= 3;
③ ①의 연주 그룹 중 ②의 그룹에 속하는 연주 그룹을 구하면 된다.
SELECT entertainers.EntertainerID, EntStageName, StyleName
FROM (entertainers LEFT OUTER JOIN entertainer_styles ON entertainers.EntertainerID=entertainer_styles.EntertainerID)
LEFT OUTER JOIN musical_styles ON entertainer_styles.StyleID=musical_styles.StyleID
WHERE StyleName='Jazz'
AND entertainers.EntertainerID
IN (SELECT EntertainerID FROM (SELECT entertainer_members.EntertainerID, COUNT(entertainer_members.MemberID) AS numOfMembers FROM entertainer_members LEFT OUTER JOIN members ON entertainer_members.MemberID=members.MemberID GROUP BY entertainer_members.EntertainerID) AS entertainer_numofmembers
WHERE entertainer_numofmembers.numOfMembers >= 3);
위 예를 HAVING 구문을 사용한 검색식으로 다시 구성하면 아래와 같다.
① 재즈를 연주하는 연주 그룹을 검색한다.
연주 그룹의 멤버 정보를 함께 살펴보기 위해 연주 그룹 멤버 정보가 포함되어 있는 entertainer_members 테이블을 함께 살펴보았다.
SELECT entertainers.EntertainerID, entertainers.EntStageName
FROM ((entertainers LEFT OUTER JOIN entertainer_styles ON entertainers.EntertainerID=entertainer_styles.EntertainerID)
LEFT OUTER JOIN musical_styles ON entertainer_styles.StyleID=musical_styles.StyleID)
LEFT OUTER JOIN entertainer_members ON entertainers.EntertainerID=entertainer_members.EntertainerID
WHERE musical_styles.StyleName='JAZZ'
② ① 결과를 연주 그룹을 기준으로 그룹핑하고 그룹 중 멤버(entertainer_members.MemberID) 수가 3명 이상(>=)인 그룹의 ID와 예명(EntStageName)을 출력한다.
SELECT entertainers.EntertainerID, entertainers.EntStageName
FROM ((entertainers LEFT OUTER JOIN entertainer_styles ON entertainers.EntertainerID=entertainer_styles.EntertainerID)
LEFT OUTER JOIN musical_styles ON entertainer_styles.StyleID=musical_styles.StyleID)
LEFT OUTER JOIN entertainer_members ON entertainers.EntertainerID=entertainer_members.EntertainerID
WHERE musical_styles.StyleName='JAZZ'
GROUP BY entertainers.EntertainerID
HAVING COUNT(entertainer_members.MemberID) >= 3;
서브쿼리를 이용한 검색식이나 HAVING 구문을 이용한 검색식의 결과는 같기 때문에 구성이 편한 검색식을 이용해서 결과를 얻으면 된다. 하지만 HAVING 구문을 이용한 검색식이 좀 더 직관적이고 간단함을 알 수 있다.
새로운 검색식을 살펴보면 GROUP BY 구문과 HAVING 구문을 통해 3명 이상의 멤버를 가진 관심 그룹을 구성하도록 하고 있다(GROUP BY entertainer_members.EntertainerID HAVING COUNT(entertainer_members.MemberID) >= 3). GROUP BY 구문에 의해 구분된 행들에 포함된 컬럼, 그리고 이들을 근거로 한 계산 값이라면 HAVING 구문의 구성 조건들로 사용될 수 있다.
● WHERE 구문과 HAVING 구문
WHERE 구문은 FROM 구문에 지정된 테이블들로부터 데이터를 추출한다. 그리고 이렇게 추출된 데이터들에서 GROUP BY 구문과 HAVING 구문에 지정된 조건들을 통해 결과 셋이 구성된다.
데이터를 얻기 위한 검색식의 처리 순서를 'FROM 구문 → WHERE 구문 → GROUP BY 구문 → HAVING 구문 → SELECT 구문'으로 볼 수 있다. 따라서 HAVING 구문을 WHERE 구문에 의해 추출된 데이터들로부터 다시 데이터를 추출하는 후속 과정이라고 볼 수 있다. WHERE 구문만으로 원하는 데이터를 얻을 수 없다면 HAVING 구문을 사용하게 된다.
예) 주문 금액의 총액이 백만달러($1 million) 이상인 지역 중 미국 서부 해안에 있는 주들(WA, OR, CA)을 알고 싶다.
① WA, OR, CA에서 들어온 주문을 구한다.
SELECT order_details.OrderNumber
FROM (order_details LEFT OUTER JOIN orders ON order_details.OrderNumber=orders.OrderNumber)
LEFT OUTER JOIN customers ON orders.CustomerID=customers.CustomerID
WHERE CustState='WA' OR CustState='OR' OR CustState='CA'
② ①을 주(CustState)를 기준으로 그룹핑하고 주문 금액의 합이 100만 달러 이상인 주를 찾는다.
SELECT customers.CustState, SUM(QuotedPrice*QuantityOrdered)
FROM (order_details LEFT OUTER JOIN orders ON order_details.OrderNumber=orders.OrderNumber)
LEFT OUTER JOIN customers ON orders.CustomerID=customers.CustomerID
WHERE CustState='WA' OR CustState='OR' OR CustState='CA'
GROUP BY customers.CustState
HAVING SUM(QuotedPrice*QuantityOrdered) > 1000000;
만약 WHERE 구문으로 추출된 데이터 안에 관심 그룹이 없다면 HAVING 구문을 사용해도 원하는 관심 그룹을 찾을 수 없다는 말도 된다.
■
'데이터 모델과 SQL' 카테고리의 다른 글
[데이터 모델과 SQL] 15. 저장된 정보 수정 - UPDATE (0) | 2023.02.03 |
---|---|
[데이터 모델과 SQL] 14. 관심 그룹(HAVING) - 2/2 (0) | 2023.02.02 |
[데이터 모델과 SQL] 13. 합(total) 연산들 (0) | 2023.01.16 |
[데이터 모델과 SQL] 12. Grouping data (0) | 2023.01.16 |
[데이터 모델과 SQL] 11. 서브쿼리Subquery - 2/2 (0) | 2023.01.16 |
댓글