Related
I have the following two tables:
1. Lecturers (LectID, Fname, Lname, degree).
2. Lecturers_Specialization (LectID, Expertise).
I want to find the lecturer with the most Specialization.
When I try this, it is not working:
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);
But when I try this, it works:
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);
What is the reason? Thanks.
WHERE clause introduces a condition on individual rows; HAVING clause introduces a condition on aggregations, i.e. results of selection where a single result, such as count, average, min, max, or sum, has been produced from multiple rows. Your query calls for a second kind of condition (i.e. a condition on an aggregation) hence HAVING works correctly.
As a rule of thumb, use WHERE before GROUP BY and HAVING after GROUP BY. It is a rather primitive rule, but it is useful in more than 90% of the cases.
While you're at it, you may want to re-write your query using ANSI version of the join:
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)
This would eliminate WHERE that was used as a theta join condition.
First we should know the order of execution of Clauses i.e
FROM > WHERE > GROUP BY > HAVING > DISTINCT > SELECT > ORDER BY.
Since WHERE Clause gets executed before GROUP BY Clause the records cannot be filtered by applying WHERE to a GROUP BY applied records.
"HAVING is same as the WHERE clause but is applied on grouped records".
first the WHERE clause fetches the records based on the condition then the GROUP BY clause groups them accordingly and then the HAVING clause fetches the group records based on the having condition.
HAVING operates on aggregates. Since COUNT is an aggregate function, you can't use it in a WHERE clause.
Here's some reading from MSDN on aggregate functions.
WHERE clause can be used with SELECT, INSERT, and UPDATE statements, whereas HAVING can be used only with SELECT statement.
WHERE filters rows before aggregation (GROUP BY), whereas HAVING filter groups after aggregations are performed.
Aggregate function cannot be used in WHERE clause unless it is in a subquery contained in HAVING clause, whereas aggregate functions can be used in HAVING clause.
Source
Didn't see an example of both in one query. So this example might help.
/**
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
This filters the table first by the companyId, then groups it (by country and city) and additionally filters it down to just city aggregations of Mexico. The companyId was not needed in the aggregation but we were able to use WHERE to filter out just the rows we wanted before using GROUP BY.
You can not use where clause with aggregate functions because where fetch records on the basis of condition, it goes into table record by record and then fetch record on the basis of condition we have give. So that time we can not where clause. While having clause works on the resultSet which we finally get after running a query.
Example query:
select empName, sum(Bonus)
from employees
order by empName
having sum(Bonus) > 5000;
This will store the resultSet in a temporary memory, then having clause will perform its work. So we can easily use aggregate functions here.
1.
We can use aggregate function with HAVING clause not by WHERE clause e.g. min,max,avg.
2.
WHERE clause eliminates the record tuple by tuple
HAVING clause eliminates entire group from the collection of group
Mostly HAVING is used when you have groups of data and WHERE is used when you have data in rows.
WHERE clause is used to eliminate the tuples in a relation,and HAVING clause is used to eliminate the groups in a relation.
HAVING clause is used for aggregate functions such as
MIN,MAX,COUNT,SUM .But always use GROUP BY clause before HAVING clause to minimize the error.
Both WHERE and HAVING are used to filter data.
In case of a WHERE statement, data filtering happens before you pull the data for operation.
SELECT name, age
FROM employees
WHERE age > 30;
Here the WHERE clause filters rows before the SELECT operation is performed.
SELECT department, avg(age) avg_age
FROM employees
GROUP BY department
HAVING avg_age> 35;
HAVING filters the data after the SELECT operation is performed. Here the operation of computing (aggregation) is done first and then a filter is applied to the result using a HAVING clause.
After creating a testing DB and tables for sql queries I see that from a tutorial that the following should bring up tables but when ran I get an error:
SELECT jobtitle, salary, COUNT(*) FROM employees GROUP BY salary;
ERROR 1055 (42000): Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'company.employees.name' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
This is not the case when I remove the jobtitle
Why is jobtitle not a valid expression for group by when running my query?
Historically, mysql, unlike most other sql servers, has allowed arbitrary fields to be selected when using group by. In your example, jobtitle would be returned from some arbitrary one of the employees rows for the returned salary. There's no guarantee that it would even be the same for a given salary between two runs of the query.
Since this is a common source of bugs, mysql has moved away from allowing this, first allowing opting in to stricter validation and then making it the default. This is controlled by the SQL_MODE system variable. You can revert to the old, bad way by doing set session sql_mode=replace(##sql_mode,'ONLY_FULL_GROUP_BY',''); before your query.
But it is better to follow the stricter rules. You can tell your query explicitly how to find a non-arbitrary jobtitle for each salary, like:
SELECT MIN(jobtitle) AS jobtitle, salary, COUNT(*) FROM employees GROUP BY salary;
or
SELECT MAX(jobtitle) AS jobtitle, salary, COUNT(*) FROM employees GROUP BY salary;
or you can simply group by both, potentially returning multiple rows for a given salary when there is more than one jobtitle for that salary:
SELECT jobtitle, salary, COUNT(*) FROM employees GROUP BY salary, jobtitle;
An important thing to care while writing GROUPBY clause in queries is that:
Only attributes which appear in GROUPBY can be used with SELECT keyword.
Aggregate functions like count,min,max,avg,etc. can be used after SELECT keyword.
So, the correct query will be,
SELECT jobtitle, salary, COUNT(*) FROM employees GROUP BY salary, jobtitle;
Your group by clause must contain all the attributes you add in select statement with aggregate function.
So your query should be
SELECT jobtitle, salary, COUNT(*) FROM employees GROUP BY salary,jobtitle;
I have the following two tables:
1. Lecturers (LectID, Fname, Lname, degree).
2. Lecturers_Specialization (LectID, Expertise).
I want to find the lecturer with the most Specialization.
When I try this, it is not working:
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);
But when I try this, it works:
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);
What is the reason? Thanks.
WHERE clause introduces a condition on individual rows; HAVING clause introduces a condition on aggregations, i.e. results of selection where a single result, such as count, average, min, max, or sum, has been produced from multiple rows. Your query calls for a second kind of condition (i.e. a condition on an aggregation) hence HAVING works correctly.
As a rule of thumb, use WHERE before GROUP BY and HAVING after GROUP BY. It is a rather primitive rule, but it is useful in more than 90% of the cases.
While you're at it, you may want to re-write your query using ANSI version of the join:
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)
This would eliminate WHERE that was used as a theta join condition.
First we should know the order of execution of Clauses i.e
FROM > WHERE > GROUP BY > HAVING > DISTINCT > SELECT > ORDER BY.
Since WHERE Clause gets executed before GROUP BY Clause the records cannot be filtered by applying WHERE to a GROUP BY applied records.
"HAVING is same as the WHERE clause but is applied on grouped records".
first the WHERE clause fetches the records based on the condition then the GROUP BY clause groups them accordingly and then the HAVING clause fetches the group records based on the having condition.
HAVING operates on aggregates. Since COUNT is an aggregate function, you can't use it in a WHERE clause.
Here's some reading from MSDN on aggregate functions.
WHERE clause can be used with SELECT, INSERT, and UPDATE statements, whereas HAVING can be used only with SELECT statement.
WHERE filters rows before aggregation (GROUP BY), whereas HAVING filter groups after aggregations are performed.
Aggregate function cannot be used in WHERE clause unless it is in a subquery contained in HAVING clause, whereas aggregate functions can be used in HAVING clause.
Source
Didn't see an example of both in one query. So this example might help.
/**
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
This filters the table first by the companyId, then groups it (by country and city) and additionally filters it down to just city aggregations of Mexico. The companyId was not needed in the aggregation but we were able to use WHERE to filter out just the rows we wanted before using GROUP BY.
You can not use where clause with aggregate functions because where fetch records on the basis of condition, it goes into table record by record and then fetch record on the basis of condition we have give. So that time we can not where clause. While having clause works on the resultSet which we finally get after running a query.
Example query:
select empName, sum(Bonus)
from employees
order by empName
having sum(Bonus) > 5000;
This will store the resultSet in a temporary memory, then having clause will perform its work. So we can easily use aggregate functions here.
1.
We can use aggregate function with HAVING clause not by WHERE clause e.g. min,max,avg.
2.
WHERE clause eliminates the record tuple by tuple
HAVING clause eliminates entire group from the collection of group
Mostly HAVING is used when you have groups of data and WHERE is used when you have data in rows.
WHERE clause is used to eliminate the tuples in a relation,and HAVING clause is used to eliminate the groups in a relation.
HAVING clause is used for aggregate functions such as
MIN,MAX,COUNT,SUM .But always use GROUP BY clause before HAVING clause to minimize the error.
Both WHERE and HAVING are used to filter data.
In case of a WHERE statement, data filtering happens before you pull the data for operation.
SELECT name, age
FROM employees
WHERE age > 30;
Here the WHERE clause filters rows before the SELECT operation is performed.
SELECT department, avg(age) avg_age
FROM employees
GROUP BY department
HAVING avg_age> 35;
HAVING filters the data after the SELECT operation is performed. Here the operation of computing (aggregation) is done first and then a filter is applied to the result using a HAVING clause.
I have the following two tables:
1. Lecturers (LectID, Fname, Lname, degree).
2. Lecturers_Specialization (LectID, Expertise).
I want to find the lecturer with the most Specialization.
When I try this, it is not working:
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);
But when I try this, it works:
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);
What is the reason? Thanks.
WHERE clause introduces a condition on individual rows; HAVING clause introduces a condition on aggregations, i.e. results of selection where a single result, such as count, average, min, max, or sum, has been produced from multiple rows. Your query calls for a second kind of condition (i.e. a condition on an aggregation) hence HAVING works correctly.
As a rule of thumb, use WHERE before GROUP BY and HAVING after GROUP BY. It is a rather primitive rule, but it is useful in more than 90% of the cases.
While you're at it, you may want to re-write your query using ANSI version of the join:
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)
This would eliminate WHERE that was used as a theta join condition.
First we should know the order of execution of Clauses i.e
FROM > WHERE > GROUP BY > HAVING > DISTINCT > SELECT > ORDER BY.
Since WHERE Clause gets executed before GROUP BY Clause the records cannot be filtered by applying WHERE to a GROUP BY applied records.
"HAVING is same as the WHERE clause but is applied on grouped records".
first the WHERE clause fetches the records based on the condition then the GROUP BY clause groups them accordingly and then the HAVING clause fetches the group records based on the having condition.
HAVING operates on aggregates. Since COUNT is an aggregate function, you can't use it in a WHERE clause.
Here's some reading from MSDN on aggregate functions.
WHERE clause can be used with SELECT, INSERT, and UPDATE statements, whereas HAVING can be used only with SELECT statement.
WHERE filters rows before aggregation (GROUP BY), whereas HAVING filter groups after aggregations are performed.
Aggregate function cannot be used in WHERE clause unless it is in a subquery contained in HAVING clause, whereas aggregate functions can be used in HAVING clause.
Source
Didn't see an example of both in one query. So this example might help.
/**
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
This filters the table first by the companyId, then groups it (by country and city) and additionally filters it down to just city aggregations of Mexico. The companyId was not needed in the aggregation but we were able to use WHERE to filter out just the rows we wanted before using GROUP BY.
You can not use where clause with aggregate functions because where fetch records on the basis of condition, it goes into table record by record and then fetch record on the basis of condition we have give. So that time we can not where clause. While having clause works on the resultSet which we finally get after running a query.
Example query:
select empName, sum(Bonus)
from employees
order by empName
having sum(Bonus) > 5000;
This will store the resultSet in a temporary memory, then having clause will perform its work. So we can easily use aggregate functions here.
1.
We can use aggregate function with HAVING clause not by WHERE clause e.g. min,max,avg.
2.
WHERE clause eliminates the record tuple by tuple
HAVING clause eliminates entire group from the collection of group
Mostly HAVING is used when you have groups of data and WHERE is used when you have data in rows.
WHERE clause is used to eliminate the tuples in a relation,and HAVING clause is used to eliminate the groups in a relation.
HAVING clause is used for aggregate functions such as
MIN,MAX,COUNT,SUM .But always use GROUP BY clause before HAVING clause to minimize the error.
Both WHERE and HAVING are used to filter data.
In case of a WHERE statement, data filtering happens before you pull the data for operation.
SELECT name, age
FROM employees
WHERE age > 30;
Here the WHERE clause filters rows before the SELECT operation is performed.
SELECT department, avg(age) avg_age
FROM employees
GROUP BY department
HAVING avg_age> 35;
HAVING filters the data after the SELECT operation is performed. Here the operation of computing (aggregation) is done first and then a filter is applied to the result using a HAVING clause.
I have problems with the following SQL Query:
SELECT job
FROM (SELECT job, COUNT(*) AS cnt
FROM Employee
GROUP BY job)
WHERE cnt=1
As Result it should only shows all jobs where cnt (count of jobs) equals 1.
When I test the select query above on Fiddle, I get following error :
Incorrect syntax near the keyword 'WHERE'.
SQLFiddle: http://sqlfiddle.com/#!6/d812a/7
No need to increase complexity by using sub-query when it is not require
SELECT job, count(job)
FROM Employee
GROUP BY job
having count(job)=1;
You need to provide alias name to the nested query
SELECT A.job
FROM (SELECT job, COUNT(*) AS cnt
FROM Employee
GROUP BY job)A
WHERE A.cnt=1
You forget to add the alias name.
Please change the query like this
SELECT job
FROM (SELECT job, COUNT(*) AS cnt
FROM Employee
GROUP BY job) As MyTable
WHERE cnt=1
You should have to give the alias name for the inner query when you are using the select and where clauses outside.
You should use the HAVING syntax :
SELECT job, COUNT(*) AS cnt
FROM Employee
GROUP BY job
HAVING cnt = 1;
You should use the HAVING clause which is done for that kind of thing. Your request will be simply :
SELECT job FROM Employee GROUP BY job
HAVING COUNT(id)=1
The documentation states that
The SQL standard requires that HAVING must reference only columns in
the GROUP BY clause or columns used in aggregate functions. However,
MySQL supports an extension to this behavior, and permits HAVING to
refer to columns in the SELECT list and columns in outer subqueries as
well.
The important thing to note is that contrary to the WHERE clause, you can use aggregate funcitons (like count, max, min ...) in the HAVING clause.