GROUP BY를 통해 데이터 요약

완료됨

집계 함수는 분석에 유용하지만 데이터를 요약하기 전에 하위 집합으로 정렬하고자 하는 경우도 있습니다. 이 섹션에서는 GROUP BY 절을 사용하여 이 작업을 수행하는 방법을 알아봅니다.

GROUP BY 절 사용

앞에서 배웠듯이 SELECT 문이 처리되면 FROM 절과 WHERE 절이 계산된 후 가상 테이블이 만들어집니다. 이제 가상 테이블의 내용을 추가적인 처리에 사용할 수 있습니다. GROUP BY 절을 사용하여 이 가상 테이블의 내용을 행 그룹으로 세분화할 수 있습니다.

행을 그룹화하려면 GROUP BY 절에 하나 이상의 요소를 지정합니다.

GROUP BY <value1> [, <value2>, …]

GROUP BY는 그룹을 만들고 절에 지정된 요소에 의해 결정된 대로 각 그룹에 행을 배치합니다.

예를 들어 다음 쿼리는 Sales.SalesOrderHeader 테이블에서 CustomerID당 한 행씩 그룹화된 행 집합을 생성합니다. GROUP BY 프로세스를 확인하는 또 다른 방법은 동일한 CustomerID 값을 갖는 모든 행을 그룹화하여 단일 결과 행에 반환하는 것입니다.

SELECT CustomerID
FROM Sales.SalesOrderHeader
GROUP BY CustomerID;

위의 쿼리는 다음 쿼리와 같습니다.

SELECT DISTINCT CustomerID
FROM Sales.SalesOrderHeader

GROUP BY 절이 처리되고 각 행이 그룹에 연결된 다음 쿼리의 이후 단계에서는 SELECT 목록에 있지만 GROUP BY 목록에 표시되지 않는 원본 행의 모든 요소를 집계해야 합니다. 이 요구 사항은 SELECT 절과 HAVING 절을 작성하는 방법에 영향을 미칩니다.

그렇다면 GROUP BY나 DISTINCT로 쿼리를 작성할 때의 차이점은 무엇입니까? CustomerID에 대한 고유 값만 알고 싶은 경우 차이가 없습니다. 하지만 GROUP BY를 사용하면 이후에 각 그룹에 집계될 다른 요소를 SELECT 목록에 추가할 수 있습니다.

가장 간단한 집계 함수는 COUNT(*)입니다. 다음 쿼리는 CustomerID 에서 원래 830개의 원본 행을 가져와 CustomerID 값을 기준으로 89개의 그룹으로 그룹화합니다. 각 고유 CustomerID 값은 GROUP BY 쿼리에서 하나의 출력 행을 생성합니다.

SELECT CustomerID, COUNT(*) AS OrderCount
FROM Sales.SalesOrderHeader
GROUP BY CustomerID;

CustomerID 값에 대해 쿼리는 행을 집계하고 수를 계산하므로 SalesOrderHeader 테이블에서 각 고객에게 속하는 행의 수를 보여 줍니다.

CustomerID

OrderCount

1234

3

1005

1

GROUP BY는 결과의 순서를 보장하지 않는다는 점에 유의합니다. 쿼리 프로세서에서 그룹화 작업을 수행하는 방법의 결과로 결과가 그룹 값의 순서대로 반환되는 경우가 많습니다. 그러나 이 동작에만 의존하면 안 됩니다. 결과를 정렬해야 하는 경우에는 ORDER 절을 명시적으로 포함해야 합니다.

SELECT CustomerID, COUNT(*) AS OrderCount
FROM Sales.SalesOrderHeader
GROUP BY CustomerID
ORDER BY CustomerID;

이번에는 결과가 지정된 순서대로 반환됩니다.

CustomerID

OrderCount

1005

1

1234

3

SELECT 문에 있는 절은 다음 순서로 적용됩니다.

  1. FROM
  2. WHERE
  3. GROUP BY
  4. HAVING
  5. SELECT
  6. ORDER BY

열 별칭은 GROUP BY 절 ‘뒤’와 ORDER BY 절 ‘앞’에 발생하는 SELECT 절에 할당됩니다. ORDER BY 절에서는 열 별칭을 참조할 수 있지만 GROUP BY 절에서는 참조할 수 없습니다. 다음 쿼리로 인해 ‘잘못된 열 이름’ 오류가 발생합니다.

SELECT CustomerID AS Customer,
       COUNT(*) AS OrderCount
FROM Sales.SalesOrderHeader
GROUP BY Customer
ORDER BY Customer;

그러나 다음 쿼리는 성공적으로 결과를 고객 ID별로 그룹화하고 정렬합니다.

SELECT CustomerID AS Customer,
       COUNT(*) AS OrderCount
FROM Sales.SalesOrderHeader
GROUP BY CustomerID
ORDER BY Customer;

GROUP BY 오류 문제 해결

SELECT 문에서 GROUP BY의 사용에 익숙해지는 것을 방해하는 일반적인 요인은 다음과 같은 유형의 오류 메시지가 발생하는 이유를 이해하는 것입니다.

메시지 8120, 수준 16, 상태 1, 줄 2 <column_name> 열이 집계 함수 또는 GROUP BY 절에 포함되어 있지 않아 선택 목록에서 잘못되었습니다.

예를 들어 SELECT 목록의 각 열이 GROUP BY 절의 열이거나 각 그룹에서 작동하는 집계 함수이므로 다음 쿼리가 허용됩니다.

SELECT CustomerID, COUNT(*) AS OrderCount
FROM Sales.SalesOrderHeader
GROUP BY CustomerID;

PurchaseOrderNumber는 GROUP BY의 일부가 아니고 집계 함수와 함께 사용되지 않으므로 다음 쿼리는 오류를 반환합니다.

SELECT CustomerID, PurchaseOrderNumber, COUNT(*) AS OrderCount
FROM Sales.SalesOrderHeader
GROUP BY CustomerID;

이 쿼리는 다음과 같은 오류를 반환합니다.

Msg 8120, Level 16, State 1, Line 1
Column 'Sales.SalesOrderHeader.PurchaseOrderNumber' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.

다음과 같은 방법으로도 생각해 볼 수 있습니다. 이 쿼리는 각 CustomerID 값에 대해 하나의 행을 반환합니다. 그러나 동일한 CustomerID 행에 다른 PurchaseOrderNumber 값이 있을 수 있습니다. 이런 경우 어떤 값을 반환해야 합니까?

고객 ID 및 구매 주문별로 주문을 보려면 다음과 같이 PurchaseOrderNumber 열을 GROUP BY 절에 추가할 수 있습니다.

SELECT CustomerID, PurchaseOrderNumber, COUNT(*) AS OrderCount
FROM Sales.SalesOrderHeader
GROUP BY CustomerID, PurchaseOrderNumber;

이 쿼리는 해당 조합에 대한 주문 수와 함께 각 고객 및 각 구매 주문 조합에 대한 하나의 행을 반환합니다.