How do I get a single row value in a group statement? - sql

I have two tables, JobTable and EmployeeTable with the following data:
EmployeeTable:
EmpId Salary
1 10
2 20
3 30
4 40
5 50
6 60
JobTable:
JobId EmpId
A 1
A 2
B 3
B 4
C 5
C 6
I need an SQL statement that will return the EmpId of the Employee with the minimum salary for each Job.

You could use the RANK() function like this:
WITH ranked AS (
SELECT
j.JobId,
e.EmpId,
e.Salary,
RANK() OVER (PARTITION BY j.JobId ORDER BY e.Salary) AS rnk
FROM JobTable j
INNER JOIN EmployeeTable e ON j.EmpId = e.EmpId
)
SELECT
JobId,
EmpId,
Salary,
FROM ranked
WHERE rnk = 1

Hmm, give this one a shot:
SELECT st.EmpID, min(st.salary)
FROM SalaryTable st INNER JOIN JobTable jt ON st.EmpID=jt.EmpID
WHERE jt.JobID = 'A'
GROUP BY st.EmpID

Related

Write a SQL code to select all employees with salary greater than the average department salary and also greater than $30K

salary(department_id,employee_id,salary)
DepartmentID EmployeeID Salary
1 1 $30,000.00
1 2 $25,000.00
1 3 $40,000.00
1 4 $33,000.00
2 5 $25,000.00
2 6 $50,000.00
This may work
select s1.employeeid, s1.departmentid, s1.salary
from salary as s1
inner join
(select departmentid, avg(salary) as avgsalary
from salary
group by departmentid) as s2
on s1.departmentid = s2.departmentid
where salary > avgsalary and salary > 30000
;
Try this query:
;WITH CTE AS
(
SELECT DepartmentID, AVG(salary) AverageSalary FROM Salary
GROUP BY DepartmentID
)
SELECT s.EmployeeID, s.DepartmentID, s.Salary, c.AverageSalary
FROM Salary s
INNER JOIN CTE c on c.DepartmentID = s.DepartmentID
WHERE s.salary > c.AverageSalary and s.salary > 30000
you can use following query
SELECT t1.DepartmentID,t2.EmployeeID,t2.Salary,t1.average
FROM
(SELECT DepartmentID,AVG(Cast(Salary as Float)) as average
FROM Test
GROUP BY DepartmentID) t1
JOIN Test t2 ON t1.DepartmentID = t2.DepartmentID AND t2.Salary > t1.average AND t2.Salary > 30
result : dbfiddle

Finding the highest average salary of a department using joins in SQL?

I have two tables with the below schema:
Table 1
-------
empID
empName
Table 2
-------
empID
department
salary
Assuming the tables are:
Table1:
empID|empName
1 A
2 B
3 C
4 D
5 E
6 F
7 G
8 H
9 I
10 J
Table 2:
empID|department|salary
1 X 10
2 X 10
3 X 10
4 Y 5
5 Y 5
6 Y 5
7 Y 5
8 Y 5
9 Z 3
10 Z 3
I need to find the department name with the highest average salary and display them along with the employee names.
The output I am expecting is:
empName|department|salary
A 10
B X 10
C 10
This was an interview question, and I am recreating this from memory so it might not be perfect. I am also picking up SQL after a gap of more than 2 years. Please suggest if I am missing something.
The query that I have formed is:
SELECT
table1.empName,
TOP(1) AVG(table2.salary),
table2.department
FROM
table1
INNER JOIN
table2
ON table1.empID = table2.empID
GROUP BY
table2.department
Your syntax looks like SQL Server (the "TOP 1"). In that database, I would do something like this:
SELECT TOP (1) WITH TIES t1.empName, t2.salary, t2.department
FROM table1 t1 INNER JOIN
table2 t2
ON t1.empID = t2.empID
ORDER BY AVG(t2.salary) OVER (PARTITION BY t2.department) DESC;
A more generic solution:
SELECT empName, salary, department
FROM (SELECT t.*,
DENSE_RANK() OVER (ORDER BY avg_salary) as seqnum
FROM (SELECT t1.empName, t2.salary, t2.department,
AVG(t2.salary) OVER (PARTITION BY t2.department) as avg_salary
FROM table1 t1 INNER JOIN
table2 t2
ON t1.empID = t2.empID
) t
) t
WHERE seqnum = 1;
Based on what I draw from your question, I would approach it this way.
WITH department_rank AS
(
SELECT
department,
RANK() OVER(ORDER BY avg_salary DESC) AS avg_salary_rank
FROM
(
SELECT
department,
AVG(salary) AS avg_salary
FROM
table2
GROUP BY
department
) tbl
)
SELECT
dept.department,
emp.empID,
emp.empName,
dept.salary
FROM
table2 dept
JOIN
table1 emp
ON (emp.empID = dept.empID)
JOIN
department_rank drnk
ON (drnk.department = dept.department)
AND (drnk.avg_salary_rank = 1) --Top ranked department based on average salary
OUTPUT:

Get the group which has maximum number of records in SQL Server

[ID] [Name] [Dept]
--------------------
1 Manu A
2 Anu A
3 Tanu A
4 Danu A
5 Anu B
6 Danu B
7 Danu C
8 Anu C
9 Tanu C
10 John C
11 Anu D
12 Jane D
13 Danu D
I need to get the Dept with maximum number of employees.
Here is what I tried
SELECT
ID, Name, Dept
FROM
(SELECT
*,
rn = ROW_NUMBER() OVER(PARTITION BY Dept)
FROM Emp) t
WHERE
rn = (SELECT MAX(rn) FROM t)
I need help in the WHERE clause.
You need aggregation to count the number of employees. The approach using row_number() is one approach, but with the right query:
SELECT Dept
FROM (SELECT Dept, COUNT(*) as cnt,
ROW_NUMBER() OVER (ORDER BY COUNT(*) DESC) as seqnum
FROM Emp
) e
WHERE seqnum = 1;
However, a more common approach would just use ORDER BY and TOP:
SELECT TOP (1) Dept, COUNT(*) as cnt
FROM emp
GROUP BY Dept
ORDER BY COUNT(*) DESC;
If you wanted ties, then you would use WITH TIES in the SELECT.
Selecting all departments having the same max number of employees:
;WITH c -- create a list of depts and number of emp's
AS (SELECT deptid,
Count(*) cnt
FROM emp
GROUP BY deptid)
SELECT d.*
FROM dept d
INNER JOIN c
ON d.deptid = c.deptid
WHERE c.cnt = (SELECT Max(cnt)
FROM c)
No WHERE is needed. Try using a GROUP BY
SELECT COUNT(Name) as NameCount, Dept from Table
GROUP BY Dept
ORDER BY COUNT(Name) DESC
The biggest group(s) will be at the top
Results
NameCount | Dept
4 A
4 C
3 D
2 B
Ok, now you added the table structure:
;WITH c
AS (SELECT Dept,
Count(*) cnt
FROM Emp
GROUP BY Dept)
SELECT c.*
FROM c
WHERE c.cnt = (SELECT Max(cnt)
FROM c)
I can't quite figure your table structure, but this selects the department with the most employees
SELECT * from Dept WHERE deptid = (
SELECT TOP 1 deptid FROM employees
GROUP BY deptid
ORDER BY COUNT(*) DESC
)

Inner join with one row of another table

**Table Employee**
Id Name
1 EmpName1
2 EmpName2
3 EmpName3
**Table EmpDeptHistory**
Id EmpId Dept Date
1 1 Housing 2015-03-02
2 2 Finance 2015-01-03
3 1 WareHouse 2015-05-02
4 2 Housing 2015-02-06
5 3 WareHouse 2015-02-02
6 1 Housing 2015-05-01
7 2 Finance 2015-01-02
8 2 Housing 2015-05-04
9 2 Finance 2015-05-02
10 1 WareHouse 2015-03-08
11 1 Housing 2015-02-20
I need find the recent dept with which every employee worked. Also I need to find for individual employee by passing EmpId
The following query returns only one employee and not all :(
SELECT e.id, edh.dept,edh.date
FROM Employee e
inner join (select top 1 eh.empid, eh.dept, eh.date
from EmpDeptHistory eh
order by eh.date desc) as edh
on e.id=edh.empid
yes, I understand the top 1 will give the emp id based on date, hence only one employee details is show. I am not sure how to get all the employee recent department.
select e.id,edh.dept,edh.date
from employee e
inner join EmpDeptHistory edh
on e.id = (Select eh.empid, eh.dept, eh.date
from EmpDeptHistory eh
where e.id=eh.empid
order by eh.date desc)
The above throws
The ORDER BY clause is invalid in views, inline functions, derived
tables, subqueries, and common table expressions, unless TOP,
OFFSET or FOR XML is also specified.
You can use CROSS APPLY to run the right-hand subquery once for each left-hand row:
SELECT e.id, edh.dept,edh.date
FROM Employee e cross apply ( select top 1 eh.empid, eh.dept, eh.date from
EmpDeptHistory eh where eh.empid = e.id order by eh.date desc) as edh
You can use a CTE and a ranking function like ROW_NUMBER:
WITH CTE AS
(
SELECT e.id, edh.dept, edh.date,
rn = ROW_NUMBER() OVER (PARTITION BY edh.EmpId ORDER BY edh.date DESC)
FROM Employee e inner join EmpDeptHistory edh
on e.id = edh.empid
)
SELECT id, dept, date
FROM CTE
WHERE rn = 1
DEMO
For the latest department for each employee, you can do it like so:
SELECT t1.*
FROM EmpDeptHistory t1 INNER JOIN
(
SELECT EmpId, MAX(Date) [Date]
FROM EmpDeptHistory
GROUP BY EmpId
) AS t2
ON t1.EmpId = t2.EmpId AND t1.Date = t2.Date
EmpId can be put into a where clause if needed.

SQL - GROUP BY and COUNT

I have a table with Column - D and E.
I want to get D, Distinct E in each D, Count of total number of entry for each D. How to write SQL for this ?
Data:
D | E
-----
1 | K
1 | K
1 | A
2 | S
2 | S
2 | S
2 | S
Desired o/p:
D | E | Total_E_in_D
----------------------
1 | K | 3
1 | A | 3
2 | S | 4
SELECT D,E,Count(E in each D)
FROM table
GROUP BY D,E.
Last column should give me the total number of entries for each D.
The specific answer to the question is:
select dept, count(*) as numemployees, count(distinct emp) as numDistinctEmployees
from d1
group by dept;
This just seems quite unusual, because the it assumes that employees would be in the same department more than once.
EDIT:
Strange data format, but just use aggregation with analytic functions:
select dept, emp, sum(count(*)) over (partition by dept) as numEmployees
from d1
group by dept, emp;
You can group on the department and the employee, and join in a query where you group on the department to count the employees:
select
e.Dept,
e.Emp
d.EmpCount
from
table e
inner join (
select
Dept,
count(distinct Emp) as EmpCount
from
table
group by
Dept
) d on d.Dept = e.Dept
group by
e.Dept, e.Emp
You could also use a subquery to count the employees:
select
e.Dept,
e.Emp,
(
select
count(distinct Emp)
from
table d
where
d.Dept = e.Dept
) as EmpCount
from
table e
group by
e.Dept, e.Emp
how's this?
select dept, emp, (select count(*) from table t2 where t2.dept = t1.dept) noEmps
from table t1