Яка різниця між HAVING та WHERE?


261

Я, мабуть, гуглю в неправильний спосіб, або я маю дурний момент у часі.

Яка різниця між твердженням HAVINGта WHEREу ньому SQL SELECT?

EDIT: Я позначив відповідь Стівена як правильну, оскільки вона містила ключовий біт інформації за посиланням:

Коли GROUP BYне використовується, HAVINGповодиться як WHEREзастереження

Ситуації, в якій я бачив WHERE, не було, GROUP BYі саме там почалася моя плутанина. Звичайно, поки ви цього не знаєте, ви не можете вказати це у питанні.


44
Рядок, який ви цитуєте, зовсім не є ключовим бітом. Ключовий біт, як вказував wcm , - HAVINGце фільтр після агрегації, тоді як фільтр WHEREперед агрегацією.
Нік Чаммас

це посилання допомогло мені зрозуміти це краще, ніж усі коментарі нижче, думав, що хтось може отримати допомогу за цим codeproject.com/Articles/25258/…
Ліхін Дурайрай

Відповіді:


94

HAVING вказує умову пошуку для групи або сукупної функції, що використовується в операторі SELECT.

Джерело


369

HAVING: використовується для перевірки умов після проведення агрегації.
ДЕ: використовується для перевірки умов до того, як відбудеться агрегація.

Цей код:

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

Надає таблицю всіх міст в MA та кількість адрес у кожному місті.

Цей код:

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

Надає таблицю міст у МА з більш ніж 5 адресами та кількістю адрес у кожному місті.


7
Це має бути прийнятою відповіддю. Відмінність "мати" і "де" це робить це відразу зрозумілим.
Пол

27

Відмінність номер одне для мене: якщо HAVINGвилучити з мови SQL, то життя продовжувалося б більш-менш, як раніше. Звичайно, запити меншини повинні бути переписані за допомогою похідної таблиці, CTE тощо, але, можливо, їх було б легше зрозуміти і підтримувати в результаті. Можливо, код оптимізатора постачальників потрібно буде переписати, щоб врахувати це, знову ж таки можливістю вдосконалення в галузі.

Тепер подумайте на мить, видаляючи WHEREз мови. Цього разу більшість існуючих запитів потрібно буде переписати без очевидної альтернативної конструкції. Кодери повинні бути творчими, наприклад, внутрішнє приєднання до таблиці, яка, як відомо, містить точно один рядок (наприклад, DUALв Oracle), використовуючи ONпункт для імітації попереднього WHEREпункту. Такі конструкції були б надумані; було б очевидно, що чогось не вистачає з мови, і в результаті ситуація буде гіршою.

TL; DR, ми могли б програти HAVINGзавтра, і все було б не гірше, можливо, краще, але те ж саме не можна сказати WHERE.


З відповідей тут, здається, багато людей не розуміють, що HAVINGстаття може використовуватися без GROUP BYзастереження. У цьому випадку HAVINGпропозиція застосовується до всього виразу таблиці і вимагає, щоб у SELECTпункті з’являлися лише константи . Зазвичай HAVINGстаття включає сукупності.

Це корисніше, ніж це звучить. Наприклад, розгляньте цей запит, щоб перевірити, чи nameунікальний стовпець для всіх значень у T:

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

Можливі лише два результати: якщо HAVINGпункт істинний, то результат з одним рядком, що містить значення 1, інакше результатом буде порожній набір.


Це буде еквівалентно "SELECT COUNT (DISTINCT name) = COUNT (name) ОТ T"?
MSpreij

@MSpreij Не знаєте, чи це працює для вас, але це не працює на SQL сервері 2005 року, але перший
Джо

22

У SQL було додано пропозицію HAVING, оскільки ключове слово WHERE не можна було використовувати з агрегатними функціями.

Перегляньте це посилання w3schools для отримання додаткової інформації

Синтаксис:

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

Запит на зразок цього:

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;

... може бути переписаний за допомогою похідної таблиці (і опущення HAVING) так:

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
Ви трохи не пропустили суть: HAVINGдодали, тому що похідні таблиці не були додані до мови, і поки вони не були SQL не були відносно повними, і коли вони неминуче HAVINGстали зайвими.
день, коли

21

Різниця між ними полягає у відношенні до пункту GROUP BY:

  • ДЕ ПРИГАДАЄТЬСЯ перед GROUP BY; SQL оцінює пункт WHERE перед тим, як групувати записи.

  • HAVING приходить після GROUP BY; SQL оцінює HAVING після того, як він групує записи.

вибрати діаграму оператора

Список літератури


Оскільки GROUP BY і HAVING є необов’язковими, на схемі показано обидва випадки, просто дотримуйтесь стрілок.
Пол Sweatte

Приклад запиту з моєї відповіді на це запитання: SELECT 1 AS result FROM T HAVING...- у вашій діаграмі я не можу дійти, HAVINGне пройшовши, GROUP BYале мій ідеально правильний і корисний запит не має GROUP BY. Незначна точка: у вас немає можливості включати буквальні значення в SELECTпункт.
день, коли

@onedaywhen Оскільки ви знаєте про неявну групу BY, чому ви її не згадали? Чи знаєте ви, чи така поведінка ви очікуєте чи ні?
Пол Sweatte

Ви думаєте, що ви цитуєте мене поза контекстом. Питання стосувалося очевидного відхилення mySQL від Standard, всі, крім останнього абзацу моєї відповіді, описують поведінку Standard, а останній натякає на "неявний пункт GROUP BY, згаданий в інших відповідях ". Ви кажете, що ваша діаграма призначена для опису (всіх) неявних поведінки? Чи не було б корисніше дотримуватися лише коду, який потрібно написати, щоб отримати бажану поведінку?
день, коли

... Я не знаю, на яку поведінку ви нагадаєте у другому посиланні. Бажаним результатом є те, що ви зафіксуєте діаграму, щоб показати дійсний (явний) шлях, який я згадав. Подумайте: діаграма охоплює цілий запит, проте питання цікавить лише WHERE->HAVINGчастину, тому я думаю, заслуговує пильної уваги на деталі. Якщо ви вважаєте, що моя відповідь неправильна, відредагуйте її або опублікуйте запропоновану корекцію в коментарях.
день, коли

12

HAVINGвикористовується, коли ви використовуєте агрегат, такий як GROUP BY.

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

8

WHERE застосовується як обмеження на множину, повернуту SQL; він використовує вбудований набір засобів SQL та індекси, а тому є найшвидшим способом фільтрації наборів результатів. Завжди використовуйте, де це можливо.

HAVING необхідний для деяких агрегатних фільтрів. Він фільтрує запит ПІСЛЯ sql знайшов, зібрав і сортував результати. Тому це набагато повільніше, ніж ДІЙ і його слід уникати, за винятком тих ситуацій, які цього вимагають.

SQL Server дозволить вам уникнути використання HAVING навіть тоді, де ДЕЙ було б набагато швидше. Не робіть цього.


Підтримка похідних таблиць на мові SQL означає, що ваше твердження "HAVING необхідний для деяких сукупних фільтрів" є помилковим.
день, коли

1
Це хороший момент. За три роки, відколи я написав цю відповідь, я, безумовно, перейшов до використання похідних таблиць, де раніше використовував би HAVING. Я не замислювався над питанням про те, чи все-таки в деяких випадках є сенс використання, який має сенс. Я також не знаю, чи отримана таблиця буде в цілому краще, ніж ВІДХОДЖЕНА.
davidcl

7

WHERE пункт не працює для сукупних функцій,
означає: не слід використовувати такий бонус: ім'я таблиці

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

ТУТ Замість використання пункту WHERE ви повинні використовувати HAVING ..

без використання групи GROUP BY, пункт HAVING просто працює як пункт WHERE

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

4

Різниця ч / б WHEREта HAVINGпункт:

Основна відмінність між WHEREі HAVINGпунктом є, WHEREвикористовується для рядкових операцій і HAVINGвикористовується для стовпців.

Для чого нам потрібна HAVINGстаття?

Як ми знаємо, функції сукупності можуть виконуватися лише на стовпцях, тому ми не можемо використовувати агрегатні функції в WHEREпункті. Тому ми використовуємо сукупні функції в HAVINGп.


2

Якщо GROUP BYне використовується, а WHEREта HAVINGпункти по суті є рівнозначними.

Однак при GROUP BYвикористанні:

  • Цей WHEREпункт використовується для фільтрації записів із результату. Фільтрація відбувається перед тим, як проводиться будь-яке групування.
  • Цей HAVINGпункт використовується для фільтрації значень з групи (тобто для перевірки умов після того, як було проведено агрегацію в групи).

Ресурс звідси


наявність і де по суті не є рівнозначними. це дасть помилку під час виконання. недійсний у пункті HAVING, оскільки він не міститься ні в сукупній функції, ні в пункті GROUP BY.
Нагендра Кумар

2

Один із способів подумати про це - це те, що клавіша наявність є додатковим фільтром до пункту "де".

Стаття WHERE використовується, фільтрує записи з результату. Фільтр відбувається перед тим, як проводиться будь-яке групування. HAVING пропозиції використовуються для значень фільтра з групи ,


1

У агрегованому запиті (Будь-який запит, де використовується сукупна функція) Визначає в пункті, де оцінюється перед тим, як генерується сукупний проміжний набір результатів,

Присудки в пункті Має бути застосовані до сукупного набору результатів ПІСЛЯ його генерування. Ось чому умови предикату для сукупних значень повинні бути розміщені в пункті Маючи, а не в пункті "Де", і чому ви можете використовувати псевдоніми, визначені в "Вибрати" в "Маючи застереження", але не в "Де".


1

У мене виникла проблема і з'ясувалася ще одна різниця між WHEREі HAVING. Він не діє однаково на індексованих стовпцях.

WHERE my_indexed_row = 123 покаже рядки та автоматично виконає "ЗАМОВЛЕННЯ ASC" для інших індексованих рядків.

HAVING my_indexed_row = 123 показує все, починаючи з найстарішого "вставленого" рядка до найновішого, без впорядкування.


Звідки ви знаєте, що це певна різниця між twain, а не випадковість реалізації конкретного SQL-сервера, який ви використовували?
JdeBP

Я щойно тестував це на MariaDB. Я думаю, що саме SQL-сервер, який я використовував 8 років тому, дав різні результати.
Сіммоніз

0

Від сюди .

стандарт SQL вимагає, щоб HAVING повинен посилатися лише на стовпці в пункті GROUP BY або стовпці, що використовуються в сукупних функціях

на відміну від пункту WHERE, який застосовується до рядків бази даних


Джерело говорить: "Використання позицій стовпців застаріле, оскільки синтаксис було видалено зі стандарту SQL". На жаль, це неправильно: ніколи нічого не вилучається зі Стандарту, тому, як це не дивно, тому у нас все ще є HAVINGдесятиліття після того, як він був «застарілий» за отриманими таблицями.
одного дня, коли

Трохи педантичний, але цитата невірна, наприклад, врахуйте SELECT 1 FROM T HAVING COUNT(*) >= 1;- не посилається на стовпці в GROUP BYпункті (немає) або стовпці в сукупних функціях (посилання на запити взагалі немає стовпців).
одного дня, коли

0

Під час роботи над проектом це також було моїм питанням. Як було сказано вище, HAVING перевіряє стан результату запиту, який уже знайшов. Але де для перевірки стану під час запуску запиту.

Наведу приклад, щоб проілюструвати це. Припустимо, у вас є така таблиця баз даних.

usertable {int userid, поле дати, int dailyincome}

Припустимо, наступні рядки знаходяться в таблиці:

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

Тепер ми хочемо отримати useridі sum(dailyincome)чиїsum(dailyincome)>100

Якщо ми пишемо:

ВИБІР користувача, сума (щоденний дохід) ВІД користувача, де сума (щоденний дохід)> 100 ГРУПИ ПО користувач

Це буде помилка. Правильним запитом буде:

ВИБРАТИ userid, сума (щоденний дохід) ВІД користувацької групи за користувачем користувач HAVING сума (щоденний дохід)> 100


0

WHERE застереження використовується для порівняння значень у базовій таблиці, тоді як пункт HAVING може використовуватися для фільтрації результатів сукупних функцій у наборі результатів запиту Клацніть тут !


-1

Я використовую HAVING для обмеження запиту на основі результатів сукупної функції. EG select * у групі blahblahblah за допомогою SOMETHING, що має кількість (SOMETHING)> 0


-1

Це може бути просто темою "де" є рядок, тоді як суб'єктом "мати" є група. Маю рацію?


3
Ви повинні бути впевнені, перш ніж публікувати відповідь. Це може ввести в оману інших.
pippin1289
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.