Sự khác biệt giữa HAVING và WHERE là gì?


261

Tôi phải đi sai đường hoặc tôi đang có một khoảnh khắc ngu ngốc trong thời gian.

Sự khác biệt giữa HAVINGWHEREtrong một SQL SELECTtuyên bố là gì?

EDIT: Tôi đã đánh dấu câu trả lời của Steven là câu trả lời đúng vì nó chứa bit thông tin chính trên liên kết:

Khi GROUP BYkhông được sử dụng, HAVINGhành xử như một WHEREmệnh đề

Tình huống tôi đã thấy WHEREtrong không có GROUP BYvà là nơi sự nhầm lẫn của tôi bắt đầu. Tất nhiên, cho đến khi bạn biết điều này, bạn không thể chỉ định nó trong câu hỏi.


44
Dòng bạn trích dẫn không phải là bit chính. Bit chính, như wcm đã chỉ ra , đó HAVINGlà bộ lọc tổng hợp, trong khi đó WHERElà bộ lọc tổng hợp trước.
Nick Chammas

liên kết này giúp tôi hiểu nó tốt hơn tất cả các ý kiến ​​dưới đây, nghĩ rằng ai đó có thể nhận được sự giúp đỡ của codeproject.com/Articles/25258/
Lijin Durairaj

Câu trả lời:


94

HAVING chỉ định một điều kiện tìm kiếm cho một nhóm hoặc một hàm tổng hợp được sử dụng trong câu lệnh SELECT.

Nguồn


369

HAVING: được sử dụng để kiểm tra các điều kiện sau khi quá trình tổng hợp diễn ra.
WHERE: được sử dụng để kiểm tra các điều kiện trước khi tập hợp diễn ra.

Mã này:

select City, CNT=Count(1)
From Address
Where State = 'MA'
Group By City

Cung cấp cho bạn một bảng gồm tất cả các thành phố ở MA và số lượng địa chỉ ở mỗi thành phố.

Mã này:

select City, CNT=Count(1)
From Address
Where State = 'MA'
Group By City
Having Count(1)>5

Cung cấp cho bạn một bảng các thành phố trong MA với hơn 5 địa chỉ và số lượng địa chỉ ở mỗi thành phố.


7
Đây phải là câu trả lời được chấp nhận. Sự khác biệt giữa "có" và "ở đâu" làm cho điều này ngay lập tức rõ ràng.
Paul

27

Sự khác biệt số một đối với tôi: nếu HAVINGbị xóa khỏi ngôn ngữ SQL thì cuộc sống sẽ tiếp tục ít nhiều như trước đây. Chắc chắn, một truy vấn thiểu số sẽ cần phải được viết lại bằng cách sử dụng bảng dẫn xuất, CTE, v.v. Có lẽ mã tối ưu hóa của các nhà cung cấp sẽ cần phải được viết lại để giải thích cho điều này, một lần nữa là cơ hội để cải tiến trong ngành.

Bây giờ hãy xem xét cho một thời điểm loại bỏ WHEREkhỏi ngôn ngữ. Lần này, phần lớn các truy vấn tồn tại sẽ cần phải được viết lại mà không có cấu trúc thay thế rõ ràng. Các lập trình viên sẽ phải có được sự sáng tạo, ví dụ như tham gia bên trong vào một bảng được biết có chứa chính xác một hàng (ví dụ: DUALtrong Oracle) bằng cách sử dụng ONmệnh đề để mô phỏng WHEREmệnh đề trước . Những công trình như vậy sẽ bị chiếm đoạt; rõ ràng là có một cái gì đó bị thiếu từ ngôn ngữ và kết quả sẽ tồi tệ hơn.

TL; DR chúng ta có thể mất HAVINGvào ngày mai và mọi thứ sẽ không tệ hơn, có thể tốt hơn, nhưng điều tương tự không thể được nói đến WHERE.


Từ các câu trả lời ở đây, dường như nhiều người dân không nhận ra rằng một HAVINGmệnh đề có thể được sử dụng mà không có một GROUP BYmệnh đề. Trong trường hợp này, HAVINGmệnh đề được áp dụng cho toàn bộ biểu thức bảng và yêu cầu chỉ các hằng số xuất hiện trong SELECTmệnh đề. Thông thường các HAVINGđiều khoản sẽ liên quan đến tổng hợp.

Điều này hữu ích hơn âm thanh. Ví dụ: xem xét truy vấn này để kiểm tra xem namecột có phải là duy nhất cho tất cả các giá trị trong T:

SELECT 1 AS result
  FROM T
HAVING COUNT( DISTINCT name ) = COUNT( name );

Chỉ có hai kết quả có thể xảy ra: nếu HAVINGmệnh đề là đúng thì kết quả có một hàng duy nhất chứa giá trị 1, nếu không kết quả sẽ là tập hợp trống.


Điều đó có tương đương với "CHỌN COUNT (tên DISTINCT) = COUNT (tên) TỪ T" không?
MSpreij

@MSpreij Không biết điều đó có hiệu quả với bạn không, nhưng nó không hoạt động trên máy chủ SQL 2005 nhưng lần đầu tiên thì không
Joe

22

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

Kiểm tra liên kết w3schools này để biết thêm thông tin

Cú pháp:

SELECT column_name, aggregate_function(column_name)
FROM table_name
WHERE column_name operator value
GROUP BY column_name
HAVING aggregate_function(column_name) operator value

Một truy vấn như thế này:

SELECT column_name, COUNT( column_name ) AS column_name_tally
  FROM table_name
 WHERE column_name < 3
 GROUP 
    BY column_name
HAVING COUNT( column_name ) >= 3;

... có thể được viết lại bằng bảng dẫn xuất (và bỏ qua HAVING) như thế này:

SELECT column_name, column_name_tally
  FROM (
        SELECT column_name, COUNT(column_name) AS column_name_tally
          FROM table_name
         WHERE column_name < 3
         GROUP 
            BY column_name
       ) pointless_range_variable_required_here
 WHERE column_name_tally >= 3;

3
Bạn đã bỏ lỡ một chút điểm: HAVINGđã được thêm vào vì các bảng dẫn xuất chưa được thêm vào ngôn ngữ và cho đến khi chúng là SQL không hoàn toàn tương đối và một khi chúng chắc chắn đã HAVINGtrở nên dư thừa.
ngày

21

Sự khác biệt giữa hai là trong mối quan hệ với mệnh đề GROUP BY:

  • Ở ĐÂU đến trước NHÓM THEO; SQL đánh giá mệnh đề WHERE trước khi nhóm ghi lại.

  • HAVING xuất hiện sau NHÓM THEO; SQL đánh giá HAVING sau khi nhóm ghi lại.

chọn sơ đồ câu lệnh

Người giới thiệu


Vì GROUP BY và HAVING đều là tùy chọn, sơ đồ hiển thị cả hai trường hợp, chỉ cần làm theo các mũi tên.
Paul Sweatte

Ví dụ truy vấn từ câu trả lời của tôi cho câu hỏi này: SELECT 1 AS result FROM T HAVING...- trong sơ đồ của bạn, tôi không thể truy cập HAVINGmà không GROUP BYtruy cập nhưng truy vấn hoàn toàn hợp lệ và hữu ích của tôi không có GROUP BY. Điểm nhỏ: bạn không có tùy chọn để bao gồm các giá trị bằng chữ trong SELECTmệnh đề.
onedaywhen

@encedaywhen Vì bạn biết về NHÓM ngầm ẩn, tại sao bạn không đề cập đến nó? Bạn có biết hành vi này có phải là điều bạn đang mong đợi hay không?
Paul Sweatte

Methinks bạn đang trích dẫn tôi ra khỏi bối cảnh. Câu hỏi là về sự sai lệch rõ ràng của myQuery so với Tiêu chuẩn, trừ đoạn cuối câu trả lời của tôi mô tả hành vi Tiêu chuẩn và ám chỉ cuối cùng về "mệnh đề GROUP BY ẩn được đề cập trong các câu trả lời khác ." Bạn đang nói sơ đồ của bạn được dự định để mô tả (tất cả) hành vi ngầm? Sẽ không hữu ích hơn nếu chỉ sử dụng mã bạn cần viết để có hành vi mong muốn?
ngày

... Tôi không biết bạn đang ám chỉ điều gì trong liên kết thứ hai. Kết quả mong muốn là bạn sửa sơ đồ để hiển thị đường dẫn hợp lệ (rõ ràng) mà tôi đã đề cập. Hãy suy nghĩ về nó: sơ đồ bao gồm toàn bộ một truy vấn nhưng câu hỏi chỉ quan tâm đến WHERE->HAVINGphần này, vì vậy tôi nghĩ rằng nó đáng được chú ý đến từng chi tiết. Nếu bạn nghĩ rằng câu trả lời của tôi là sai thì hãy chỉnh sửa nó hoặc đăng một sự điều chỉnh được đề xuất trong các bình luận.
ngày

12

HAVINGđược sử dụng khi bạn đang sử dụng một tổng hợp như GROUP BY.

SELECT edc_country, COUNT(*)
FROM Ed_Centers
GROUP BY edc_country
HAVING COUNT(*) > 1
ORDER BY edc_country;

8

WHERE được áp dụng như một giới hạn trên tập hợp được SQL trả về; nó sử dụng các chỉ số và chỉ mục được thiết lập sẵn của SQL và do đó là cách nhanh nhất để lọc các tập kết quả. Luôn luôn sử dụng WHERE bất cứ khi nào có thể.

HAVING là cần thiết cho một số bộ lọc tổng hợp. Nó lọc truy vấn SAU sql đã lấy, tập hợp và sắp xếp kết quả. Do đó, nó chậm hơn nhiều so với WHERE và nên tránh ngoại trừ trong những tình huống yêu cầu.

SQL Server sẽ cho phép bạn thoát khỏi việc sử dụng HAVING ngay cả khi WHERE sẽ nhanh hơn nhiều. Đừng làm điều đó.


Hỗ trợ cho các bảng dẫn xuất trong ngôn ngữ SQL có nghĩa là khẳng định của bạn "HAVING là cần thiết cho một số bộ lọc tổng hợp" là sai.
ngày

1
Đó là một điểm hay. Trong ba năm kể từ khi tôi viết câu trả lời này, tôi chắc chắn đã chuyển sang sử dụng các bảng dẫn xuất mà trước đây tôi đã từng sử dụng HAVING. Tôi đã không nghĩ qua câu hỏi liệu HAVING có còn một số trường hợp sử dụng có ý nghĩa hay không. Tôi cũng không biết liệu một bảng dẫn xuất sẽ hoạt động tốt hơn so với HAVING.
davidcl

7

Mệnh đề WHERE không hoạt động cho các hàm tổng hợp
có nghĩa là: bạn không nên sử dụng như phần thưởng này: tên bảng

SELECT name  
FROM bonus  
GROUP BY name  
WHERE sum(salary) > 200  

TẠI ĐÂY Thay vì sử dụng mệnh đề WHERE, bạn phải sử dụng HAVING ..

không sử dụng mệnh đề GROUP BY, mệnh đề HAVING chỉ hoạt động như mệnh đề WHERE

SELECT name  
FROM bonus  
GROUP BY name  
HAVING sum(salary) > 200  

4

Sự khác biệt b / w WHEREHAVINGmệnh đề:

Sự khác biệt chính giữa WHEREHAVINGmệnh đề là, WHEREđược sử dụng cho các hoạt động hàng và HAVINGđược sử dụng cho các hoạt động cột.

Tại sao chúng ta cần HAVINGmệnh đề?

Như chúng ta biết, các hàm tổng hợp chỉ có thể được thực hiện trên các cột, vì vậy chúng ta không thể sử dụng các hàm tổng hợp trong WHEREmệnh đề. Do đó, chúng tôi sử dụng các hàm tổng hợp trong HAVINGmệnh đề.


2

Khi GROUP BYkhông được sử dụng, các mệnh đề WHEREHAVINGvề cơ bản là tương đương.

Tuy nhiên, khi GROUP BYđược sử dụng:

  • Các WHEREkhoản được sử dụng để ghi chép bộ lọc từ một kết quả. Việc lọc xảy ra trước khi bất kỳ nhóm được thực hiện.
  • Các HAVINGkhoản được sử dụng để lọc các giá trị từ một nhóm (ví dụ, để kiểm tra điều kiện sau khi tập hợp thành các nhóm đã được thực hiện).

Tài nguyên từ đây


có và nơi không cơ bản tương đương. Nó sẽ báo lỗi trong khi thực thi. không hợp lệ trong mệnh đề HAVING vì nó không có trong hàm tổng hợp hoặc mệnh đề GROUP BY.
Nagendra Kumar

2

Một cách để nghĩ về nó là mệnh đề có là một bộ lọc bổ sung cho mệnh đề where.

Một ĐÂU khoản được sử dụng bộ lọc các bản ghi từ một kết quả. Bộ lọc xảy ra trước khi bất kỳ nhóm được thực hiện. Một HAVING khoản được sử dụng để lọc các giá trị từ một nhóm


1

Trong truy vấn Tổng hợp, (Bất kỳ truy vấn nào sử dụng hàm tổng hợp) Dự đoán trong mệnh đề where được ước tính trước khi tập kết quả trung gian tổng hợp được tạo,

Vị ngữ trong mệnh đề Có được áp dụng cho tập kết quả tổng hợp SAU khi nó được tạo. Đó là lý do tại sao các điều kiện vị ngữ trên các giá trị tổng hợp phải được đặt trong mệnh đề Có, không phải trong mệnh đề Where và tại sao bạn có thể sử dụng các bí danh được xác định trong mệnh đề Chọn trong Mệnh đề Có, nhưng không phải trong Mệnh đề Where.


1

Tôi đã có một vấn đề và tìm ra một sự khác biệt giữa WHEREHAVING. Nó không hoạt động theo cách tương tự trên các cột được lập chỉ mục.

WHERE my_indexed_row = 123 sẽ hiển thị các hàng và tự động thực hiện "ĐẶT HÀNG ASC" trên các hàng được lập chỉ mục khác.

HAVING my_indexed_row = 123 hiển thị mọi thứ từ hàng "được chèn" cũ nhất đến hàng mới nhất, không có thứ tự.


Làm thế nào để bạn biết rằng đây là một sự khác biệt được xác định giữa twain, chứ không phải là một sự cố khi triển khai máy chủ SQL cụ thể mà bạn đang sử dụng?
JdeBP

Tôi vừa thử nó trên MariaDB. Tôi đoán đó là máy chủ SQL tôi đã sử dụng 8 năm trước đã tạo ra các kết quả khác nhau.
Simmoniz

0

Từ đây .

tiêu chuẩn SQL yêu cầu HAVING phải chỉ tham chiếu các cột trong mệnh đề GROUP BY hoặc các cột được sử dụng trong các hàm tổng hợp

trái ngược với mệnh đề WHERE được áp dụng cho các hàng cơ sở dữ liệu


Nguồn nói, "Việc sử dụng các vị trí cột không được chấp nhận vì cú pháp đã bị xóa khỏi tiêu chuẩn SQL." Đáng buồn thay, điều này là sai: không có gì bị xóa khỏi Tiêu chuẩn, điều trớ trêu là tại sao chúng ta vẫn còn HAVINGhàng thập kỷ sau khi nó bị 'phản đối' bởi các bảng dẫn xuất.
onedaywhen

Hơi mô phạm nhưng trích dẫn không chính xác, ví dụ như xem xét SELECT 1 FROM T HAVING COUNT(*) >= 1;- không tham chiếu các cột trong GROUP BYmệnh đề (không có) cũng như các cột trong các hàm tổng hợp (tham chiếu truy vấn không có cột nào cả).
onedaywhen

0

Trong khi làm việc trên một dự án, đây cũng là câu hỏi của tôi. Như đã nêu ở trên, HAVING kiểm tra điều kiện trên kết quả truy vấn đã được tìm thấy. Nhưng ở đâu là để kiểm tra điều kiện trong khi truy vấn chạy.

Hãy để tôi đưa ra một ví dụ để minh họa điều này. Giả sử bạn có một bảng cơ sở dữ liệu như thế này.

có thể sử dụng {int userid, date datefield, int Dailyincome}

Giả sử, các hàng sau nằm trong bảng:

1, 2011-05-20, 100

1, 2011-05-21, 50

1, 2011-05-30, 10

2, 2011-05-30, 10

2, 2011-05-20, 20

Bây giờ, chúng tôi muốn có được userids và sum(dailyincome)của aisum(dailyincome)>100

Nếu chúng ta viết:

CHỌN userid, sum (Dailyincome) TỪ có thể sử dụng được WHERE sum (Dailyincome)> 100 NHÓM THEO userid

Đây sẽ là một lỗi. Truy vấn chính xác sẽ là:

CHỌN userid, sum (Dailyincome) TỪ NHÓM có thể sử dụng B BYNG userid HAVING sum (Dailyincome)> 100


0

Mệnh đề WHERE được sử dụng để so sánh các giá trị trong bảng cơ sở, trong khi mệnh đề HAVING có thể được sử dụng để lọc kết quả của các hàm tổng hợp trong tập kết quả của truy vấn Nhấp vào đây !


0

Khi GROUP BY không được sử dụng, các mệnh đề WHERE và HAVING về cơ bản là tương đương.

Tuy nhiên, khi GROUP BY được sử dụng:

  • Mệnh đề WHERE được sử dụng để lọc các bản ghi từ kết quả. Việc lọc xảy ra trước khi bất kỳ nhóm được thực hiện.
  • Mệnh đề HAVING được sử dụng để lọc các giá trị từ một nhóm (nghĩa là để kiểm tra các điều kiện sau khi tổng hợp thành các nhóm đã được thực hiện).

-1

Tôi sử dụng HAVING để ràng buộc một truy vấn dựa trên kết quả của hàm tổng hợp. AI chọn * trong nhóm blahblahblah bởi SOMETHING có số đếm (SOMETHING)> 0


-1

Nó có thể chỉ là chủ đề của "nơi" là một hàng, trong khi chủ đề "có" là một nhóm. Tôi có đúng không


3
Bạn nên chắc chắn trước khi đăng một câu trả lời. Điều này có thể gây hiểu lầm cho người khác.
pippin1289
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.