1. Pengenalan Analisis Agregat
Operasi agregasi merupakan konsep yang sangat penting dalam kueri basis data. Biasanya digunakan untuk analisis statistik seperti penjumlahan, penghitungan, rata-rata, nilai maksimum, dan minimum. Operasi-operasi ini membantu pengguna mengekstrak informasi yang bermakna dari sejumlah besar data, memberikan dukungan untuk analisis data dan pengambilan keputusan. Fungsi-fungsi yang diimplementasikan dalam basis data untuk agregasi biasanya disebut sebagai fungsi agregat.
2. Operasi Agregat Dasar
2.1 Konsep Fungsi Agregat
Fungsi agregat adalah fungsi yang digunakan dalam bahasa kueri basis data untuk melakukan serangkaian perhitungan dan mengembalikan satu nilai. Dalam SQL dan bahasa kueri serupa, fungsi agregat dapat beroperasi pada kolom data dan mengembalikan satu nilai, seperti penjumlahan (SUM), rata-rata (AVG), penghitungan (COUNT), maksimum (MAX), dan minimum (MIN). Ketika kita perlu melakukan analisis statistik data, fungsi agregat adalah alat penting untuk memproses himpunan data dan mengekstrak data statistik.
2.2 Agregasi Single-Field
Dalam aplikasi praktis, analisis agregasi single-field adalah kebutuhan yang sangat umum, sering digunakan untuk mendapatkan hasil statistik seperti jumlah, rata-rata, nilai maksimum, dan minimum dari suatu kolom tertentu. Misalkan kita memiliki tabel informasi pembayaran, dan ingin menghitung total jumlah yang dibayarkan oleh pengguna. Dengan menggunakan framework ent
, kita dapat membuat kueri dari entitas dan menerapkan fungsi agregat sebagai berikut:
func Do(ctx context.Context, client *ent.Client) {
// Menghitung jumlah dari kolom Amount untuk entitas Pembayaran
sum, err := client.Payment.Query().
Aggregate(
ent.Sum(payment.Amount),
).
Int(ctx)
if err != nil {
log.Fatalf("Gagal mendapatkan hasil jumlah: %v", err)
}
log.Printf("Total jumlah pembayaran: %d", sum)
}
Pada potongan kode di atas, kita memulai sebuah kueri untuk entitas pembayaran menggunakan client.Payment.Query()
, kemudian menggunakan metode Aggregate()
untuk memanggil fungsi ent.Sum
dengan payment.Amount
sebagai parameter untuk menghitung total jumlah pembayaran. Kita menggunakan .Int(ctx)
untuk mengonversi hasil agregat menjadi bilangan bulat dan mencatatnya.
2.3 Agregasi Multi-Field
Dalam banyak kasus, kita perlu melakukan operasi agregasi pada beberapa kolom daripada hanya satu. Pada bagian ini, kita akan mendemonstrasikan bagaimana mencapai agregasi multi-field melalui sebuah contoh.
Pada contoh ini, kita akan menjumlahkan, mencari nilai minimum, mencari nilai maksimum, dan menghitung kolom Umur
dalam tabel hewan peliharaan.
func Do(ctx context.Context, client *ent.Client) {
var v []struct {
Jumlah, Minimal, Maksimal, JumlahData int
}
err := client.Pet.Query().
Aggregate(
ent.Sum(pet.FieldAge), // Jumlah Umur
ent.Min(pet.FieldAge), // Umur Minimal
ent.Max(pet.FieldAge), // Umur Maksimal
ent.Count(), // Menghitung
).
Scan(ctx, &v)
if err != nil {
log.Fatalf("Pencarian gagal: %v", err)
}
// Output semua hasil agregat
for _, agg := range v {
fmt.Printf("Jumlah: %d Minimal: %d Maksimal: %d Jumlah: %d\n", agg.Jumlah, agg.Minimal, agg.Maksimal, agg.JumlahData)
}
}
Pada potongan kode di atas, kita menggunakan fungsi Aggregate
untuk melakukan agregasi multi-field, dan menggunakan fungsi Scan
untuk menyimpan hasil agregasi dalam slice v
. Kemudian, kita melakukan iterasi melalui v
untuk menampilkan semua hasil agregat.
3. Penerapan Agregasi Group By
3.1. Menggunakan Group By untuk Mengelompokkan Kolom
Dalam operasi basis data, Group By
adalah metode umum untuk mengelompokkan data. Pada bagian ini, kita akan belajar bagaimana menggunakan Group By
untuk mengelompokkan data dalam basis data.
Contoh tutorial, bagaimana mengelompokkan satu atau lebih kolom menggunakan Group By.
Misalkan kita memiliki tabel pengguna dan perlu mengelompokkan kolom nama
pengguna serta menghitung jumlah pengguna dalam setiap kelompok. Berikut adalah contoh kode bagaimana mencapai kebutuhan ini:
func Do(ctx context.Context, client *ent.Client) {
nama, err := client.User.
Query().
GroupBy(user.FieldName).
Strings(ctx)
if err != nil {
log.Fatalf("Gagal menjalankan kueri yang dikelompokkan: %v", err)
}
// Output nama dari setiap kelompok
for _, nam := range nama {
fmt.Println("Nama kelompok:", nam)
}
}
Pada kode di atas, kita menggunakan metode GroupBy
dari pembangun kueri untuk menentukan kolom mana yang ingin kita kelompokkan.
3.2. Pengelompokan dan Penyatuan Beberapa Bidang
Terkadang, kita ingin mengelompokkan data berdasarkan beberapa bidang dan melakukan fungsi agregat pada setiap kelompok. Berikut adalah contoh bagaimana mencapai kebutuhan ini:
Berikut adalah contoh bagaimana mencapai kebutuhan ini:
Kode berikut menunjukkan bagaimana mengelompokkan data dalam tabel pengguna berdasarkan bidang name
dan age
, dan menghitung total usia dan jumlah pengguna di setiap kelompok.
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("Gagal menjalankan query pengelompokan dan agregasi beberapa bidang: %v", err)
}
// Output informasi detail untuk setiap kelompok
for _, group := range v {
fmt.Printf("Nama: %s Usia: %d Total: %d Jumlah: %d\n", group.Name, group.Age, group.Sum, group.Count)
}
}
Pada contoh ini, kita tidak hanya mengelompokkan data berdasarkan bidang name
dan age
dalam tabel pengguna, tetapi juga menggunakan fungsi agregat Count
dan Sum
untuk menghitung total jumlah catatan dan total usia di setiap kelompok.
4. Menggabungkan Having dengan Group By
Klausa Having
menyaring hasil agregat yang diperoleh setelah operasi Group By
. Contoh berikut menunjukkan bagaimana memilih hanya pengguna dengan usia maksimum di setiap peran:
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("Gagal menjalankan query Having yang digabungkan dengan Group By: %v", err)
}
// Output informasi pengguna yang memenuhi kondisi Having
for _, user := range users {
fmt.Printf("ID: %d Usia: %d Peran: %s\n", user.Id, user.Age, user.Role)
}
}
Kode di atas akan menghasilkan query SQL setara untuk memilih pengguna dengan usia maksimum di setiap peran.