2012-02-12 2 views
127

У меня есть две таблицы:SQL - наличие VS где

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

Я хочу найти лектора с большей специализации. Когда я пытаюсь это, он не работает:

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); 

Но когда я пытаюсь это, она работает:

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); 

В чем причина? Благодарю.

+2

Можете ли вы уточнить, какую версию SQL вы используете (MySQL, MS SQL, PostgreSQL, Oracle и т. Д.). Кроме того, когда вы говорите «не работает», вы имеете в виду, что результаты не так, как вы ожидаете, или что существует ошибка компиляции/разбора? – jklemmack

+1

Почему вы используете ALL вместо MAX ?. Есть ли преимущества? – skan

ответ

237

WHERE пункт вводит условие на отдельные строки; Статья HAVING вводит условие на агрегирование, то есть результаты выбора, где один результат, такой как подсчет, средний, минимальный, максимальный или суммарный, был получен из нескольких строк. Ваш запрос вызывает условие второго типа (т. Е. Условие на агрегацию), поэтому HAVING работает правильно.

Как правило, используйте WHERE до GROUP BY и HAVING после GROUP BY. Это довольно примитивное правило, но оно полезно в более чем 90% случаев.

Пока вы на него, вы можете переписать запрос с использованием ANSI версии объединения:

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) 

Это исключит WHERE, который был использован в качестве теты условия соединения.

31

HAVING работает на агрегатах. Поскольку COUNT является агрегированной функцией, вы не можете использовать ее в предложении WHERE.

Here's некоторые чтения из MSDN по совокупным функциям.

8

Вы не можете использовать предложение where с помощью агрегатных функций, потому что, если вы извлекаете записи по условию, оно переходит в запись таблицы по записи, а затем извлекает запись по условию, которое мы даем. Так что в это время мы не можем найти предложение. Хотя предложение clue работает на resultSet, который мы наконец получаем после запуска запроса.

Пример запроса:

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

Это будет хранить Resultset во временной памяти, то иметь пункт будет выполнять свою работу. Поэтому мы можем легко использовать агрегатные функции здесь.

+1

Я думаю, что мы не можем использовать предложение HAVING без предложения GROUP BY. Позиция предложения HAVING - SELECT -> FROM -> WHERE -> GROUP BY -> HAVING -> ORDER BY – Ronnie

8
  1. ИНЕК можно использовать с SELECT, INSERT, UPDATE и заявлением, в то время как HAVING можно использовать только с ЗЕЬЕСТОМ.

  2. WHERE фильтрует строки перед агрегацией (GROUP BY), тогда как группы фильтров HAVING после агрегации выполняются.

  3. Функция агрегации не может использоваться в предложении WHERE, если она не находится в подзапросе, содержащемся в предложении HAVING, тогда как агрегированные функции могут использоваться в предложении HAVING.

Source

2

1. Мы можем использовать агрегатную функцию с HAVING условия не ИНЕК, например, мин, макс, ср.

2. ИНЕКЕ исключает запись кортежа на кортеж предложения HAVING исключает всю группу из коллекции группы

В основном HAVING используется, когда у вас есть группы данных и WHERE используется, когда у вас есть данные в строках ,

4

Не видел пример как в одном запросе. Поэтому этот пример может помочь.

/** 
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 

Это фильтрует таблицу сначала по CompanyID, то группы его (по стране и городу) и дополнительно фильтрует его вниз только город агрегаты Мексики. Компания companyId не нужна в агрегации, но мы могли использовать WHERE для фильтрации только тех строк, которые мы хотели, прежде чем использовать GROUP BY.

6

Сначала мы должны знать порядок выполнения пунктов i.e FROM> WHERE> GROUP BY> HAVING> DISTINCT> SELECT> ORDER BY. Поскольку ГДЕ пункт получает выполняется перед GROUP BY пункта запись не может быть отфильтрована, применяя ГДЕ к GROUP BY применяется запись.

«HAVING такое же, как предложение WHERE, но применяется к сгруппированным записям».

сначала ГДЕ раздел извлекает записи, основываясь на состоянии затем GROUP BY оговорка групп их соответствующим образом, а затем ОГОВОРКА HAVING извлекает записи группы, основанные на имеющей состоянии.

Смежные вопросы