How to write the SQL query for summarizing salary - sql

Q. I want a update query for updating the sum of salaries of employees departmentwise in the dept
table
DEPT table : columns :: DEPTNO DNAME LOC SUM_SAL
10 'CC' 'BLR'
20 'ADMIN' 'DEL'
30 'HR' 'CAL'
update a
set sum_sal = b.sum_sal
from dept a,
(select deptno, sum(sal) sum_sal from emp group by deptno ) b
where a.deptno = b.deptno;
But it is not working
update a
set sum_sal = b.sum_sal
from dept a,
(select deptno, sum(sal) sum_sal from emp group by deptno ) b
where a.deptno = b.deptno;
update a
set sum_sal = b.sum_sal
from dept a,
(select deptno, sum(sal) sum_sal from emp group by deptno ) b
where a.deptno = b.deptno;
from dept a,
ERROR at line 3: ORA-00933: SQL command not properly ended

Oracle doesn't support a from clause in an update.
Just use a correlated subquery:
update dept
set sum_sal = (select sum(e.sal) from emp e where e.deptno = dept.deptno);

One option would be using with..as select ... clause within an update statement :
update dept d
set d.sum_sal =
( with e as (
select *
from emp
)
select sum(e.sal)
from e
where e.deptno = d.deptno
group by e.deptno
);
Demo

You can use MERGE statement as it is a good candidate for MERGE
Try the following query:
MERGE INTO DEPT D
USING
(
SELECT
E.DEPTNO,
SUM(E.SAL) SUM_SAL
FROM
EMP E
GROUP BY
E.DEPTNO
) E
ON ( E.DEPTNO = DEPT.DEPTNO )
WHEN MATCHED THEN
UPDATE SET D.SUM_SAL = E.SUM_SAL;
Cheers!!

Related

SQL compilation error: Unsupported subquery type cannot be evaluated in snowflake DB

I am facing Unsupported Subquery error in the snowflake DB. But in the same query is working fine in the ORACLE DB.
SQL compilation error: Unsupported subquery type cannot be evaluated
Example :
SELECT A.EMPNO,A.ENAME,D.DEPTNO
FROM EMP E
LEFT OUTER JOIN DEPT D
ON E.DEPTNO = D.DEPTNO
AND D.EFFDT =
(SELECT MAX(EFFDT) FROM DEPT E WHERE E.DEPTNO = D.DEPTNO)
When I try this code into snowflake it is showing error.
It depends if you can have many equal EFFDT per DEPTNO and which point to want to use a RANK or MAX
OR if you only want the single best EFFDT per DEPTNO at which point I would use a ROW_NUMBER()
So if you want to filter at the end I would use:
SELECT
E.EMPNO,
E.ENAME,
D.DEPTNO
FROM EMP E
LEFT OUTER JOIN DEPT D
ON E.DEPTNO = D.DEPTNO
QUALIFY DENSE_RANK() OVER(PARTITION BY D.DEPTNO ORDER BY D.EFFDT DESC) = 1
OR you can filter before the join:
SELECT
e.empno,
e.ename,
d.deptno
FROM emp AS e
LEFT OUTER JOIN (
SELECT z.effdt, z.deptno
FROM dept AS z
QUALIFY DENSE_RANK() OVER(PARTITION BY z.DEPTNO ORDER BY z.EFFDT DESC) = 1
) as d
ON e.deptno = d.deptno
thus with these great fake data CTE's:
WITH emp(empno, ename, deptno) as (
select * from values
(1,'emp_1', 10),
(2,'emp_2', 20)
), dept(effdt, other, deptno) as (
select * from values
(111, 'row1', 10),
(221, 'row2', 20),
(222, 'row3', 20)
)
SELECT
e.empno,
e.ename,
d.deptno,
d.other
FROM emp AS e
LEFT OUTER JOIN (
SELECT z.effdt, z.deptno, z.other
FROM dept AS z
QUALIFY DENSE_RANK() OVER(PARTITION BY z.deptno ORDER BY z.EFFDT DESC) = 1
) as d
ON e.deptno = d.deptno
gives:
EMPNO
ENAME
DEPTNO
OTHER
1
emp_1
10
row1
2
emp_2
20
row3

Select the manager name with the most employees

We have a table emp with columns empno, ename, job, mgr, hiredate, sal, comm, deptno
I have tried
SELECT m.ename, COUNT(e.empno) FROM emp e
INNER JOIN emp m ON e.empno = m.empno
GROUP BY m.ename HAVING COUNT(e.empno) = GREATEST(COUNT(e.empno));
My output is the names of the managers each with the value 1
How do we output the name of the manager with the most employees?
The following works:
SELECT COUNT(e.empno), m.ename FROM emp e
INNER JOIN emp m ON e.mgr = m.empno
GROUP BY m.ename HAVING GREATEST(COUNT(e.ename)) = COUNT(e.ename)
LIMIT 1;
First, fix the ON clause. Second, Use ORDER BY and LIMIT if you want one row:
SELECT m.ename, COUNT(e.empno)
FROM emp e INNER JOIN
emp m
ON m.empno = e.mgr
GROUP BY m.ename
ORDER BY COUNT(e.empno) DESC
LIMIT 1;
Your HAVING clause does not filter anything because any (non-NULL) value is equal to itself.

Perform SELECT statement inside of SELECT Statement?

I'm using Emp, Dept... databases. I would like to get the Name, Salary, Deptno and Average salary in the department of those employees who earn more than the average of their department. So here is what I'm trying to do:
SELECT e.Ename, e.Sal, e.Deptno
, (
SELECT AVG(Sal)
FROM Emp b
WHERE b.Deptno = e.Deptno
GROUP BY Deptno
) AS 'Average Salary'
FROM Emp e
WHERE e.Sal > (
SELECT AVG(b.Sal)
FROM Emp b
WHERE b.Deptno = e.Deptno
GROUP BY Deptno
);
And I can't use AVG(Sal), because it will give the average salary of the employee, and not the department where he works.
You would use a correlated subquery:
SELECT e.Ename, e.Sal, e.Deptno,
(SELECT AVG(e2.Sal)
FROM Emp e2
WHERE e2.Deptno = e.Deptno
) AS [Average Salary]
FROM Emp e
WHERE e.Sal > (SELECT AVG(e2.Sal)
FROM Emp e2
WHERE e2.Deptno = e.Deptno
);
But in actuality, you would just use a window function:
select e.*
from (select e.*, avg(sal) over (partition by deptno) as avg_sal
from emp e
) e
where sal > avg_sal;
Just get rid of the group by.
SELECT e.Ename, e.Sal, e.Deptno, (SELECT AVG(Sal)
FROM Emp b
WHERE b.Deptno = e.Deptno
) AS 'Average Salary'
FROM Emp e
WHERE e.Sal > (SELECT AVG(b.Sal)
FROM Emp b
WHERE b.Deptno = e.Deptno
);
If you join to the subquery, you will not need to repeat it.
SELECT e.Ename, e.Sal, e.Deptno, dAvgs.avgSal AS 'Average Salary'
FROM Emp AS e
INNER JOIN (
SELECT Deptno, AVG(b.Sal) AS avgSal
FROM Emp b
GROUP BY Deptno
) AS dAvgs
ON e.Deptno = dAvgs.Deptno AND e.Sal > dAvgs.avgSal
;

Select departments with or without employees. Also select employees if assigned

I want to select DNAME, DEPTNO from all departments with or without employees assigned. And if a department does have any employees I want to get their ENAME, EMPNO.
I tried this: select e.empno,e.name,d.deptno,d.dname from emp e full join dept d
on e.deptno=d.deptno
But it didn't work.
Table structure:
DEPT
DEPTNO DNAME
EMP
EMPNO ENAME DEPTNO
Use OUTER JOIN(LEFT/RIGHT)
SELECT D.DEPTNO,
D.DNAME,
E.EMPNO,
E.ENAME
FROM DEPT D
LEFT OUTER JOIN EMP E
ON D.DEPTNO = E.DEPTNO
When the Department does not have any employee then NULL will be displayed in E.EMPNO and E.ENAME column
SELECT
DEPT.DEPTNO,DEPT.DNAME,EMP.EMPNO,EMP.NAME
FROM
DEPT LEFT OUTER JOIN
EMP ON DEPT.DEPTNO = EMP.DEPTNO

Display empno,ename,sal,deptno,dname,location, Display highest paid employee of every department

How to display highest paid employee of every department WITH empno,ename,sal,deptno,dname,location....
select e.empno,e.ename, max(e.Sal),d.Deptno
from DEPTNO d
inner join emp e
on d.Deptno = e.DEPTNO
group by d.DEPTNO;
Employee table:
Deptno table:
Using the row_number() analytic function makes this easy:
select e.empno,
e.ename,
e.sal,
d.deptno,
d.dname,
d.loc
from Deptno d
join (select e.*,
row_number() over (
partition by e.deptno
order by sal desc) as rn
from Employee e) e
on e.deptno = d.deptno
and e.rn = 1
In this case, the row_number() function will return a value of 1 for the highest paid employee of every department, so that's why the join condition includes e.rn = 1 to limit the results to those employees.
Try this :
select empno,ename,deptno,sal from
(
select e.empno,e.ename,d.Deptno,sal,max(sal) over (partition by d.deptno order by null) max_sal from Employee e,Deptno d where e.deptno = d.deptno
)where sal=max_sal
here max_sal return max salary with partition by department