Где против наличия SQL

Я новичок в SQL, и я хотел знать, в чем разница между предложением Where и предложением Have. Для меня это одно и то же, и оба используются для фильтрации записи. Спасибо, что дали мне информацию.


person Tan Lawrence    schedule 12.09.2018    source источник
comment
Возможный дубликат WHERE vs HAVING   -  person jpw    schedule 12.09.2018
comment
Также: stackoverflow.com/questions/15090342/   -  person jpw    schedule 12.09.2018
comment
@jpw первый - довольно ужасный вопрос, потому что один из действительно получивших наибольшее количество голосов ответов поощряет полагаться на глупость mysql, заключающуюся в том, что не нужно указывать группу, и, кроме того, создается впечатление, что где и наличие эквивалентны, но как-то лучше, потому что вы можете использовать псевдонимы с ним. Это ужасная вещь, чтобы сделать ученика   -  person Caius Jard    schedule 12.09.2018
comment
@CaiusJard Я понимаю вашу точку зрения, но некоторые ответы на связанные вопросы действительно объясняют (с различной степенью детализации) различия между где и имеют, поэтому ответ ОП таков: просят есть.   -  person jpw    schedule 12.09.2018
comment
Конечно, хотя я всегда беспокоился о том, что, когда новички, которые не знают предметную область, хорошо читают ТАК, они предпочитают ответы, получившие наибольшее количество голосов и отмеченные галочкой, как более правильные, и я несколько потрясен тем, что ответ, рекомендующий рутинное использование того, за что так высоко проголосовали. Молиться о том, чтобы под капотом MySQL реализовал его как select x from(select y from t) where a=b, а не select y from t group by * having a=b, но даже в этом случае это плохая практика в контексте обучения - однажды студент перейдет к другим БД. MySQL часто выглядит как VB6 вздрагивает   -  person Caius Jard    schedule 13.09.2018


Ответы (2)


К вашему сведению, помимо запросов SELECT, вы можете использовать предложение WHERE с предложением UPDATE и DELETE, но предложение HAVING можно использовать только с запросом SELECT. Пример:

update CUSTOMER set CUST_NAME="Johnny" WHERE CUST_ID=1; //This line of code worked
update CUSTOMER set CUST_NAME="Johnny" HAVING CUST_ID=1; //Incorrect Syntax

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

В то время как предложения WHERE и HAVING можно использовать вместе в запросе SELECT с агрегатной функцией.

SELECT CUST_ID, CUST_NAME, CUST_GENDER
FROM CUSTOMER
WHERE CUST_GENDER='MALE'
GROUP BY CUST_ID
HAVING CUST_ID=8;

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

person RogerSK    schedule 12.09.2018
comment
что вы имеете в виду группы строк, я не совсем понимаю, что \ - person Tan Lawrence; 12.09.2018
comment
группы строк — это строки, имеющие одинаковое значение для определенного поля. - person Cid; 12.09.2018
comment
@TanLawrence Как вы знаете, предложение WHERE будет применяться к каждой отдельной строке в базе данных, а предложение HAVING применяется к группе строк с функцией агрегирования, такой как «Среднее», «Сумма», «Макс.», «Мин.» и т. д. - person RogerSK; 12.09.2018
comment
Этот ответ наполнен синтаксическими ошибками, пожалуйста, очистите его - person Caius Jard; 12.09.2018

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

HAVING используется для фильтрации строк после того, как с ними подействовал GROUP BY. Вы можете указать столбцы в предложении HAVING только в том случае, если они были сгруппированы или являются частью агрегата (означает, что они передаются какой-либо функции, такой как SUM (столбец), AVG (столбец), COUNT (столбец) и т. д.)

Счета сотрудников, у которых было более одного повышения заработной платы:

--yes
SELECT emp_name 
FROM pay_rise_log 
WHERE dept = 'accounts'
GROUP BY emp_name 
HAVING count(*) > 1

--yes - equivalent if HAVING wasn't a thing
SELECT emp_name 
FROM (
  --do this first, count the records
  SELECT emp_name, COUNT(*) as ct 
  FROM pay_rise_log 
  WHERE dept = 'accounts' 
  GROUP BY emp_name 
) a
WHERE a.ct > 1 --and now filter to more than one pay rise

--no, you can't use a count(*) (done during a group by) before the group by is performed
SELECT emp_name 
FROM pay_rise_log 
WHERE dept = 'accounts' AND count(*) > 1 
GROUP BY emp_name

--no
SELECT emp_name 
FROM pay_rise_log 
WHERE dept = 'accounts'
GROUP BY emp_name
HAVING count(*) > 1 AND gender = 'male' --no, the gender column was not grouped and is not presented inside an aggregate function

--works, but is unusual. gender should be in the where clause
SELECT emp_name 
FROM pay_rise_log 
WHERE dept = 'accounts'
GROUP BY emp_name, gender
HAVING count(*) > 1 AND gender = 'male'

--works, but gender should be part of the WHERE clause to avoid needlessly counting females
--also has a potential bug if genders alphabetically after 'male' are present
--though it would count people who have been male even if they aren't currently, which may be a bonus?!
SELECT emp_name 
FROM pay_rise_log 
WHERE dept = 'accounts'
GROUP BY emp_name
HAVING count(*) > 1 AND MAX(gender) = 'male'

MySQL немного утомляет с точки зрения обучения, потому что в некоторых конфигурациях вы можете опустить GROUP BY, и он сделает это неявно за вас, поэтому вы можете не осознавать, что GROUP BY выполняется.

В ответ на ваш комментарий вы можете использовать WHERE перед группой; вы используете его, чтобы выбрать, какие записи вы хотите сгруппировать. Если сотрудников 100 000, а в бухгалтерии только 100, то нет смысла группировать и считать ВСЕХ, только 99% данных выкинуть:

--yes
SELECT emp_name 
FROM pay_rise_log 
WHERE dept = 'accounts' --pick 100 employees
GROUP BY emp_name 
HAVING count(*) > 1 --pick only those with 2 or more pay rises

--no (and potentially wrong too)
SELECT emp_name 
FROM pay_rise_log --pick 100,000 employees
GROUP BY emp_name 
HAVING count(*) > 1 and MAX(dept) = 'accounts' --pick only accounts staff who had more than 1 pay rise
person Caius Jard    schedule 12.09.2018
comment
что, если я использую предложение WHERE перед GROUP BY, результат будет другим? - person Tan Lawrence; 12.09.2018