1. 집계 분석 소개
집계 연산은 데이터베이스 쿼리에서 매우 중요한 개념입니다. 일반적으로 합계, 계수, 평균, 최댓값 및 최솟값과 같은 통계 분석에 사용됩니다. 이러한 연산들은 사용자가 대량의 데이터에서 의미 있는 정보를 추출하고 데이터 분석 및 의사 결정을 지원하는 데 도움을 줍니다. 데이터베이스에서 구현된 함수는 일반적으로 집계 함수라고 합니다.
2. 기본 집계 작업
2.1 집계 함수의 개념
집계 함수는 데이터베이스 쿼리 언어에서 사용되는 함수로, 일련의 계산을 수행하고 단일 값을 반환합니다. SQL 및 유사한 쿼리 언어에서 집계 함수는 데이터 열에 작용하여 합계 (SUM), 평균 (AVG), 계수 (COUNT), 최댓값 (MAX) 및 최솟값 (MIN)과 같은 단일 값을 반환할 수 있습니다. 데이터 통계 분석을 수행해야 할 때, 집계 함수는 데이터 집합을 처리하고 통계 데이터를 추출하는 중요한 도구입니다.
2.2 단일 필드 집계
실제 응용 프로그램에서는 특정 열의 합, 평균, 최댓값 및 최솟값과 같은 통계 결과를 얻기 위한 단일 필드 집계 분석이 매우 일반적으로 사용됩니다. 사용자 지불 정보 테이블이 있다고 가정하고 사용자가 낸 총 금액을 계산하려면, ent
프레임워크를 사용하여 다음과 같이 엔터티에서 쿼리를 생성하고 집계 함수를 적용할 수 있습니다:
func Do(ctx context.Context, client *ent.Client) {
// 지불 엔터티의 Amount 필드 합계 계산
sum, err := client.Payment.Query().
Aggregate(
ent.Sum(payment.Amount),
).
Int(ctx)
if err != nil {
log.Fatalf("총합을 가져오지 못했습니다: %v", err)
}
log.Printf("총 지불액: %d", sum)
}
위의 코드 스니펫에서 client.Payment.Query()
를 사용하여 지불 엔터티에 대한 쿼리를 시작하고, Aggregate()
메서드를 사용하여 payment.Amount
를 매개변수로 사용하여 총 지불액을 계산합니다. .Int(ctx)
를 사용하여 집계 결과를 정수로 변환하고 기록합니다.
2.3 다중 필드 집계
많은 경우 하나 이상의 필드에 대해 단순히 하나가 아니라 여러 필드에 대해 집계 작업을 수행해야 합니다. 이 섹션에서는 다중 필드 집계를 예를 통해 어떻게 달성하는지를 보여줍니다.
이 예에서는 pet 테이블의 Age
필드에 대해 합계를 구하고 최솟값, 최댓값, 및 계수하는 방법을 보여줍니다.
func Do(ctx context.Context, client *ent.Client) {
var v []struct {
Sum, Min, Max, Count int
}
err := client.Pet.Query().
Aggregate(
ent.Sum(pet.FieldAge), // 나이의 합계
ent.Min(pet.FieldAge), // 최소 연령
ent.Max(pet.FieldAge), // 최대 연령
ent.Count(), // 계수
).
Scan(ctx, &v)
if err != nil {
log.Fatalf("쿼리 실패: %v", err)
}
// 모든 집계 결과 출력
for _, agg := range v {
fmt.Printf("합계: %d 최소: %d 최대: %d 계수: %d\n", agg.Sum, agg.Min, agg.Max, agg.Count)
}
}
위의 코드에서 Aggregate
함수를 사용하여 다중 필드 집계를 수행하고, Scan
함수를 사용하여 집계 결과를 슬라이스 v
에 저장합니다. 그런 다음 v
를 반복하여 모든 집계 결과를 출력합니다.
3. Group By 집계의 응용
3.1. Group By를 사용한 필드 그룹화
데이터베이스 작업에서 Group By
는 데이터를 그룹화하는 일반적인 방법입니다. 이 섹션에서는 데이터베이스에서 Group By
를 사용하여 데이터를 그룹화하는 방법을 배우게 됩니다.
튜토리얼 예제, Group By를 사용하여 하나 이상의 필드를 그룹화하는 방법입니다.
가정해보면 사용자 테이블이 있고 사용자의 name
필드를 그룹화하고 각 그룹의 사용자 수를 계산해야 한다고 가정해봅시다. 이 요구 사항을 충족하는 코드 예제는 다음과 같습니다:
func Do(ctx context.Context, client *ent.Client) {
names, err := client.User.
Query().
GroupBy(user.FieldName).
Strings(ctx)
if err != nil {
log.Fatalf("그룹화된 쿼리 실행 실패: %v", err)
}
// 각 그룹의 이름 출력
for _, name := range names {
fmt.Println("그룹 이름:", name)
}
}
위의 코드에서 쿼리 빌더의 GroupBy
메서드를 사용하여 그룹화할 필드를 지정합니다.
3.2. 여러 필드를 기준으로 그룹화 및 집계
가끔은 데이터를 여러 필드를 기준으로 그룹화하고 각 그룹에 대해 집계 함수를 수행하길 원할 때가 있습니다. 아래는 이 요구 사항을 어떻게 달성하는지에 대한 예시입니다:
다음 코드는 name
및 age
필드를 기준으로 사용자 테이블의 데이터를 그룹화하고 각 그룹의 총 연령과 사용자 수를 계산하는 방법을 보여줍니다.
func Do(ctx context.Context, client *ent.Client) {
var v []struct {
Name string `json:"name"`
Age int `json:"age"`
Sum int `json:"sum"`
Count int `json:"count"`
}
err := client.User.Query().
GroupBy(user.FieldName, user.FieldAge).
Aggregate(ent.Count(), ent.Sum(user.FieldAge)).
Scan(ctx, &v)
if err != nil {
log.Fatalf("여러 필드를 기준으로 그룹화 및 집계하는 쿼리 실행에 실패했습니다: %v", err)
}
// 각 그룹에 대한 상세 정보 출력
for _, group := range v {
fmt.Printf("이름: %s 나이: %d 합: %d 개수: %d\n", group.Name, group.Age, group.Sum, group.Count)
}
}
이 예시에서는 사용자 테이블의 데이터를 name
및 age
필드를 기준으로 그룹화할 뿐만 아니라, 각 그룹의 레코드 수와 총 연령을 계산하기 위해 Count
및 Sum
집계 함수를 사용합니다.
4. Group By와 Having의 결합
Having
절은 Group By
작업 이후에 얻은 집계 결과를 필터링합니다. 다음 예시는 각 역할에서 최대 연령을 갖는 사용자만을 선택하는 방법을 보여줍니다:
func Do(ctx context.Context, client *ent.Client) {
var users []struct {
Id Int
Age Int
Role string
}
err := client.User.Query().
Modify(func(s *sql.Selector) {
s.GroupBy(user.FieldRole)
s.Having(
sql.EQ(
user.FieldAge,
sql.Raw(sql.Max(user.FieldAge)),
),
)
}).
ScanX(ctx, &users)
if err != nil {
log.Fatalf("Having과 Group By를 병합한 쿼리 실행에 실패했습니다: %v", err)
}
// Having 조건을 만족하는 사용자 정보 출력
for _, user := range users {
fmt.Printf("ID: %d 나이: %d 역할: %s\n", user.Id, user.Age, user.Role)
}
}
위 코드는 각 역할에서 최대 연령을 갖는 사용자를 선택하기 위한 동등한 SQL 쿼리를 생성합니다.