Given a staff table with the following attributes:
ec,name,code,dob,salary
List the staff members earning more than the average salary.
My solution:
select* from staff where salary > avg(salary);
What is wrong with it?
An aggregate may not appear in the WHERE clause unless it is in a subquery contained in a HAVING clause or a select list, and the column being aggregated is an outer reference.
Example using WHERE clause :
select *
from staff
where salary > (select avg(salary) from staff)
Example using HAVING clause :
select deptid,COUNT(*) as TotalCount
from staff
group by deptid
having count(*) > 2
Having clause specifies a search condition for a group or an aggregate. HAVING can be used only with the SELECT statement. HAVING is typically used in a GROUP BY clause. When GROUP BY is not used, HAVING behaves like a WHERE clause.
Related
I am trying to get the emp_id of everyone who sold more than 100000.
This query returns all employees and their sales:
SELECT SUM(total_sales), emp_id
FROM works_with
GROUP BY emp_id;
Something like this doesn't work:
SELECT emp_id
FROM works_with
WHERE SUM(total_sales), emp_id
GROUP BY emp_id > 100000;
Do I need to use nested queries?
For this solution you need to group the data by emp_id and then with group by you need to use having clause instead of where clause to filter the data with following condition SUM(total_sales)>100000.
So with your first query is perfect. You just need to add having SUM(total_sales)>100000 with it.
SELECT emp_id
FROM works_with
GROUP BY emp_id
having SUM(total_sales)>100000;
I have 2 columns:
DEPT_ID number;
DEPT_SUB_ID varchar2(5);
I want to find all the DEPT_ID's which have more than one unique value for DEPT_SUB_ID.
How can this be done?
I would use:
select dept_id
from x
group by dept_id
having min(dept_sub_id) <> max(dept_sub_id);
In many cases, two simple aggregations (such as min() or max()) have better performance than a count(distinct).
select dept_id, count(distinct dept_sub_id)
from x
group by dept_id
having count(distinct dept_sub_id) > 1
The keys here are count(distinct) which counts the distinctly different dept_sub_id's within the dept_id
Group by, obviously groups the counts by dept_id
having is like a "where" ran after the group-by does its grouping.
Simply use count with distinct.
select dept_id,count(distinct dept_sub_id)
from dept
group by dept_id
having count(distinct dept_sub_id) > 1;
I am trying to find the number of employees in a table that earn exactly the maximum salary of all the employees in the table called tblPerson.
Select Max(x.[No of Employees]) as Number, x.Salary as Salary
from
(
Select Count(Id) as [No of Employees], Salary
from tblPerson
Group by Salary
Having Salary = MAX(Salary)
)x
where x.[No of Employees]=3
Now I know this is a kind of long and complex way of doing it, but I was trying to do it using a derived table. But I am getting the error:
"Column 'x.Salary' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause"
My question is, why am I getting this particular error since the main query is a simple Select statement with a where clause. Isn't it??
Mainly, aggregate functions work only with other aggregate functions or grouped by columns.
Why? Because an aggregate function needs to know the set of values to do calculation with.
In you case, the max() will want to use all the data available for the calculation and display a single result (single row) and the other column will want to be displayed row by row. So there's a conflict.
Thank you all. Every answer helped me. However, I think I found a pretty simple way to do it:
Select top 1 Count(Id) as [No of Employees], salary
from tblPerson
Group by Salary
Order by [No of Employees] DESC
select count(*) from tblPerson where salary=(select max(salary) from tblPerson)
You get the error because 'max' is an aggregation, while you have nothing to aggregate the number by.
Select Max(x.[No of Employees]) as Number, x.Salary as Salary
from
(
Select Count(Id) as [No of Employees], Salary
from tblPerson
Group by Salary
Having Salary = MAX(Salary)
)x
---------
Group by Salary -- all other items in your select statement
---------
where x.[No of Employees]=3
however, you can also use a temporary table or variable to find the persons.
To solve this via a variable, you could do the following
declare #maxSalary Decimal
set #maxSalary = (Select max(salary) from tblperson) --insert the max value into a variable
Then either aggregate the persons (or do some other logic):
Select ID from tblperson where salary = #maxSalary
The reason for not using a group by is that using a variable is more efficient, as you search the table instead of aggregating over it.
Create a CTE (RESULT), and using DENSE_RANK function, get the highest salary, together with the EmployeeID's.
The first row of the RESULT table will give the highest salary.
Using the aggregate function COUNT, get the number of Employees with the highest Salary.
with RESULT (EmployeeID, Salary, DenseRank) as
(select EmployeeID, Salary,
DENSE_RANK() over (ORDER BY SALARY DESC) AS DenseRank
from Employee)
select TOP 1 Salary,
(select COUNT(EmployeeID)
from Employee
where Salary = (select TOP 1 Salary)
from RESULT
where DenseRank = 1)
)
from RESULT
where DenseRank = 1;
i want to use a simple count(*) code but there is something wrong.
select fname,lname, dno, count(*) from employee group by dno having count(*);
I am getting the following error:
ERROR at line 4: ORA-00920: invalid relational operator
thank you very much!!
For a group operation to be performed, you need to mention the column names in the group by clause.
So the final query for you would be :
select fname,lname, dno, count(*) from employee group by dno,fname,lname;
Hope this helps. :)
This query has two problems:
1. Invalid use of group by operator
2. Syntax error in having clause.
For step1: Group by clause to be used, make sure you have all columns in group by clause which you are mentioning in select statement.
Biggest demerit of this way is, This grouping makes sub groups and using function like count(*) becomes senseless.
ex- If you have total 10 record of which 2 unique record in "dno" and "lname" is completely unique(which will be obvious practically). Then using group by dno,lname will create total of 10 groups and count(*) will return 1,1,1 value for each one of them. Actual need of group by got lost just to make query run.
So be careful.
For step2 : correct syntax is having count()>1 or count()=2 or anything you want but complete it.
To preserve your logical requirement, you can use analytical function like below:
select e1.fname,e1.lname,e1.dno from
(select fname,lname, dno, count(*) over (partition by dno) as cnt
from employee) e1
where e1.cnt>1;
e.cnt>1 in above query is my assumption. use it as per your need.
No need for "having"
select fname,lname, dno, count(*) from employee group by dno;
You should have an expression for having clause.
Try
select fname,lname, dno, count(*) from employee group by dno having count(*) > 0;
Also I think #Timur is right, there is no need for you to even have the having clause , group by is sufficient
select fname,lname, dno, count(*)
from employee
group by dno,fname,lname;
your have missed few column name in group by , also having should have the relational operator.
please try
select fname,lname, dno, count(1) from employee group by fname,lname,
dno having count(1)>=1;
I have a table Employees, which has Fields as below:
Employee_name,Employee_id,Employee_status,Employee_loc,last_update_time.
This table does not have any constraint.
I have tried the below query.
select Employee_name, count(1)
from Employees
where Employee_status = 'ACTIVE'
Group by Employee_name,Employee_loc
having count(Employee_name) > 1
order by count(Employee_name) desc
In the select, I need to get Employee_id too.. Can any one help on how to get that?
You can just add Employee_id to the query, and also add it to the group by clause. (Adding it to the grouping won't make any difference in the query results, assuming each employee name each employee id is unique).
If the grouping does make a difference, that implies that some combinations of employee name and location have more than one ID associated with them. Your query would therefore need to decide which ID to return, possibly by using an aggregate function.
SELECT EMPLOYEE_NAME, EMPLOYEE_ID, COUNT(1)
FROM
EMPLOYEES
WHERE
EMPLOYEE_NAME IN
(
SELECT EMPLOYEE_NAME
FROM EMPLOYEES
WHERE Employee_status = 'ACTIVE'
GROUP BY Employee_name,Employee_loc
HAVING COUNT(*) > 1
)
GROUP BY EMPLOYEE_NAME, EMPLOYEE_ID
You can also use partition by clause and select whichever columns you want to see irrespective of the columns you are using for aggregation.
A very short and simple explanation here - Oracle "Partition By" Keyword