ORACLE: not a GROUP BY expression - sql

I am trying to figure this out but I keep getting this error. I know it has something to do with the subqueries in the SELECT and HAVING clauses but I have no idea how to fix them. Any help would be greatly appreciated.
department table: https://gyazo.com/f9d782abd428acc7ec2e7d5d59befad7
employee table: https://gyazo.com/b2d7d792c0933b13d6fdd7166fffb8a6
expected output: https://gyazo.com/41f6a5626a5827acbe76e3c41287742d
EDIT: I figured out an alternative syntax! Thanks for all the help!
CURSOR c_emp (p_total_emp NUMBER) IS
SELECT department.DEPARTMENT_NAME
, MAX(employee.HIRE_DATE)
, (SELECT COUNT(EMPLOYEE_ID)
FROM employee
HAVING HIRE_DATE = MAX(HIRE_DATE))
, ROUND(MAX(employee.SALARY))
, ROUND(MAX(employee.SALARY) * 0.68)
, (SELECT COUNT(EMPLOYEE_ID)
FROM employee
HAVING SALARY > ROUND(MAX(employee.SALARY) * 0.68))
FROM employee
INNER JOIN department
ON employee.DEPARTMENT_ID = department.DEPARTMENT_ID
GROUP BY 1
HAVING (SELECT COUNT(EMPLOYEE_ID)
FROM employee
HAVING SALARY > ROUND(MAX(employee.SALARY) * 0.68)) > p_total_emp
ORDER BY DEPARTMENT_NAME ASC
;
sample:

Hoping you're having a great week so far. :)
Just a heads up on the query, you are experiencing the error because you can't GROUP BY 1. You need to GROUP BY columns that you're not aggregating. (eg. department.DEPARTMENT_NAME) like the following:-
CURSOR c_emp (p_total_emp NUMBER) IS
SELECT department.DEPARTMENT_NAME
, MAX(employee.HIRE_DATE)
, (SELECT COUNT(EMPLOYEE_ID)
FROM employee
HAVING HIRE_DATE = MAX(HIRE_DATE))
, ROUND(MAX(employee.SALARY))
, ROUND(MAX(employee.SALARY) * 0.68)
, (SELECT COUNT(EMPLOYEE_ID)
FROM employee
HAVING SALARY > ROUND(MAX(employee.SALARY) * 0.68))
FROM employee
INNER JOIN department
ON employee.DEPARTMENT_ID = department.DEPARTMENT_ID
GROUP BY department.DEPARTMENT_NAME
HAVING (SELECT COUNT(EMPLOYEE_ID)
FROM employee
HAVING SALARY > ROUND(MAX(employee.SALARY) * 0.68)) > p_total_emp
ORDER BY DEPARTMENT_NAME ASC
;

Related

basic sql employee

The employee table (EMP) specifies groups by department code, the sum of salaries by group, the average (constant treatment), and the number of people in each group's salary, and is presented below, listed in department code order. I would like to modify the following SQL syntax to look up departments whose average salary exceeds 2800000.
SELECT
DEPT
, SUM(SALARY) 합계
, FLOOR(AVG(SALARY)) 평균
, COUNT(*) 인원수
FROM
EMP
GROUP BY
DEPT
ORDER BY DEPT ASC;
question 1. Conditions that need to be modified
question 2. What should I add to the presented code?
I can't read your aliases so I'll just presume what they mean.
If query - you posted in the question - works OK, then use it as a CTE and select desired data from it:
with data as
(select dept,
sum(salary) sumsal,
floor(avg(salary)) avgsal,
count(*) cnt
from emp
group by dept
)
select *
from data
where avgsal > 2800000;
you can use below sql:
SELECT
DEPT
, SUM(SALARY) 합계
, FLOOR(AVG(SALARY)) 평균
, COUNT(*) 인원수
FROM
EMP
GROUP BY
DEPT having FLOOR(AVG(SALARY) > 2800000
ORDER BY DEPT ASC;
You can filter aggregated result using having
SELECT
DEPT
, SUM(SALARY) 합계
, FLOOR(AVG(SALARY)) 평균
, COUNT(*) 인원수
FROM
EMP
GROUP BY DEPT
HAVING AVG(SALARY) >2800000
ORDER BY DEPT ASC;

How to retrieve highest salary for each department across employees?

I am trying to compile a query which gives me the highest salary per each department and for each unique employee. The complexity is that 1 employee can be part of multiple departments.
In case the same employee has the highest salary in several departments, only the department with a lower salary should show. This is my start but I am not sure how to continue from here:
select max(salary) as salary, dd.dept_name,d.emp_no
from salaries s
inner join dept_emp d on
s.emp_no=d.emp_no
inner join departments dd on
d.dept_no=dd.dept_no
group by 2,3;
My output is:
What should I modify from here?
For an employee, you seem to only want to include the department with the smallest salary. I would recommend using window functions:
select s.*
from (select s.*,
rank() over (partition by dept_name order by salary desc) as seqnum_d
from (select s.*, d.dept_name,
rank() over (partition by dept_name order by salary) as seqnum_ed
from salaries s join
dept_emp d
on s.emp_no = d.emp_no join
departments dd
d.dept_no = dd.dept_no
) s
where seqnum_ed = 1
) s
where seqnum_d = 1;
Something like this?
select m.salary, m.emp_no, salary.dept_name from salary,
(select emp_no, min(salary) salary from salary group by emp_no) m
where
m.emp_no=salary.emp_no and m.salary=salary.salary;

Sql - How many people earn min and max salary?

I have a table with Employees, Departments and Salaries and I would like to get min and max salaries per department (what is just min/max with group by on department), but how to count how many Employees earn that min and max salary per department?
Select Department,
Count(distinct EmployeeID) as Employees,
Min(Salary) as Min,
Max(Salary) as Max
From Employees
Group by Department;
You need to make your query as a subquery for the following one :
Select Department, count(*) as "Count People"
From Employees
Where (Department,Salary) IN
(
Select Department, Min(Salary)
From Employees
Group by Department
Union all
Select Department, Max(Salary)
From Employees
Group by Department
)
Group by Department;
Rextester Demo
Maybe you need 2 distinct values for the counters of minimum and maximum salaries of each department:
SELECT t1.Department, t1.MinCounter, t2.MaxCounter FROM
(SELECT t.Department, COUNT(*) AS MinCounter
FROM
(SELECT Department, MIN(Salary) AS MinSalary FROM Employees
GROUP BY Department) AS t
INNER JOIN Employees
ON (t.MinSalary = Employees.Salary) AND (t.Department = Employees.Department)
GROUP BY t.Department) AS t1
INNER JOIN
(SELECT t.Department, COUNT(*) AS MaxCounter
FROM
(SELECT Department, MAX(Salary) AS MaxSalary FROM Employees
GROUP BY Department) AS t
INNER JOIN Employees
ON (t.MaxSalary = Employees.Salary) AND (t.Department = Employees.Department)
GROUP BY t.Department) AS t2
ON t1.Department = t2.Department
The above query consists of 2 subqueries joined by Department, each of which fetches the counter of the minimum and the maximum salary per department. If you also want included in the query the amounts of the minimum and the maximum salary per department, then check this:
SELECT t1.Department, t1.MinSalary, t1.MinCounter, t2.MaxSalary, t2.MaxCounter
FROM
(SELECT t.Department, t.MinSalary, COUNT(*) AS MinCounter
FROM (SELECT Department, MIN(Salary) AS MinSalary FROM Employees
GROUP BY Department) AS t
INNER JOIN Employees
ON (t.Department = Employees.Department)
AND (t.MinSalary = Employees.Salary)
GROUP BY t.Department, MinSalary) AS t1
INNER JOIN
(SELECT t.Department, t.MaxSalary, COUNT(*) AS MaxCounter
FROM (SELECT Department, MAX(Salary) AS MaxSalary FROM Employees
GROUP BY Department) AS t
INNER JOIN Employees
ON (t.Department = Employees.Department)
AND (t.MaxSalary = Employees.Salary)
GROUP BY t.Department, MaxSalary) AS t2
ON t1.Department = t2.Department
You can get the min and max salaries in a subquery, then count how many employees have those salaries in an outer query, like so: https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=b89ac6b76112bf7db65ce6e37754198b
select agg.*
, count(case when e.Salary = agg.MinSalary then 1 end) EmployeesWithMin
, count(case when e.Salary = agg.MaxSalary then 1 end) EmployeesWithMax
from
(
select Department
, count(1) EmployeesInDepartment
, min(Salary) MinSalary
, max(Salary) MaxSalary
from Employees
group by Department
) agg
inner join Employees e
on e.Department = agg.department
and e.Salary in (agg.MaxSalary, agg.MinSalary)
group by agg.Department
, agg.EmployeesInDepartment
, agg.MinSalary
, agg.MaxSalary
Or an alternative approach: https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=8a5e539fcd3e5985d44f86b1e331f030
select agg.Department
, min(agg.MinSalary) MinSalary
, max(agg.MaxSalary) MaxSalary
, count(case when Salary = MinSalary then 1 end) EmployeesWithMin
, count(case when Salary = MaxSalary then 1 end) EmployeesWithMax
from
(
select Department
, min(Salary) over (partition by Department) MinSalary
, max(Salary) over (partition by Department) MaxSalary
, Salary
from Employees
) agg
group by agg.Department
The former may be simpler to understand for a beginner. The latter is less verbose, so easier to read. i.e. Pick whichever you're more comfortable supporting / whichever makes most sense to you.
In terms of performance, the second performed slightly better for my sample data; but a number of variables may influence this (number of rows, spread of values, availability of indexes), so it's best to test on data as similar to real-world as possible if you need to pick the optimal query.
Let me know if any of the methods used here aren't familiar to you and I can add explanations as required.

Ora-00935 error group nested too deeply

The following sql query keeps throwing an error that group function is nested too deeply
select department_name
from department
where department_id in (select department_id
from student
group by department_id
having count(student_id)=max(count(student_id)));
Can someone suggest how to correct this without making other table ??
I do not see what the in buys you. I find this easier to write and to follow with the calculation in the from clause:
select d.department_name
from (select s.department_id, count(*) as num_students,
rank() over (order by count(*) desc) as seqnum
from student s
group by s.department_id
) s join
department d
on s.department_id = d.department_id
where seqnum = 1;
This also makes it easy to add the number of students in the most populous departments.
Try using the MAX analytics function
SELECT department_name
FROM department
WHERE department_id IN
( SELECT
department_id
FROM
( SELECT
department_id,
COUNT(student_id) students,
MAX(COUNT(student_id)) OVER () max_students
FROM student
GROUP BY department_id
)
WHERE students=max_students
);
Not tested.
Or in Oracle 12c onwards you could use the FECTH clause
SELECT department_name
FROM department
WHERE department_id IN
( SELECT department_id
FROM student
GROUP BY department_id
ORDER BY COUNT(student_id) DESC
FETCH FIRST ROW WITH TIES
);

sorting table based on a condition

i have to sort the employees in the EMPLOYEE table by the following rule: when their department is SALES, sort by experience, otherwise sort by SALARY
this is what i have tried :
select FNAME||' '||LNAME as emp_name,salary,HIRE_DATE from employee
where dept_id=(select dept_id from department where name='SALES') order by HIRE_DATE asc;
UNION
select FNAME||' '||LNAME as emp_name,salary,HIRE_DATE from employee
where dept_id NOT IN (select dept_id from department where name='SALES') order by salary desc;
which throws an error because of two orders i think. Any solutions?
try this:
select FNAME||' '||LNAME as emp_name,salary,HIRE_DATE from employee E
join department D
on E.dept_id=D.dept_id
order by (case when D.name='SALES' then HIRE_DATE end),
(case when D.name<>'SALES' then salary end) desc
Sales department is displayed first, sorted by hire_date. Other departments are displayed next ordered by salary.
select FNAME||' '||LNAME as emp_name,salary,HIRE_DATE
from employee
inner join department
on employee.dept_id = department.dept_id
order by
-- Sales department is on top. Swap 0 and 1 if you want sales on bottom
case when department.name = 'SALES'
then 0
else 1
end,
-- And employees are sorted by hire_date
case when department.name = 'SALES'
then employee.HIRE_DATE
else null
end,
-- Employees from other departments are sorted by salary
employee.Salary desc
use decode:
SELECT fname || ' ' || lname AS emp_name
,salary
,hire_date
FROM employee e
,department d
WHERE e.dept_id = d.dept_id
ORDER BY decode(d.name,'SALES',experience,salary)
;
see also http://sqlfiddle.com/#!4/afa6f/1
SELECT e.fname||' '||e.lname as emp_name, e.salary, e.hire_date
FROM employee e, department d
WHERE e.dept_id = d.dept_id
ORDER BY
CASE
WHEN d.name ='SALES' then
hire_date ASC
ELSE
salary DESC
END
OK. Apologies, try this - probably been answered already tho.