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() เพื่อเรียกใช้ฟังก์ชัน ent.Sum ด้วยพารามิเตอร์เป็น payment.Amount เพื่อคำนวณยอดเงินรวม เราใช้ .Int(ctx) เพื่อแปลงผลรวมรวมเป็นจำนวนเต็ม และบันทึกไว้

2.3 การรวมด้วยฟิลด์มากกว่าหนึ่ง

ในกรณีมากมาย เราต้องการดำเนินการรวมบนฟิลด์มากกว่าหนึ่ง ไม่ใช่แค่หนึ่งเท่านั้น ในส่วนนี้ เราจะสาธิตวิธีในการทำค่ารวมของฟิลด์มากกว่าหนึ่งผ่านตัวอย่าง

ในตัวอย่างนี้ เราจะทำการรวมผลรวม หาค่าต่ำสุด หาค่าสูงสุด และนับฟิลด์ 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("Failed to execute multiple fields grouping and aggregation query: %v", err)
    }
    // แสดงข้อมูลโดยละเอียดสำหรับแต่ละกลุ่ม
    for _, group := range v {
        fmt.Printf("Name: %s Age: %d Sum: %d Count: %d\n", group.Name, group.Age, group.Sum, group.Count)
    }
}

ในตัวอย่างนี้ เราไม่เพียงแค่จัดกลุ่มข้อมูลตามฟิลด์ name และ age ในตารางผู้ใช้ แต่ยังใช้ฟังก์ชันการรวม Count และ Sum เพื่อคำนวณจำนวนรวมและอายุรวมในแต่ละกลุ่ม

4. การใช้ Having ร่วมกับ Group By

คลอส 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("Failed to execute Having combined with Group By query: %v", err)
    }
    // แสดงข้อมูลผู้ใช้ที่ทำให้เงื่อนไข Having เป็นจริง
    for _, user := range users {
        fmt.Printf("ID: %d Age: %d Role: %s\n", user.Id, user.Age, user.Role)
    }
}

โค้ดข้างต้นจะสร้างคิวรี่ SQL เทียบเท่าเพื่อเลือกผู้ใช้ที่มีอายุสูงสุดในแต่ละบทบาท