Update data of master tbl based on child tbl data - sql-server

I have two table tblEMP and tblChild.
In tblEMP, I have two column Empid and salary and in tblEMP salary value is currently null.
In tblChild, I have three column Childid, Empid and salary. whrere empid is from tblEMP.
I have datas as shown in below image.
Now I want to update Salary of tblEMP from salary of tblChild with matched EMPID.
For Example tblEMP : EMPID 1's salary would be : 2500 (tblChild ChildId 3) and
EMPID 2's salary would be : 500 (tblChild ChildId 4) and
EMPID 3's salary would be : 4000 (tblChild ChildId 6).
Thanks

Try this:
;with cte as
(select empid,max(childid) maxid
from child
group by empid)
update emp
set salary = c.salary
from
emp e
inner join cte t on e.empid = t.empid
inner join child c on t.maxid = c.childid
Basically, you get the maximum ChildID for each EmpID and then do 2 joins - first between Emp and the CTE based on EmpId and then between the CTE and Child on the ChildID, to get the desired records from the Child table.

Or you can use:
;with cte
as
(
select childid, empid, salary,
row_number() over(partition by empid order by empid, childid desc) rno
from child
)
update emp
set salary = cte.salary
from cte
where cte.empid = temp.empid
and cte.rno = 1
doing row numbering based on empid and updating employee table accodtingly

Related

Top 5 Employees from each dept with lowest attendance

How do I find top 5 employees from each department with lowest attendance?
---Employee Table
--- Department Table
--- Attendance Table
I tried in this way to find top 5 salary from each department but how to apply in this specially for attendance table with employee and department table how to find top 5 employees with lowest attendance please assist me in this regard with cte.
Thanks
With ctetemp As
(
Select E.EmpId, E.Ename, E.Salary,D.Dname,
DENSE_RANK() OVER(PARTITION BY D.DeptId ORDER BY Salary desc) as rnw
from EmployeeTbl AS E JOIN Departmet AS D
ON D.DeptId = e.Dept_Id_Emp
)
Select * from ctetemp
where rnw IN (5)
You will need to reference the attendance table.
I'm assuming 'a' means 'absent' in this context.
SELECT
AbsenceSummary.DeptID
,AbsenceSummary.EmpId
,AbsenceSummary.AbsentDays
,AbsenceSummary.AbsentRank
FROM
(
SELECT
dept.DeptId
,att.EmpId
,COUNT(*) AS AbsentDays
,DENSE_RANK() OVER (PARTITION BY dept.DeptId ORDER BY COUNT(*) DESC) AS AbsentRank
FROM
attendance att
INNER JOIN
employee emp
ON emp.EmpID = att.EmpId
INNER JOIN
department dept
ON dpt.DeptId = emp.DeptId
WHERE
dept.DeptId IN (<the departments you care about>)
AND att.atdate >= <your minimum date>
AND att.atdate <= <your maximum date>
AND att.attendance = 'a' --absent
GROUP BY
dept.DeptId
,att.EmpId
) AbsenceSummary
WHERE
AbsenceSummary.AbsentRank <= 5
For the record, the AtId column in this situation is useless and possibly counterproductive. The key is (EmpId,atDate).

How to test against a list of items in an if statement

I have a large table (130 columns). It is a monthly dataset that is separated by month (jan,feb,mar,...). every month I get a small set of duplicate rows. I would like to remove one of the rows, it does not matter which row to be deleted.
This query seems to work ok when I only select the ID that I want to filter the dups on, but when I select everything "*" from the table I end up with all of the rows, dups included. My goal is to filter out the dups and insert the result set into a new table.
SELECT DISTINCT a.[ID]
FROM MonthlyLoan a
JOIN (SELECT COUNT(*) as Count, b.[ID]
FROM MonthlyLoan b
GROUP BY b.[ID])
AS b ON a.[ID] = b.[ID]
WHERE b.Count > 1
and effectiveDate = '01/31/2017'
Any help will be appreciated.
This will show you all duplicates per ID:
;WITH Duplicates AS
(
SELECT ID
rn = ROW_NUMBER() OVER (PARTITION BY ID ORDER BY ID)
FROM MonthlyLoan
)
SELECT ID,
rn
FROM Duplicates
WHERE rn > 1
Alternatively, you can set rn = 2 to find the immediate duplicate per ID.
Since your ID is dupped (A DUPPED ID!!!!)
all you need it to use the HAVING clause in your aggregate.
See the below example.
declare #tableA as table
(
ID int not null
)
insert into #tableA
values
(1),(2),(2),(3),(3),(3),(4),(5)
select ID, COUNT(*) as [Count]
from #tableA
group by ID
having COUNT(*) > 1
Result:
ID Count
----------- -----------
2 2
3 3
To insert the result into a #Temporary Table:
select ID, COUNT(*) as [Count]
into #temp
from #tableA
group by ID
having COUNT(*) > 1
select * from #temp

T-Sql query for the situation - Need a departmentID with max number of employees?

let's say employee table has employee details and deptId of the employee.
to get the number of employees in each deptid,
select deptId, COUNT(*) from employee group by deptId;
question is: to get the deptId having max number of employees of the above result set,
select Top 1 deptId, COUNT(*) from employee group by deptId order by 2 desc
(2-ref to second column in the query list) - will do.. but
Is there anyway to avoid ordering this set? or better way of writing this sql,
thanks
If you just want the MAX number of employees within a department, you can do this:
SELECT TOP 1 DepartmentID,
COUNT(EmployeeID)
FROM EmployeeTable
GROUP BY DepartmentID
ORDER BY COUNT(EmployeeID) DESC
Without any ordering, it is hard, but try
Select deptId, cnt
From (Select deptId, count(*) cnt
from employee
Group By deptId) Z
Where cnt = (Select Max(cnt)
From (Select deptId, count(*) cnt
From employee
Group By deptId) ZZ)

How to retrieve name of employee having salary greater than the average salary of their respective department

I have a table named "tblEmployee". Columns in this table are "EmpId","Department","Salary".
Rows in this table are as follows(e1,sales,10000),(e2,hr,20000),(e3,sales,30000),(e4,production,40000),(e5,hr,50000).
I want to retrieve name of the employee whose salary is greater than the average salary of their respective department.I want solution for sql server.
Thanks in advance.
select emp.EmpId, emp.Department
from tblEmployee emp
where emp.Salary > ( select
avg(emp2.Salary)
from tblEmployee emp2
where emp2.Department = emp.Department
)
Avoiding an aggregate by using an the OVER clause to generate in-line AVG
;WITH cte as
(
select
EmpId, Department, Salary,
AVG(Salary) OVER (PARTITION BY Department) AS DeptAvgSal
FROM
tblEmployee
)
SELECT
EmpId, Department, Salary
FROM
cte
WHERE
Salary > DeptAvgSal
This works for me:
select e.eid,e.did,e.ename,e.sal,t.avg_sal dpt_avg_sal from emp e inner join
(select emp.did, AVG(sal) avg_sal from emp inner join dpt on emp.did = dpt.did
group by emp.did) t
on e.did = t.did where e.sal > avg_sal
Where #department is the passed-in parameter denoting which department...
select * from tblEmployee where Salary >
(select AVG(Salary) from tblEmployee where Department = #department)
and Department = #department
order by salary desc

select top 1 with a group by

I have two columns:
namecode name
050125 chris
050125 tof
050125 tof
050130 chris
050131 tof
I want to group by namecode, and return only the name with the most number of occurrences. In this instance, the result would be
050125 tof
050130 chris
050131 tof
This is with SQL Server 2000
I usually use ROW_NUMBER() to achieve this. Not sure how it performs against various data sets, but we haven't had any performance issues as a result of using ROW_NUMBER.
The PARTITION BY clause specifies which value to "group" the row numbers by, and the ORDER BY clause specifies how the records within each "group" should be sorted. So partition the data set by NameCode, and get all records with a Row Number of 1 (that is, the first record in each partition, ordered by the ORDER BY clause).
SELECT
i.NameCode,
i.Name
FROM
(
SELECT
RowNumber = ROW_NUMBER() OVER (PARTITION BY t.NameCode ORDER BY t.Name),
t.NameCode,
t.Name
FROM
MyTable t
) i
WHERE
i.RowNumber = 1;
select distinct namecode
, (
select top 1 name from
(
select namecode, name, count(*)
from myTable i
where i.namecode = o.namecode
group by namecode, name
order by count(*) desc
) x
) as name
from myTable o
SELECT max_table.namecode, count_table2.name
FROM
(SELECT namecode, MAX(count_name) AS max_count
FROM
(SELECT namecode, name, COUNT(name) AS count_name
FROM mytable
GROUP BY namecode, name) AS count_table1
GROUP BY namecode) AS max_table
INNER JOIN
(SELECT namecode, COUNT(name) AS count_name, name
FROM mytable
GROUP BY namecode, name) count_table2
ON max_table.namecode = count_table2.namecode AND
count_table2.count_name = max_table.max_count
I did not try but this should work,
select top 1 t2.* from (
select namecode, count(*) count from temp
group by namecode) t1 join temp t2 on t1.namecode = t2.namecode
order by t1.count desc
Here are to examples that you could use but the temp table use is more efficient than the view, but was done on a small data sample. You would want to check your own statistics.
--Creating A View
GO
CREATE VIEW StateStoreSales AS
SELECT t.state,t.stor_id,t.stor_name,SUM(s.qty) 'TotalSales'
,ROW_NUMBER() OVER (PARTITION BY t.state ORDER BY SUM(s.qty) DESC) AS 'Rank'
FROM [dbo].[sales] s
JOIN [dbo].[stores] t ON (s.stor_id = t.stor_id)
GROUP BY t.state,t.stor_id,t.stor_name
GO
SELECT * FROM StateStoreSales
WHERE Rank <= 1
ORDER BY TotalSales Desc
DROP VIEW StateStoreSales
---Using a Temp Table
SELECT t.state,t.stor_id,t.stor_name,SUM(s.qty) 'TotalSales'
,ROW_NUMBER() OVER (PARTITION BY t.state ORDER BY SUM(s.qty) DESC) AS 'Rank' INTO #TEMP
FROM [dbo].[sales] s
JOIN [dbo].[stores] t ON (s.stor_id = t.stor_id)
GROUP BY t.state,t.stor_id,t.stor_name
SELECT * FROM #TEMP
WHERE Rank <= 1
ORDER BY TotalSales Desc
DROP TABLE #TEMP

Resources