Group By on same column in subquery - sql

I have a sql table called Employee in which I have EmployeeID, Status and DepartmentID columns. Now I have been assigned with the task of creating a tabular report where in I need count of total employees for a department, count of Employees which are active(Status), and DepartmentID.
Getting the Count of total employees and corresponding DepartmentID is simple with a Group By clause.
Select count(*) as 'Total Employees',DepartmentID from Employees
Group By DepartmentID
How would I get the Count of Employees with a particular Status for the same DepartmentID as the outer query?
Please let me know if you want some more clarifications about the problem.

If you have column Status with values active , no need of outer query
Select count(*) as 'Total Employees',
SUM(CASE WHEN status='Active' THEN 1 ELSE 0 END ) as TotalActiveEmployees,
DepartmentID
from Employees
Group By DepartmentID

Try this one.
Select count(*) as 'Total Employees',
COUNT(CASE WHEN status='Active' THEN 1 ELSE 0 END ) as TotalActiveEmployees,
DepartmentID
from Employees
Group By DepartmentID

Related

DB2 SQL : How to get 2 rows data into 1

I am getting employee data from source which gives me 2 rows for same employee. 1st row has a salary and 2nd has commission. to identify if it is salary or commission I have got one Flag column.
Now I want to store it in single row in my target table, where I would have salary and commision as columns.
try a chance maybe work
select employee_id,sum(salary)salary,sum(commission) from
(select employee_id,0 as salary,commission from tblname where flag=1
union all
select employee_id ,salary ,0 commission from tblname where flag=0
)a
group by employee_id
Use conditional aggregation
select employee_id,max(case when flag=0 then salary end) as salary,
max(case when flag=1 then commission end) as commission
from tablename
group by employee_id

SQL Server Group Records Based Another Columns

I am working on a table that contains employee data. The table has historical employee records based on department and year as follows:
Now I want to consolidate records based on EmployeeId, Department and get the Min FromYear and Max ToYear like this:
I tried to use a query :
Select EmployeeId, Department, MIN(FromYear), MAX(ToYear)
from Employee
GROUP BY EmployeeId, Department
But this query fails for the employee with ID 3 as it returns me only 2 rows:
I have added a similar structure and query here: http://sqlfiddle.com/#!9/6f1e53/5
Any help would be highly appreciated!
This is a gaps-and-islands problem. Identify the islands using lag() and a cumulative sum. Then aggregate:
select employeeid, department, min(fromyear), max(toyear)
from (select e.*,
sum(case when prev_toyear >= fromyear - 1 then 0 else 1 end) over (partition by employeeid order by fromyear) as grp
from (select e.*,
lag(toyear) over (partition by employeeid, department order by fromyear) as prev_toyear
from employee e
) e
) e
group by employeeid, department, grp
order by employeeid, min(fromyear);
Here is a db<>fiddle.
you can use self join as well
select a.employeeid, min(a.fromyear), max(b.toyear) from emp a
inner join emp b on a.employeeid=b.employeeid
group by a.employeeid

SSMS Count with HAVING - SQL

I'm trying to count the number of Departments in a database where there are exaclty 6 employees in each Department.
I've written the query below, but it returns the rows with the Departments where there are 6 employees.
But what I'd like is the TOTAL NUMBER of ROWS where each Department has 6 employees.
Does anyone know how I can modify this query to give me a total number, please?
TIA
select count(Department)
--Department as [Department Name]
from HumanResources.vEmployeeDepartment
GROUP BY Department
HAVING count(Department) = 6
You can wrap your query with another count statement to count the number of departments returned by the inner query:
select COUNT(*) from
(
select Department as cnt
from HumanResources.vEmployeeDepartment
GROUP BY Department
HAVING count(Department) = 6
) as t

Find if Employee is a manager

I have 2 tables employee and employeeManager.
Employee table has 3 columns:
employeeId (pk), firstname, lastname
EmployeeManager table has 5 columns:
employeemanagerid (PK),
employeeid (FK references employee > employeeid),
managerid (FK references employee > employee id),
effectivestartdate,
effectiveenddate
I need to display records as
Employeeid, firstname, lastname, isManager
The IsManager column can have 2 values: Y for yes and N for no.
I need to find the status as of today. I.E. On the day query is run.
Any help?
Presumably, you have a rule that says that a manager has people reporting to him or her. That is not the case in the real world, but it is necessary for answering your question.
You basically want an exists clause to see if anyone exists who is reporting to the manager. That looks like:
select e.*,
(case when exists (select 1
from employeemanager m
where m.managerid = e.employeeid and
m.effectivestartdate <= getdate() and
m.effectiveenddate > getdate()
)
then 'Y' else 'N'
end) as isManager
from employee e;
This subquery:
select distinct managerid
from employeemanager
where convert(date, getdate()) between effectivestartdate and effectiveenddate
returns all the managers.
Left join the table employee to that subquery and with a CASE expression get the results you need:
select e.*,
case when t.managerid is null then 'N' else 'Y' end isManager
from employee e left join (
select distinct managerid
from employeemanager
where convert(date, getdate()) between effectivestartdate and effectiveenddate
) t on t.managerid = e.employeeid

Which of both ways for solving this exercise is more efficient?

So, this is the exercise:
Make a query that displays the number of presidents (job_id AD_PRES), the total salary sum of the presidents, the number of administration vice presidents (job_id AD_VP), and the total salary sum of those vice presidents.
The way it was shown to me:
Select count(decode(job_id,'AD_PRES',1,0)) AS NumOfPres,
Sum(decode(job_id,'AD_PRES',salary,0) AS SumSalaryP,
count(decode(job_id,'AD_VP',1,0)) AS NumOfPres,
Sum(decode(job_id,'AD_VP',salary,0) AS SumSalaryVP
FROM EMPLOYEES;
This is what I did:
Select count (e.job_id),sum(e.salary),count(m.job_id),sum(m.salary)
FROM employees e join employees m on(e.job_id=m.job_id)
Where e.job_id='AD_PRES'
AND m.job_id='AD_VP';
So, join is more readable I would say but is there any other performance difference?
Your join is forcing the relationship between the employees. If there is no such relationship then all results would return 0.
Also you are linking all employees that are president with all employees that are vice-president. So if you have 3 presidents and 10 vicepresidents, the join will result in 30 rows and the sum will be repeated to calculate the total, something that would never happen in the first query.
The exercise didn't specify return a single row, so the simple way is:
Select
job_id,
count(*),
sum(salary)
FROM EMPLOYEES
where job_id in ('AD_PRES', 'AD_VP')
group by job_id
The 1st Select uses legacy syntax and will not return a correct result as count(decode(job_id,'AD_PRES',1,0)) is the same as count(*).
And it's reading all rows, there should be a WHERE:
Select
sum(case when job_id = 'AD_PRES' then 1 else 0 end) AS NumOfPres,
Sum(case when job_id = 'AD_PRES' then salary else 0 end) AS SumSalaryP,
sum(case when job_id = 'AD_VP' then 1 else 0 end) AS AS NumOfVPs,
Sum(case when job_id = 'AD_PRES' then salary else 0 end) AS SumSalaryVP
FROM EMPLOYEES
where job_id in ('AD_PRES', 'AD_VP');
Your 2nd Select doesn't work at all. You join on matching job_ids, but one is 'AD_PRES' and the other 'AD_VP', so no match.
When you want to join it would be a CROSS JOIN:
Select *
from
( Select
count(*) AS NumOfPres,
sum(salary) AS SumSalaryP
FROM EMPLOYEES
where job_id ='AD_PRES'
)
cross join
( Select
count(*) AS NumOfVPs,
sum(salary) AS SumSalaryVP
FROM EMPLOYEES
where job_id ='AD_VP'
)