How to use group function in self join? - oracle

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;

Related

Using JOIN with cte

I have the following setup, which seems to be working fine. I am having trouble modifying the query to include the department_name in the output.
I can't seem to get the JOIN working with the CTE. Its probably something trivial but after many attempts I can't get it to work.
Any help would be appreciated.
Below is my setup and test case.
CREATE TABLE departments( department_id, department_name) AS
SELECT 1, 'IT' FROM DUAL UNION ALL
SELECT 2, 'DBA' FROM DUAL;
CREATE TABLE employees (employee_id, first_name, last_name, hire_date, salary, department_id) AS
SELECT 1, 'Lisa', 'Saladino', DATE '2001-04-03', 100000, 1 FROM DUAL UNION ALL
SELECT 2, 'Abby', 'Abbott', DATE '2001-04-04', 50000, 1 FROM DUAL UNION ALL
SELECT 3, 'Beth', 'Cooper', DATE '2001-04-05', 60000, 1 FROM DUAL UNION ALL
SELECT 4, 'Carol', 'Orr', DATE '2001-04-06', 70000,1 FROM DUAL UNION ALL
SELECT 5, 'Vicky', 'Palazzo', DATE '2001-04-07', 88000,2 FROM DUAL UNION ALL
SELECT 6, 'Cheryl', 'Ford', DATE '2001-04-08', 110000,1 FROM DUAL UNION ALL
SELECT 7, 'Leslee', 'Altman', DATE '2001-04-10', 666666, 1 FROM DUAL UNION ALL
SELECT 8, 'Jill', 'Coralnick', DATE '2001-04-11', 190000, 2 FROM DUAL UNION ALL
SELECT 9, 'Faith', 'Aaron', DATE '2001-04-17', 122000,2 FROM DUAL;
WITH cte AS (
SELECT department_id,
first_name,
last_name,
salary,
DENSE_RANK() OVER(PARTITION BY department_id ORDER BY salary DESC) AS rnk
FROM employees
)
SELECT department_id,
/* department_name */
first_name,
last_name,
salary
FROM cte
WHERE rnk=1
You did not join the table.
WITH cte AS (
SELECT department_id,
first_name,
last_name,
salary,
DENSE_RANK() OVER(PARTITION BY department_id ORDER BY salary DESC) AS rnk
FROM employees
)
SELECT e.department_id,
d.department_name,
e.first_name,
e.last_name,
e.salary
FROM cte e
INNER JOIN departments d
ON (d.department_id = e.department_id)
WHERE rnk=1
or:
WITH cte AS (
SELECT e.department_id,
d.department_name,
e.first_name,
e.last_name,
e.salary,
DENSE_RANK() OVER(PARTITION BY e.department_id ORDER BY e.salary DESC) AS rnk
FROM employees e
INNER JOIN departments d
ON (d.department_id = e.department_id)
)
SELECT department_id,
department_name,
first_name,
last_name,
salary
FROM cte
WHERE rnk=1
or using a sub-query, instead of the sub-query factoring clause:
SELECT e.department_id,
d.department_name,
e.first_name,
e.last_name,
e.salary
FROM (
SELECT department_id,
first_name,
last_name,
salary,
DENSE_RANK() OVER(PARTITION BY department_id ORDER BY salary DESC) AS rnk
FROM employees
) e
INNER JOIN departments d
ON (d.department_id = e.department_id)
WHERE rnk=1
or:
SELECT department_id,
department_name,
first_name,
last_name,
salary
FROM (
SELECT e.department_id,
d.department_name,
e.first_name,
e.last_name,
e.salary,
DENSE_RANK() OVER(PARTITION BY e.department_id ORDER BY e.salary DESC) AS rnk
FROM employees e
INNER JOIN departments d
ON (d.department_id = e.department_id)
)
WHERE rnk=1
fiddle

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).

Group by a subquery in Oracle

Say I have a query such as the following:
SELECT
EmployeeName,
DepNo,
sum(wages)
FROM
Employees
GROUP BY
EmployeeName,
DepNo
Then I have some data in another table called Departments such as:
DepNo DepName
1 Accountants
2 HR
3 IT
How could I swap the Employee.DepNo to be the Department.DepName?
I tried adding a nested select but I ran into an issue when grouping:
SELECT
EmployeeName,
(SELECT DISTINCT DepName FROM Departments WHERE Employees.DepNo = Departments.DepNo) AS DepName,
sum(wages)
FROM
Employees
GROUP BY
EmployeeName,
DepName
Don't use a subquery, just JOIN to the other table and then return the column in the SELECT:
SELECT E.EmployeeName,
D.DepName,
SUM(Wages) AS Wages
FROM Employees E
JOIN Departments D ON E.DepNo = D.DepNo
GROUP BY E.EmployeeName,
D.DepName
Since you are asking for another answer, You may update your query to -
SELECT
EmployeeName,
(SELECT DISTINCT DepName
FROM Departments
WHERE Employees.DepNo = Departments.DepNo) AS DepName,
sum(wages)
FROM
Employees
GROUP BY
EmployeeName,
Employees.DepNo

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

Oracle PL/SQL group by issue

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

Resources