Oracle PL/SQL group by issue - oracle

I want to do this excercise for Oracle 10g Express
"Write an SQL query to retrieve the department name, firstname,
lastname, salary of the employee who earns the maximum salary for that
department."
I tried this code but it is not working for me.
There are two tables named employees, departments
ERROR is: ORA-00979: not a GROUP BY expression
SELECT first_name, last_name, departments.department_name, salary
FROM employees, departments
where employees.department_id = departments.department_id
group by salary
Output must be like that.

You will want to use an aggregate function to get the result. In this case you will use max() to get the highest salary for each department.
There are several ways that this can be written.
You can use a subquery in a join:
select d.department_name,
e.first_name,
e.last_name,
e.salary
from employees e
inner join
(
select max(salary) MaxSalary, department_id
from employees
group by department_id
) e1
on e.department_id = e1.department_id
and e.salary = e1.maxsalary
inner join departments d
on e.department_id = d.department_id;
Since you are using Oracle, you can use windowing functions to get the result:
select department_name, first_name, last_name, salary
from
(
select d.department_name,
e.first_name,
e.last_name,
e.salary,
row_number() over(partition by d.department_id order by e.salary desc) rn
from employees e
inner join departments d
on e.department_id = d.department_id
) d
where rn = 1
Or you can even use a WHERE clause to filter the data:
select d.department_name,
e.first_name,
e.last_name,
e.salary
from employees e
inner join departments d
on e.department_id = d.department_id
where salary in (select max(salary)
from employees e1
where e.department_id = e1.department_id
group by department_id)

I understand the question that you are asking is in reference to using GROUP BY but I would take a closer look at the question.
"Write an SQL query to retrieve the department name, firstname, lastname, salary of the employee who earns the maximum salary for that department."
I think you would also benefit from looking at the Maximum function since you are looking for the employee with the Maximum salary.
You need an aggregate function to be able to use GROUP BY. Aggregate functions are functions that perform a task over several records. These are functions like SUM, AVG, and COUNT. When you have an aggregate function, you group by whatever is not in the function.
In your example, MAX would be your aggregate function and you can use your GROUP BY successfully.
Here is a link for Aggregate Functions

Related

Oracle HR Schema. Selecting of max salary from Employees

I need to select city, max salary in the city and employee name whose salary is max from Oracle HR Schema.
I try to do below code, but city name repeats:
select l.city, e.last_name, e.salary from locations l
inner join departments d on l.location_id = d.location_id
inner join employees e on d.department_id = e.department_id
and e.salary = (select max(salary) from employees where department_id = d.department_id)
group by l.city, e.last_name, e.salary
order by e.salary;
What is wrong with my code?
I've attached result, which I need.Correct SQL result
You can use the DENSE_RANK analytic function (which will return all employees with the maximum salary per city):
SELECT city,
last_name,
salary
FROM (
SELECT l.city,
e.last_name,
e.salary,
DENSE_RANK() OVER (
PARTITION BY l.location_id
ORDER BY e.salary DESC
) AS rnk
FROM locations l
INNER JOIN departments d
ON l.location_id = d.location_id
INNER JOIN employees e
ON d.department_id = e.department_id
)
WHERE rnk = 1;
or aggregation with KEEP (which will only return one employee with the maximum salary and the maximum last name per location):
SELECT MAX(l.city) AS city,
MAX(e.last_name) KEEP ( DENSE_RANK LAST ORDER BY e.salary ) AS last_name,
MAX(e.salary) AS salary
FROM locations l
INNER JOIN departments d
ON l.location_id = d.location_id
INNER JOIN employees e
ON d.department_id = e.department_id
GROUP BY
l.location_id
What is wrong with my code?
You are correlating on department_id = d.department_id and not on the location (or city name; however, don't aggregate on the city name as there could be two different locations with the same name).

how to get a row number for each group in report?

i am making a report that getting employees for each group and i need to get a row number for each employee in each department group
select rownum,e.empno, e.ename, e.sal, e.comm, e.deptno, d.dname
from emp e
left join dept d on emp.deptno = dept.deptno
order by deptno;
We can try using ROW_NUMBER here:
SELECT
ROW_NUMBER() OVER (PARTITION BY emp.deptno ORDER BY emp.ename) rn,
emp.empno,
emp.ENAME,
emp.SAL,
emp.COMM,
emp.DEPTNO,
dept.dname
FROM emp
LEFT JOIN dept
ON emp.deptno = dept.deptno
ORDER BY
emp.deptno;
Note that you never provided logic for what should decide the ordering of each employee within a department. In the absence of this, I have used the employee name. If you want some other ordering, then just modify the ORDER BY clause in the call to ROW_NUMBER.

Missing Function Error in Count

I have 2 data tables, Employees and Departments. I want to show the department numbers, department names, the number of employees in each department, the average salary of each department, the employee names, their salaries, and jobs IDs of the employees. Here's what I wrote for my code:
select d.department_id, d.department_name, e.count(*) Employees,
avg(e.salary) Avg_salary, e.last_name, e.salary, e.job_id
from departments d join employees e
on d.department_id = e.department_id
group by d.department_id, d.department_name, e.last_name, e.salary, e.job_id
order by d.department_id;
However, the error "Missing Function" appears when I run the code. How do I fix it?
try this:
SELECT d.department_id,
d.department_name,
Count(*) Employees,
Avg(e.salary) Avg_salary,
e.last_name,
e.salary,
e.job_id
FROM departments d
JOIN employees e
ON d.department_id = e.department_id
GROUP BY d.department_id,
d.department_name,
e.last_name,
e.salary,
e.job_id
ORDER BY d.department_id;
e.count(*) should just be count(*).
EDIT:
Is this what you need?
COUNT(*) OVER (PARTITION BY e.department_id) DeptCt

In HQL, How to get comma separated string from subquery result in select clause?

I have a requirement to display the sub-query result as comma separated string in HQL.
select DEPARTMENT_ID,
(select FIRST_NAME
FROM EMPLOYEES
where DEPARTMENT_ID =90) as Employee_Names
FROM DEPARTMENTS
where DEPARTMENT_ID =90;
The sub-query result in the select clause i need to show as comma separated values.
Any help is appreciated in advance. Thanks.
I see two possible solution.
First
Do it in Oracle:
select
d.DEPARTMENT_ID,
listagg(FIRST_NAME, ',') within group(order by FIRST_NAME) as Employee_Name
FROM
DEPARTMENTS d join EMPLOYEES e
on d.DEPARTMENT_ID = e.DEPARTMENT_ID
where
d.DEPARTMENT_ID = 90
group by
d.DEPARTMENT_ID
It has limitation : If total length of concateneted strings >4000 then code would fail.
Second
I assume this code is needed for some report then you can collect all FIRST_NAME and then manually read ResultSet(If you code works in Java) and combine data as you want. Then you can overhead limit of 4000 characters in Oracle.
select
d.DEPARTMENT_ID,
FIRST_NAME as Employee_Name
FROM
DEPARTMENTS d join EMPLOYEES e
on d.DEPARTMENT_ID = e.DEPARTMENT_ID
where
d.DEPARTMENT_ID =90

How to use group function in self join?

I want to convert Subquery into Join, following is the subquery
SELECT employee_id, last_name, salary
FROM employees
WHERE salary > (SELECT AVG(salary)
FROM employees);
I wrote following join, but I am getting "ORA-00934: group function is not allowed here" error
SELECT e.employee_id,
e.last_name,
e.salary
FROM employees e
INNER JOIN employees average
ON(e.salary>AVG(average.salary));
You can use this like
SELECT e.employee_id,
e.last_name,
e.salary
FROM employees e
INNER JOIN (select AVG(salary) salary from employees ) average
ON (e.salary > average.salary)
Group by e.employee_id;

Resources