Getting missing keyword error in running code on oracle - sql

I have 2 tables, one table storing details of staff (columns are staff_id, staff_name, department_id) and another table storing details of department (columns are department_id, department_name, department_block_num).
I need to write a query to display names of department and staff count in each department, if staff not exist display count as 0.
Here is code
Select department_name,
case department.department_id
when department.department_id=staff.department_id then count(staff_name)
else 0 end staff_count
From department, staff
Group by department_name
order by department_name;

You are looking for a LEFT JOIN and an aggregation query:
select d.department_id, d.department_name,
count(s.department_id) as staff_count
from department d left join
staff s
on d.department_id = s.department_id
group by d.department_id, d.department_name

Related

Sql subquery with a group by and a join on two tables

So i have two tables
EMPLOYEE- Contains columns including EMPLOYEE_NAME, DEPARTMENT_ID and SALARY
DEPARTMENTS - Contains columns including DEPARTMENT_NAME, and DEPARTMENT_ID
I need to display the department name and the average slary for each department and order it by the average salaries.
I am new to DBs and am having trouble.
I try to do a subquery in the from field ( this subquery returns exactly what i need minus the department name which requires me to then join the departments table to the results) all the data in the subquery is in one table- employees. while department name is in the departments table.
here is what i tried.
SELECT D.DEPARTMENT_NAME, T.PERDEPT
FROM
(
SELECT DEPARTMENT_ID, AVG(SALARY) AS PERDEPT
FROM EMPLOYEE
GROUP BY DEPARTMENT_ID
ORDER BY PERDEPT
) AS TEST T
JOIN DEPARTMENTS
ON D.DEPARTMENT_ID=T.DEPARTMENT_ID;
This returns a
SQL command not properly terminated
on the line with the AS TEST T
any and all help is greatly appreciated
many thanks
This query should do what you ask:
select d.department_name, avg(e.salary) as avg_salary
from salary_department d
left join employee e on e.department_id = d.department_id
group by d.department_name
order by avg(e.salary)
Simply correct your table aliases as you seem to have two aliases for subquery (TEST and T) and no assignment for D. Adjust SQL with one alias for each table/query reference:
...
(
SELECT ...
) AS T
JOIN DEPARTMENTS D
With that said, you do not even need the subquery as aggregate query with JOIN should suffice, assuming DEPARTMENT_ID is unique in DEPARTMENTS table to not double count the aggregate.
SELECT D.DEPARTMENT_NAME,
AVG(E.SALARY) AS PERDEPT
FROM EMPLOYEE E
JOIN DEPARTMENTS D
ON E.DEPARTMENT_ID = D.DEPARTMENT_ID
GROUP BY E.DEPARTMENT_ID,
D.DEPARTMENT_NAME
ORDER BY AVG(SALARY)

Simple SQL query not working out

click here for database model
Asked: Show for every department with at least 3 employees, the department's name and the amount of employees in that department born before 1967.
My code so far:
`Select department, department_name, numberofemployeesbefore1967 = ( select count(empleyee_id) from employee where year(dateofbirth) < 1967)
From employee inner join department on (department = department_id)
group by department, department_name
having count(*) >=3`
The output I have now: output
I feel like this is a really easy one, but I cannot find how to show only the employees born before 1967 for that specific department.
Anyone to help me out?
I check the year in the main query and >=3 in a subquery
SELECT department department_name, count(*)
FROM department d
JOIN employee e on d.department_id = e.department
WHERE YEAR(dateOfBirth) < 1967
AND (SELECT COUNT(*) FROM employee WHERE department = d.department_id) >= 3
GROUP BY d.id, d.name
Tweaked the subquery like so...
Select department, department_name, (select count(empleyee_id) from employee where year(dateofbirth) < 1967) AS numberofemployeesbefore1967
From employee inner join department on (department = department_id)
group by department, department_name
having count(*) >=3

SQL: Unable to SELECT joined column

I've written an SQL statement to display the department_id, job_id and of employees with the lowest salary, but one of the conditions required me to exclude departments with the names 'IT' and 'SALES', which were only accessible from another table departments. As such I joined the two tables using the shared column department_id and managed to filter the results as needed however, I am unable to select the department_id to display alongside the job_id and salaries. This is what I've managed so far:
SELECT EMPLOYEES.DEPARTMENT_ID JOB_ID, MIN(SALARY)
FROM EMPLOYEES JOIN DEPARTMENTS
ON DEPARTMENTS.DEPARTMENT_ID = EMPLOYEES.DEPARTMENT_ID
WHERE JOB_ID NOT LIKE '%REP'
AND DEPARTMENTS.DEPARTMENT_NAME NOT IN ('IT','SALES')
GROUP BY EMPLOYEES.DEPARTMENT_ID
HAVING MIN(SALARY) >= 6000 AND MIN(SALARY) <= 18000;
First, table aliases make the query much easier to write and read:
SELECT e.DEPARTMENT_ID, e.JOB_ID, MIN(e.SALARY)
FROM EMPLOYEES e JOIN
DEPARTMENTS d
ON d.DEPARTMENT_ID = e.DEPARTMENT_ID
WHERE e.JOB_ID NOT LIKE '%REP' AND d.DEPARTMENT_NAME NOT IN ('IT',' SALES')
GROUP BY e.DEPARTMENT_ID, e.JOB_ID
HAVING MIN(e.SALARY) >= 6000 AND MIN(e.SALARY) <= 18000;
You need all non-aggregated columns in the GROUP BY.
Comma is missing in your query after department id in SELECT - so it considers Job ID as Alias for department ID and displayed as Job ID in query result. But again you don't have Job ID in GROUP BY Clause and need to add that in group by or have to use any aggregate function
SELECT **EMPLOYEES.DEPARTMENT_ID, JOB_ID,** MIN(SALARY)
FROM EMPLOYEES JOIN DEPARTMENTS ON DEPARTMENTS.DEPARTMENT_ID=EMPLOYEES.DEPARTMENT_ID
WHERE JOB_ID NOT LIKE '%REP' AND DEPARTMENTS.DEPARTMENT_NAME NOT IN('IT','SALES')
GROUP BY EMPLOYEES.DEPARTMENT_ID,JOB_ID
HAVING MIN(SALARY) >= 6000 AND MIN(SALARY) <= 18000;

Employees with largest salary in department

I found a couple of SQL tasks on Hacker News today, however I am stuck on solving the second task in Postgres, which I'll describe here:
You have the following, simple table structure:
List the employees who have the biggest salary in their respective departments.
I set up an SQL Fiddle here for you to play with. It should return Terry Robinson, Laura White. Along with their names it should have their salary and department name.
Furthermore, I'd be curious to know of a query which would return Terry Robinsons (maximum salary from the Sales department) and Laura White (maximum salary in the Marketing department) and an empty row for the IT department, with null as the employee; explicitly stating that there are no employees (thus nobody with the highest salary) in that department.
Return one employee with the highest salary per dept.
Use DISTINCT ON for a much simpler and faster query that does all you are asking for:
SELECT DISTINCT ON (d.id)
d.id AS department_id, d.name AS department
,e.id AS employee_id, e.name AS employee, e.salary
FROM departments d
LEFT JOIN employees e ON e.department_id = d.id
ORDER BY d.id, e.salary DESC;
->SQLfiddle (for Postgres).
Also note the LEFT [OUTER] JOIN that keeps departments with no employees in the result.
This picks only one employee per department. If there are multiple sharing the highest salary, you can add more ORDER BY items to pick one in particular. Else, an arbitrary one is picked from peers.
If there are no employees, the department is still listed, with NULL values for employee columns.
You can simply add any columns you need in the SELECT list.
Find a detailed explanation, links and a benchmark for the technique in this related answer:
Select first row in each GROUP BY group?
Aside: It is an anti-pattern to use non-descriptive column names like name or id. Should be employee_id, employee etc.
Return all employees with the highest salary per dept.
Use the window function rank() (like #Scotch already posted, just simpler and faster):
SELECT d.name AS department, e.employee, e.salary
FROM departments d
LEFT JOIN (
SELECT name AS employee, salary, department_id
,rank() OVER (PARTITION BY department_id ORDER BY salary DESC) AS rnk
FROM employees e
) e ON e.department_id = d.department_id AND e.rnk = 1;
Same result as with the above query with your example (which has no ties), just a bit slower.
This is with reference to your fiddle:
SELECT * -- or whatever is your columns list.
FROM employees e JOIN departments d ON e.Department_ID = d.id
WHERE (e.Department_ID, e.Salary) IN (SELECT Department_ID, MAX(Salary)
FROM employees
GROUP BY Department_ID)
EDIT :
As mentioned in a comment below, if you want to see the IT department also, with all NULL for the employee records, you can use the RIGHT JOIN and put the filter condition in the joining clause itself as follows:
SELECT e.name, e.salary, d.name -- or whatever is your columns list.
FROM employees e RIGHT JOIN departments d ON e.Department_ID = d.id
AND (e.Department_ID, e.Salary) IN (SELECT Department_ID, MAX(Salary)
FROM employees
GROUP BY Department_ID)
This is basically what you want. Rank() Over
SELECT ename ,
departments.name
FROM ( SELECT ename ,
dname
FROM ( SELECT employees.name as ename ,
departments.name as dname ,
rank() over (
PARTITION BY employees.department_id
ORDER BY employees.salary DESC
)
FROM Employees
JOIN Departments on employees.department_id = departments.id
) t
WHERE rank = 1
) s
RIGHT JOIN departments on s.dname = departments.name
Good old classic sql:
select e1.name, e1.salary, e1.department_id
from employees e1
where e1.salary=
(select maxsalary=max(e.salary) --, e. department_id
from employees e
where e.department_id = e1.department_id
group by e.department_id
)
Table1 is emp - empno, ename, sal, deptno
Table2 is dept - deptno, dname.
Query could be (includes ties & runs on 11.2g):
select e1.empno, e1.ename, e1.sal, e1.deptno as department
from emp e1
where e1.sal in
(SELECT max(sal) from emp e, dept d where e.deptno = d.deptno group by d.dname)
order by e1.deptno asc;
SELECT
e.first_name, d.department_name, e.salary
FROM
employees e
JOIN
departments d
ON
(e.department_id = d.department_id)
WHERE
e.first_name
IN
(SELECT TOP 2
first_name
FROM
employees
WHERE
department_id = d.department_id);
`select d.Name, e.Name, e.Salary from Employees e, Departments d,
(select DepartmentId as DeptId, max(Salary) as Salary
from Employees e
group by DepartmentId) m
where m.Salary = e.Salary
and m.DeptId = e.DepartmentId
and e.DepartmentId = d.DepartmentId`
The max salary of each department is computed in inner query using GROUP BY. And then select employees who satisfy those constraints.
Assuming Postgres
Return highest salary with employee details, assuming table name emp having employees department with dept_id
select e1.* from emp e1 inner join (select max(sal) avg_sal,dept_id from emp group by dept_id) as e2 on e1.dept_id=e2.dept_id and e1.sal=e2.avg_sal
Returns one or more people for each department with the highest salary:
SELECT result.Name Department, Employee2.Name Employee, result.salary Salary
FROM ( SELECT dept.name, dept.department_id, max(Employee1.salary) salary
FROM Departments dept
JOIN Employees Employee1 ON Employee1.department_id = dept.department_id
GROUP BY dept.name, dept.department_id ) result
JOIN Employees Employee2 ON Employee2.department_id = result.department_id
WHERE Employee2.salary = result.salary
SQL query:
select d.name,e.name,e.salary
from employees e, depts d
where e.dept_id = d.id
and (d.id,e.salary) in
(select dept_id,max(salary) from employees group by dept_id);
Take look at this solution
SELECT
MAX(E.SALARY),
E.NAME,
D.NAME as Department
FROM employees E
INNER JOIN DEPARTMENTS D ON D.ID = E.DEPARTMENT_ID
GROUP BY D.NAME

How do I structure this SQL SELECT query?

I have two tables and I need to make a certain select.
First table is Employe that has colums Name *Departament_ID* and Salary
The second table is Departament that has colums Departament ID and *Departament_Name*
My SQL script has to get me the name of the departament, the maximum salay and minimum salary where Departament_ID is '30'
Something like this should do the trick (note: all spellings are exactly as you gave in your first post).
SELECT d.Department_Name AS name,
MAX(e.salary) AS max_salary,
MIN(e.salary) AS min_salary
FROM Department d
LEFT JOIN Employe e ON d.Department_ID = e.Department_ID
WHERE d.Department_ID = 30
SELECT d.department_name,
MIN(e.salary) AS 'Minimum Salary',
MAX(e.salary) AS 'Maximum Salary'
FROM department d,employee e
WHERE d.department_id=30 AND d.department_id=e.department_id
GROUP BY d.department_name
SELECT max(sal) as MaximumSalary
,min(sal) as MinimumSalary
,department.Departament_Name
,employee.Name
FROM employee
INNER JOIN department ON
employee.departmentid = department.department_id
WHERE department.department_id = 31
GROUP BY department.department_id
max and min function will give you the maximum and minimum value of the employee table for the salary column. This will require you to use GROUP BY because they need to calculate the maximum and minimum from a group of data witch in this case is the maximum/minimum by department. We group by department id because it's a unique key of the table. The inner join is here to join the two tables you have. It's an inner join because we want to have the department into the query.
SELECT d.Department_Name AS name,
MAX(e.salary) AS max_salary,
MIN(e.salary) AS min_salary
FROM Department d
Inner JOIN Employee ON d.Department_ID = e.Department_ID
WHERE d.Department_ID = 30