So sánh mệnh đề where và mệnh đề having năm 2024

Mệnh đề HAVING trong SQL có thể được xem là một sự thay thế cho WHERE. Nguyên nhân vì sao? Ý nghĩa và cú pháp sử dụng của HAVING như thế nào? Hãy xem tiếp ngay dưới đây.

1. Ý nghĩa của GROUP BY

Mệnh đề HAVING được thêm vào SQL bởi vì từ khóa WHERE không thể được sử dụng với các hàm tổng hợp.

  • Cú pháp:

SELECT tên cột

FROM tên bảng

WHERE điều kiện

GROUP BY tên cột

HAVING điều kiện

ORDER BY tên cột;

2. Ví dụ HAVING

Để thực hiện ví dụ này, bạn cần nhập cơ sở dữ liệu mẫu Northwind vào SQL Server Management Studio. Hãy xem bài viết hướng dẫn ngay dưới đây:

Tham khảo: Hướng dẫn tải và cài đặt dữ liệu mẫu Northwind trong SQL Server Management Studio

Câu lệnh SQL dưới đây sẽ liệt kê nếu nhân viên có tên “Davolio” hoặc “Fuller” có nhiều hơn 25 đơn đặt hàng:

Câu hỏi

Câu trả lời

Cả hai đều chỉ định điều kiện tìm kiếm nhưng ...

Bạn cần đăng nhập để xem

Gợi ý câu hỏi

Tìm các giá trị trùng lặp trong bảng SQL?

Normalization là gì?

Sự khác biệt giữa một Local temp table và một Global temp table?

Row constructors là gì?

CHECK Constraint - Ràng buộc CHECK là gì?

WHERE là điều kiện lọc sơ bộ ban đầu. Các Column trong WHERE phải có trong bảng TblA, không thể WHERE Tan_Xuat > 1

HAVING là điều kiện lọc trên bảng ảo sau khi nhóm lệnh SELECT Stt ...GROUP BY Stt được thực hiện. Sau khi GROUP BY thì mới có cột Tan_Xuat, lúc đó muốn lọc tiếp với điều kiện Stt xuất hiện trên 1 lần thì HAVING Tan_Xuat > 1

GROUP BY thì gộp các dòng có chung một giá trị nào đó (VD: Stt) lại thành 1 dòng. Với các cột không có trong GROUP BY thì phải dùng SUM, AVG, MIN, MAX để xử lý. Khi group lại thì cột Dien_Giai ko phải kiểu số nên không thể dùng SUM vì cộng lại thì chả có ý nghĩa gì nên có thể dùng MIX, MIN để chọn một giá trị đứng đầu or cuối theo sắp xếp

GROUP BY luôn đứng sau WHERE (nếu có), còn HAVING luôn đứng sau GROUP BY

(Theo kinh nghiệm của tôi thì thế thôi, chưa đọc qua giáo trình nào nên cũng không rõ có gì hiểu sai hay thiếu ko)

Mệnh đề HAVING trong SQL được sử dụng để lọc các bản ghi và chỉ lấy những bản ghi phù hợp với yêu cầu hoặc thực sự cần thiết tương tự như mệnh đề WHERE. Tuy nhiên:

  • WHERE là câu lệnh điều kiện trả kết quả đối chiếu với từng dòng.
  • HAVING là câu lệnh điều kiện trả kết quả đối chiếu cho nhóm được tạo bởi mệnh đề GROUP BY.

Vì vậy mà sau GROUP BY thì sẽ chỉ dùng được HAVING còn WHERE không dùng được sau GROUP BY.

Cú pháp sử dụng HAVING trong SQL

Vị trí của mệnh đề HAVING trong một truy vấn SQL như sau:

SELECT FROM WHERE GROUP BY HAVING ORDER BY

Lưu ý: Mệnh đề HAVING phải theo sau mệnh đề GROUP BY trong một truy vấn và đặt trước mệnh đề ORDER BY nếu được sử dụng.

Dưới đây là cú pháp của lệnh SELECT bao gồm mệnh đề HAVING:

SELECT cot1, cot2 FROM bang1, bang2 WHERE [ dieu_kien ] GROUP BY cot1, cot2 HAVING [ dieu_kien ] ORDER BY cot1, cot2

Ví dụ về HAVING trong SQL

Giả sử bảng NHANVIEN có các bản ghi như sau:

++--+-+---+--+

ID TEN TUOI DIACHI LUONG
+----+----------+-----+-----------+----------+
1 Thanh 32 Haiphong 2000.00
2 Loan 25 Hanoi 1500.00
3 Nga 23 Hanam 2000.00
4 Manh 25 Hue 6500.00
5 Huy 27 Hatinh 8500.00
6 Cao 22 HCM 4500.00
7 Lam 24 Hanoi 10000.00
+----+----------+-----+-----------+----------+

Để hiển thị bản ghi có độ tuổi xuất hiện lớn hơn hoặc bằng 2 lần, ta chạy lệnh như sau:

SQL > SELECT ID, TEN, TUOI, DIACHI, LUONG FROM NHANVIEN GROUP BY tuoi HAVING COUNT(tuoi) >= 2;

Kết quả trả về là:

++--+-+---+--+

ID TEN TUOI DIACHI LUONG
+----+----------+-----+-----------+----------+
2 Loan 25 Hanoi 1500.00
+----+----------+-----+-----------+----------+

Trong phần tiếp theo, chúng ta sẽ tìm hiểu về Transaction trong SQL, các bạn nhớ theo dõi nhé.

Bài trước: Khung nhìn VIEW trong SQL

Bài tiếp: TRANSACTION trong SQL

GROUP BY được sử dụng để nhóm các dòng dữ liệu dựa trên giá trị của một hoặc nhiều cột. Mục đích chính của GROUP BY là thực hiện các phép tổng hợp hoặc hàm tính toán trên các nhóm dữ liệu.

Sau đây là cách GROUP BY được thực thi trong câu lệnh.

![A diagram of a split and combine Description automatically generated](https://datapot.vn/wp-content/uploads/2023/12/a-diagram-of-a-split-and-combine-description-auto.png)

Cú pháp của GROUP BY:

  SELECT
      Col_1,
      Col_2,
      Aggregate_function(Col_3)
  FROM Table
  GROUP BY
      Col_1,
      Col_2

  • Col_1, Col_2: Cột truy vấn, cột được gộp từ mệnh đề GROUP BY.
  • Aggregate_function(Col_3): Hàm tính toán được áp dụng với Col_3.
  • Col_3: Cột được áp dụng hàm tính toán
  • Table: Bảng dữ liệu truy vấn.

Các hàm tính toán phổ biến

![A diagram of a diagram Description automatically generated](https://datapot.vn/wp-content/uploads/2023/12/a-diagram-of-a-diagram-description-automatically.png)

Ví dụ: Từ bảng Product thuộc bộ dữ liệu adventureworks, truy vấn các cột sau: ProductCategoryID, tổng giá tiền của sản phẩm, giá tiền trung bình, đếm số ProductID, số ProductID riêng biệt, giá tiền tối đa, giá tiền tối thiểu của giá tiền từng sản phẩm. Nhóm các trường có chung ProductIDCategoryID thành các nhóm riêng biệt.

![A screenshot of a computer Description automatically generated](https://datapot.vn/wp-content/uploads/2023/12/a-screenshot-of-a-computer-description-automatica-23.png)

Giải thích câu lệnh truy vấn:

  • FROM: Dữ liệu được truy vấn từ bảng SalesLT.Product.
  • GROUP BY: Nhóm các đơn hàng có chung ProductCategoryID vào với nhau.
  • SELECT: Truy vấn các cột ProductCategoryID, tổng giá tiền của sản phẩm, giá tiền trung bình, đếm số ProductID, số ProductID riêng biệt, giá tiền tối đa, giá tiền tối thiểu của từng sản phẩm.
  • Hàm SUM: Tính toán tổng giá tiền của từng nhóm sản phẩm.
  • Hàm AVG: Tính toán giá tiền trị trung bình của từng sản phẩm.
  • Hàm COUNT: Đếm số ProductID của từng nhóm sản phẩm.
  • Hàm COUNT(DISTINCT): Đếm số ProductID riêng biệt của từng nhóm sản phẩm.
  • Hàm MAX: Tính toán giá tiền lớn nhất của từng nhóm sản phẩm.
  • Hàm MIN: Tính toán giá tiền nhỏ nhất của từng nhóm sản phẩm.

Chỉ định điều kiện các nhóm bằng mệnh đề HAVING

HAVING là một điều kiện được sử dụng trong SQL sau mệnh đề GROUP BY. Nó được sử dụng để lọc các nhóm dữ liệu dựa trên hàm tính toán (aggregate function). Mục đích chính của HAVING là lọc các nhóm dữ liệu sau khi đã thực hiện tính toán.

Cú pháp của HAVING:

  SELECT
      Col_1,
      Col_2,
      Aggregate_function(Col_3)
  FROM Table
  GROUP BY
      Col_1,
      Col_2
  HAVING Aggregate_condition

  • Col_1, Col_2: Cột truy vấn, cột được gộp từ mệnh đề GROUP BY.
  • Aggregate_function(Col_3): Hàm tính toán được áp dụng với Col_3.
  • Col_3: Cột được áp dụng hàm tính toán
  • Table: Bảng dữ liệu truy vấn.
  • Aggregate_condition: Lọc nhóm dữ liệu đã được tính toán thoả mãn điều kiện đề ra.

Ví dụ: Từ bảng Product thuộc bộ dữ liệu adventureworks, truy vấn các cột sau: ProductCategoryID, cân nặng trung bình của sản phẩm được lưu dưới tên avg_weight, giá trung bình của sản phẩm được lưu dưới tên avg_list_price. Chỉ hiển thị ProductCategoryID thoả mãn cân nặng trung bình lớn hơn 1000.

So sánh mệnh đề where và mệnh đề having năm 2024

Giải thích câu lệnh truy vấn:

  • GROUP BY: Nhóm các đơn hàng có chung ProductCategoryID vào với nhau.
  • HAVING: Lọc nhóm dữ liệu đã được tính toán đã được tính toán thoả mãn điều kiện cân nặng trung bình của sản phẩm lớn hơn 1000.

WHERE và HAVING khác nhau ở đâu?

WHERE sử dụng để lọc các hàng của dữ liệu gốc trong khi HAVING sử dụng để lọc các hàng của kết quả sau GROUP BY.

Các hàm tính toán (Aggregate Functions) ví dụ: SUM, AVG, MIN, MAX, … chỉ có thể được sử dụng trong câu lệnh HAVING.

Ví dụ: Từ bảng thuộc SalesOrderDetail, truy vấn các cột sau SalesOrderID, tổng số đơn hàng, tổng doanh thu và doanh thu trung bình. Lọc điều kiện thoả mãn UnitPriceDiscount = 0 và tổng số đơn hàng lớn hơn bằng 100.

Không sử dụng được hàm tính toán (Aggregate Function) trong câu lệnh WHERE nên khi thực hiện truy vấn câu lệnh sẽ báo lỗi.

![A screenshot of a computer Description automatically generated](https://datapot.vn/wp-content/uploads/2023/12/a-screenshot-of-a-computer-description-automatica-24.png)

Vì vậy ta phải sử dụng từ khóa (Keyword) HAVING để thực hiện truy vấn.

![A screenshot of a computer Description automatically generated](https://datapot.vn/wp-content/uploads/2023/12/a-screenshot-of-a-computer-description-automatica-25.png)

Giải thích câu lệnh truy vấn:

  • WHERE: Lọc các dòng dữ liệu thoả mãn đơn vị chiết khấu bằng “0”.
  • GROUP BY: Nhóm các hàng của cột SalesOrderID có cùng giá trị trong một cột thành các nhóm riêng biệt.
  • HAVING: Lọc nhóm dữ liệu đã được tính toán thoả mãn điều kiện tổng số lượng sản phẩm lớn hơn hoặc bằng 100.
  • ORDER BY: Dữ liệu được sắp xếp theo tổng doanh thu giảm dần.

Hàm cửa sổ (Window Functions)

Hàm cửa sổ (Window Functions) trong SQL được sử dụng để thực hiện các phép tính toán các dòng có liên quan đến dòng hiện tại.

Lệnh truy vấn:

  SELECT
      Col_1,
      {Window_function}(Col_2)
  OVER([PARTITION BY Col_1] [ORDER BY COL_3])
   Table_name

  • Col_1: Tên cột đầu tiên muốn chọn.
  • Hàm cửa sổ:
    • {Window Functions}: Tên của hàm tổng hợp như SUM, AVG,…
    • Col_2: Tên của cột mà áp dụng Window Functions.
    • OVER: Xác định khung cửa sổ, bao gồm PARTITION BY(Nếu có), ORDER BY(Sắp xếp dữ liệu trong cửa sổ)
    • PARTITION BY(Nếu có): Nhóm các hàng liên quan đến nhau để thực hiện tính toán.
    • ORDER BY: Sắp xếp các hàng có trong từng cửa sổ.
    • Col_3: Cột để sắp xếp trong từng cửa sổ.
  • New_col: Tên bạn muốn đặt cho dữ liệu mới.
  • Table_name: Tên bảng dữ liệu.

Các hàm cửa sổ phổ biến:

![A diagram of a work flow Description automatically generated](https://datapot.vn/wp-content/uploads/2023/12/a-diagram-of-a-work-flow-description-automaticall.png)

Trong phạm vi tài liệu này, chúng ta sẽ tập trung giới thiệu về Ranking Function, hai nhóm hàm còn lại là Aggregate Function và Analytic Function được đưa ra để tham khảo thêm.

Hàm xếp hạng (Ranking Functions)

Một số hàm xếp hạng phổ biến thường được thấy như:

  1. ROW_NUMBER

Dùng để xếp hạng các dòng dữ liệu, nhưng không quan tâm đến giá trị giống nhau.

![A screenshot of a computer Description automatically generated](https://datapot.vn/wp-content/uploads/2023/12/a-screenshot-of-a-computer-description-automatica-26.png)

Ví dụ: Từ bảng Product thuộc bộ dữ liệu adventurewoks, truy vấn tên và đánh số thứ tự theo StandardCost.

![A screenshot of a computer Description automatically generated](https://datapot.vn/wp-content/uploads/2023/12/a-screenshot-of-a-computer-description-automatica-27.png)

Ví dụ: Từ bảng Product thuộc bộ dữ liệu adventurewoks, truy vấn tên, gom nhóm theo màu sắc và đánh số thứ tự, sắp xếp thứ tự theo StandardCost.

![A screenshot of a computer Description automatically generated](https://datapot.vn/wp-content/uploads/2023/12/a-screenshot-of-a-computer-description-automatica-28.png)

Giải thích câu lệnh truy vấn:

  • SELECT: Truy vấn các cột Name, StandardCost và đánh số thứ tự tăng dần bằng hàm ROW_NUMBER dựa trên thứ tự của StandardCost.
  • Hàm cửa sổ với hàm ROW_NUMBER: Gom nhóm theo màu sắc sau đó đánh số thứ tự theo cột StandardCost, sắp xếp theo cột StandardCost.
  • Partition By sẽ tạo ra các tập dữ liệu nhỏ. Sau đó đánh số thứ tự trong từng trường.
  • Hàm RANK

Thường được sử dụng để xếp hạng các dòng dữ liệu dựa trên một hoặc nhiều cột.

Cú pháp của hàm RANK():

  SELECT
      Col_1,
      Col_2,
  RANK() OVER ([PARTITION BY Col_1 ORDER BY Col_2) AS RANK
  FROM Table_name

  • Col_1, Col_2: Cột thực hiện truy vấn.
  • RANK(): Xếp hạng các hàng dữ liệu.
  • OVER( PARTITION BY Col_1): Xác định phạm vi của cửa sổ dữ liệu mà hàm sẽ được áp dụng. Ở đây là đảm bảo hàm RANK() chỉ được áp dụng cho các hàng có cùng giá trị của Col_1.

(PARTITION BY) là không bắt buộc.

  • Table_name: Bảng dữ liệu được sử dụng.

Ví dụ: Từ bảng dữ liệu Product thuộc bộ dữ liệu Product. Truy vấn Name, StandardCost và xếp hạng dựa trên StandardCost.

![A screenshot of a computer Description automatically generated](https://datapot.vn/wp-content/uploads/2023/12/a-screenshot-of-a-computer-description-automatica-29.png)

Giải thích câu lệnh truy vấn:

  • SELECT: Truy vấn các cột Name, StandardCost và xếp hạng bằng hàm RANK dựa trên StandardCost.

Đối với các sản phẩm Touring Tire Tube, Mountain Tire Tube, Water Bottle cùng chung 1 xếp hạng là 3 do có chung cùng một mức StandardCost là 1.8863. Khác với Row_Number sẽ đánh lần thứ tự bất kể StandardCost có chung giá trị.

  1. DENSE_RANK

Hàm DENSE_RANK xếp hạng các dòng dữ liệu, nhưng không bỏ qua thứ hạng nếu có các giá trị giống nhau.

Ví dụ: Nếu có 2 giá trị lớn nhất, cả hai được xếp hạng là 1 và giá trị tiếp theo xếp hạng thứ 2.

Cú pháp của hàm DENSE_RANK:

  SELECT
      Col_1,
      Col_2,
  DENSE_RANK() OVER ([PARTITION BY Col_1 ORDER BY Col_2) AS RANK
  FROM Table_name

  • Col_1, Col_2: Cột thực hiện truy vấn.
  • DENSE_RANK(): Xếp hạng các hàng dữ liệu và không bỏ qua thứ hạng nếu có các giá trị giống nhau.
  • OVER( PARTITION BY Col_1): Xác định phạm vi của cửa sổ dữ liệu mà hàm sẽ được áp dụng. Ở đây là đảm bảo hàm DENSE_RANK() chỉ được áp dụng cho các hàng có cùng giá trị của Col_1.

(PARTITION BY) là không bắt buộc.

  • Table_name: Bảng dữ liệu được sử dụng.

Ví dụ: Từ bảng dữ liệu Product thuộc bộ dữ liệu Product. Truy vấn Name, StandardCost và xếp hạng dựa trên StandardCost.

![A screenshot of a computer Description automatically generated](https://datapot.vn/wp-content/uploads/2023/12/a-screenshot-of-a-computer-description-automatica-30.png)

Giải thích câu lệnh truy vấn:

  • SELECT: Truy vấn các cột Name, StandardCost và xếp hạng bằng hàm DENSE_RANK dựa trên StandardCost.

Đối với các sản phẩm Touring Tire Tube, Mountain Tire Tube, Water Bottle cùng chung 1 xếp hạng là 3 do có chung cùng một mức StandardCost là 1.8863 và xếp hạng được đánh tiếp theo sẽ là 4 thay vì bị bỏ qua như ROW_NUMBER.

Tương tự như ROW_NUMBER thì DENSE_RANK cũng có thể sử dụng kèm với PARTITION BY để phân nhóm dữ liệu và đánh thứ hạng trong từng nhóm.

So sánh 3 hàm RANK, DENSE_RANK và ROW_NUMBER.

Để phân biệt rõ ràng hơn, ta cùng xem ví dụ sau:

Từ bảng SalesLT.Product thuộc bộ dữ liệu adventureworks, truy vấn các cột Name, StandardCost, xếp hạng thứ tự theo hàm RANK, DENSE_RANK và ROW_NUMBER.

![A screenshot of a computer Description automatically generated](https://datapot.vn/wp-content/uploads/2023/12/a-screenshot-of-a-computer-description-automatica-31.png)

Giải thích câu lệnh truy vấn:

  • SELECT: Truy vấn các cột Name, StandardCost, xếp hạng thứ tự theo hàm RANK, DENSE_RANK và ROW_NUMBER.
  • Hàm ROW_NUMBER: Đánh số thứ tự sau khi sắp xếp theo cột dữ liệu đề ra.
  • Hàm RANK: Hàm đánh xếp hạng, khi xếp hạng đến giá trị giống nhau, những giá trị này được xếp cùng chung 1 hạng và bỏ qua xếp hạng tiếp theo.
  • Hàm DENSE_RANK: Xếp hạng hàng dữ liệu theo thứ tự, khi xếp hạng đến các giá trị giống nhau, những giá trị này được xếp cùng chung 1 hạng và không bỏ qua xếp hạng tiếp theo.

Bạn có thể tham khảo các hàm xếp hạng khác tại Microsoft Document.

Một số hàm tính toán trong hàm cửa sổ (Window Functions) khác

Hàm tính toán (Aggregate Functions)

  • Hàm SUM

Hàm SUM được sử dụng để tính tổng của một cột.

Cú pháp của hàm SUM():

  • Expression: Biểu thức cần tính tổng.

Ví dụ: Từ bảng dữ liệu dbo.FactInternetSales và dbo.DimSalesTerritory thuộc bộ dữ liệu AdventureWorksDW2019, kết hợp chung bảng FactInternetSales và DimSalesTerritory. Truy vấn ProductKey, SalesTerritoryCountry, OrderQuantity. Tạo hàm cửa sổ để tính tổng OrderQuantity, sắp xếp theo thứ tự giảm dần của ProductKey.

![A screenshot of a computer Description automatically generated](https://datapot.vn/wp-content/uploads/2023/12/a-screenshot-of-a-computer-description-automatica-32.png)

Giải thích câu lệnh truy vấn:

  • FROM: Dữ liệu được truy vấn từ bảng SalesOrderHeader.
  • INNER JOIN: Kết hợp điểm chung bảng FactInternetSales được gán tên FIS với bảng DimSalesTerritory được gán tên DST.
  • ON: Khai báo điều kiện kết hợp bảng từ cột khoá chính SalesTerritoryKey trong bảng FactInternetSales và khoá ngoại SalesTerritoryKey trong bảng DimSalesTerritory.
  • SELECT: Truy vấn các cột ProductKey, SalesTerrritoryCountry, OrderQuantity.
    • Hàm cửa sổ với hàm SUM: Gom nhóm theo các quốc gia sau đó tính tổng, sắp xếp theo thứ tự giảm dần của ProductKey và gán tên sum_orderqty.

Hàm thống kê (Analytic Functions)

Hàm thống kê (Analytic Functions) thường thấy phổ biến như:

  • LEAD(Col): sử dụng để so sánh giữa giá trị hiện tại và giá trị của dòng tiếp theo.
  • LAG(Col): sử dụng để so sánh giữa giá trị hiện tại và giá trị của dòng trước đó.

Ví dụ: Từ bảng SalesOrderHeader thuộc bộ dữ liệu AdventureWork, truy vấn ngày Order trước và sau của từng đơn hàng so với ngày hạn

Khi nào dùng HAVING khi nào dùng WHERE?

Sự khác biệt giữa mệnh đề WHERE và mệnh đề HAVing trong SQL Server.

Trong câu lệnh SELECT từ khóa HAVING là gì?

Mệnh đề HAVING trong Access xác định những bản ghi đã nhóm được hiển thị trong câu lệnh SELECT bằng mệnh đề GROUP BY. Sau khi mệnh đề GROUP BY kết hợp các bản ghi, mệnh đề HAVING sẽ hiển thị mọi bản ghi được nhóm bởi mệnh đề GROUP BY trong đó có thỏa mãn các điều kiện của mệnh đề HAVING.

Hầm HAVING là gì?

HAVING là một điều kiện được sử dụng trong SQL sau mệnh đề GROUP BY. Nó được sử dụng để lọc các nhóm dữ liệu dựa trên hàm tính toán (aggregate function). Mục đích chính của HAVING là lọc các nhóm dữ liệu sau khi đã thực hiện tính toán. Col_1, Col_2: Cột truy vấn, cột được gộp từ mệnh đề GROUP BY.

Câu hỏi truy vấn SQL là gì?

Câu lệnh SQL, hoặc truy vấn SQL, là các lệnh hướng dẫn hợp lệ mà hệ thống quản lý cơ sở dữ liệu quan hệ hiểu được. Nhà phát triển phần mềm xây dựng các câu lệnh SQL bằng nhiều phần tử ngôn ngữ SQL khác nhau.