SQL - có VS ở đâu


202

Tôi có hai bảng sau:

1. Lecturers (LectID, Fname, Lname, degree).
2. Lecturers_Specialization (LectID, Expertise).

Tôi muốn tìm giảng viên có Chuyên môn nhất. Khi tôi thử điều này, nó không hoạt động:

SELECT
  L.LectID, 
  Fname, 
  Lname 
FROM Lecturers L, 
     Lecturers_Specialization S
WHERE L.LectID = S.LectID
AND COUNT(S.Expertise) >= ALL (SELECT
  COUNT(Expertise)
FROM Lecturers_Specialization
GROUP BY LectID);

Nhưng khi tôi thử nó, nó hoạt động:

SELECT
  L.LectID,
  Fname,
  Lname 
FROM Lecturers L,
     Lecturers_Specialization S
WHERE L.LectID = S.LectID
GROUP BY L.LectID,
         Fname,
         Lname 
HAVING COUNT(S.Expertise) >= ALL (SELECT
  COUNT(Expertise)
FROM Lecturers_Specialization
GROUP BY LectID); 

Lý do là gì? Cảm ơn.


2
Bạn có thể làm rõ phiên bản SQL nào bạn đang sử dụng (MySQL, MS SQL, PostgreSQL, Oracle, v.v.). Ngoài ra, khi bạn nói "không hoạt động", bạn có nghĩa là kết quả không như bạn mong đợi, hoặc có lỗi biên dịch / phân tích cú pháp không?
jklemmack

2
Tại sao bạn sử dụng TẤT CẢ thay vì MAX?. Có lợi thế gì không?
skan

Câu trả lời:


351

WHEREmệnh đề giới thiệu một điều kiện trên các hàng riêng lẻ ; HAVINGmệnh đề giới thiệu một điều kiện trên các tập hợp , tức là kết quả của lựa chọn trong đó một kết quả duy nhất, chẳng hạn như đếm, trung bình, tối thiểu, tối đa hoặc tổng, đã được tạo từ nhiều hàng. Truy vấn của bạn yêu cầu một loại điều kiện thứ hai (nghĩa là một điều kiện trên tập hợp) do đó HAVINGhoạt động chính xác.

Như một quy tắc của ngón tay cái, sử dụng WHEREtrước GROUP BYHAVINGsau GROUP BY. Đó là một quy tắc khá nguyên thủy, nhưng nó hữu ích trong hơn 90% các trường hợp.

Trong khi bạn đang ở đó, bạn có thể muốn viết lại truy vấn của mình bằng phiên bản ANSI của phép nối:

SELECT  L.LectID, Fname, Lname
FROM Lecturers L
JOIN Lecturers_Specialization S ON L.LectID=S.LectID
GROUP BY L.LectID, Fname, Lname
HAVING COUNT(S.Expertise)>=ALL
(SELECT COUNT(Expertise) FROM Lecturers_Specialization GROUP BY LectID)

Điều này sẽ loại bỏ WHEREđược sử dụng như một điều kiện tham gia theta .


39

HAVINGhoạt động trên tổng hợp. Vì COUNTlà một hàm tổng hợp, bạn không thể sử dụng nó trong một WHEREmệnh đề.

Đây là một số đọc từ MSDN trên các hàm tổng hợp.


30

Trước tiên, chúng ta nên biết thứ tự thực hiện các khoản, tức là TỪ> Ở ĐÂU> NHÓM> HAVING> DISTINCT> CHỌN> ĐẶT HÀNG B .NG. Kể từ ĐÂU khoản được thực hiện trước khi GROUP BY khoản các hồ sơ không thể được lọc bằng cách áp dụng ĐÂU đến một GROUP BY áp dụng hồ sơ.

"HAVING giống như mệnh đề WHERE nhưng được áp dụng trên các bản ghi được nhóm".

đầu tiên mệnh đề WHERE tìm nạp các bản ghi dựa trên điều kiện sau đó mệnh đề GROUP BY nhóm chúng theo đó và sau đó mệnh đề HAVING tìm nạp các bản ghi nhóm dựa trên điều kiện có.


Là thứ tự hoạt động này luôn luôn được sử dụng? Điều gì xảy ra nếu trình tối ưu hóa truy vấn thay đổi thứ tự?
MSIS

1
@MSIS ngay cả khi trình tối ưu hóa truy vấn thay đổi thứ tự, kết quả sẽ giống như khi lệnh này được tuân theo. Đó là một trật tự hợp lý.
Stephen

18
  1. Mệnh đề WHERE có thể được sử dụng với các câu lệnh SELECT, INSERT và UPDATE, trong khi HAVING chỉ có thể được sử dụng với câu lệnh SELECT.

  2. WHERE lọc các hàng trước khi tổng hợp (NHÓM THEO), trong khi các nhóm bộ lọc HAVING sau khi tổng hợp được thực hiện.

  3. Hàm tổng hợp không thể được sử dụng trong mệnh đề WHERE trừ khi nó nằm trong truy vấn con có trong mệnh đề HAVING, trong khi các hàm tổng hợp có thể được sử dụng trong mệnh đề HAVING.

Nguồn


11

Không thấy một ví dụ về cả hai trong một truy vấn. Vì vậy, ví dụ này có thể giúp đỡ.

  /**
INTERNATIONAL_ORDERS - table of orders by company by location by day
companyId, country, city, total, date
**/

SELECT country, city, sum(total) totalCityOrders 
FROM INTERNATIONAL_ORDERS with (nolock)
WHERE companyId = 884501253109
GROUP BY country, city
HAVING country = 'MX'
ORDER BY sum(total) DESC

Cái này lọc bảng đầu tiên bởi công tyId, sau đó nhóm nó (theo quốc gia và thành phố) và thêm vào đó lọc xuống các tập hợp thành phố của Mexico. Công ty không cần thiết trong tổng hợp nhưng chúng tôi có thể sử dụng WHERE để lọc ra các hàng chúng tôi muốn trước khi sử dụng GROUP BY.


nó không phải là một ví dụ điển hình như bạn có thể chuyển đổi: `Ở ĐÂU companyId = 884501253109 GROUP BY nước, nước HAVING thành phố = 'MX'` để: `Ở ĐÂU companyId = 884501253109, country = GROUP 'MX' THEO thành phố '
Etienne Herlaut

Nếu chỉ di chuyển bộ lọc [quốc gia] sang WHERE mà bạn đã đề xuất, truy vấn sẽ lỗi từ CHỌN [quốc gia], vì [quốc gia] không còn được bao gồm trong tập hợp GROUP BY, do đó không thể được chọn.
Nhân

Quan điểm của bạn về tối ưu hóa được thực hiện khi chuyển [quốc gia] sang WHERE vì đó sẽ là một dữ liệu nhỏ hơn được đặt thành NHÓM theo sau. Tất nhiên đây chỉ là một ví dụ để minh họa cho việc sử dụng có thể. Chúng tôi có thể thay đổi thành HAVING sum (tổng cộng)> 1000 và đó sẽ là trường hợp hoàn toàn hợp lệ để bao gồm WHERE và HAVING.
Nhân

9

Bạn không thể sử dụng mệnh đề where với các hàm tổng hợp vì khi tìm nạp các bản ghi trên cơ sở điều kiện, nó sẽ đi vào bản ghi bảng theo bản ghi và sau đó tìm nạp bản ghi trên cơ sở điều kiện chúng tôi đã cung cấp. Vì vậy, thời gian đó chúng ta không thể mệnh đề. Trong khi có mệnh đề hoạt động trên resultset mà cuối cùng chúng ta nhận được sau khi chạy truy vấn.

Ví dụ truy vấn:

select empName, sum(Bonus) 
from employees 
order by empName 
having sum(Bonus) > 5000;

Điều này sẽ lưu trữ các kết quả trong một bộ nhớ tạm thời, sau đó có mệnh đề sẽ thực hiện công việc của nó. Vì vậy, chúng ta có thể dễ dàng sử dụng các hàm tổng hợp ở đây.


2
Tôi nghĩ rằng chúng ta không thể sử dụng mệnh đề HAVING mà không có mệnh đề GROUP BY. Vị trí của Điều khoản HAVING - CHỌN -> TỪ -> Ở ĐÂU -> NHÓM THEO -> CÓ -> ĐẶT HÀNG
B --NG

4

1. Chúng ta có thể sử dụng hàm tổng hợp với mệnh đề HAVING không phải bằng mệnh đề WHERE, ví dụ min, max, avg.

2. Mệnh đề WHERE loại bỏ tuple bản ghi bằng tuple mệnh đề HAVING loại bỏ toàn bộ nhóm khỏi tập hợp nhóm

Chủ yếu là HAVING được sử dụng khi bạn có các nhóm dữ liệu và WHERE được sử dụng khi bạn có dữ liệu theo hàng.

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.