Consider i have 2 employers(Google,Yahoo) and google is having 3 employee's and yahoo is 2 employee
My query should add
1000 to employee1 for google company
2000 to employee2 for google company
3000 to employee3 for google company
1000 to employee1 for Yahoo company
2000 to employee2 for Yahoo company
For each set of employees it should adding salary starting from 1000
You can use ROW_NUMBER() to calculate the new Salary:
SELECT Company,
Emp,
ROW_NUMBER() OVER(PARTITION BY Company ORDER BY Emp) * 1000 + Salary As NewSalary
FROM YourTable
If you want to actually update the salary, one way is to use that query as a CTE:
;WITH CTE AS (
SELECT Company,
Emp,
ROW_NUMBER() OVER(PARTITION BY Company ORDER BY Emp) * 1000 + Salary As NewSalary
FROM YourTable
)
UPDATE T
SET Salary = NewSalary
FROM YourTable T
INNER JOIN CTE C ON(T.Company = C.Company AND T.Emp = C.Emp)
Related
I have a table that Tracks Employees and the days they have spent in a policy. I don't generate this Data, it is dumped to our Server Daily.
The table looks like this:
My Goal is to get rid of the duplicates by keeping only the most recent Date.
In this example, if I run the query, I would like it to keep Rows 11 for Nicholas Morris and 14 for Tiana Sullivan.
Assumption: First name and Last Name combo are unique
So far,
This is what I have been doing:
select *
from
Employees IN(
Select ID
from Employees
group by FirstName, lastName
Having count(*) > 1)
This returns to me the rows that have duplicates and I have to manually search them and remove the ones I don't want to keep.
I am sure there is a better way of doing this
Thanks for your help
You can use a CTE and ROW_NUMBER() function to do it.
The query to get the data is:
SELECT ID, FirstName, LastName, ROW_NUMBER()
OVER (PARTITION BY FirstName, LastName ORDER BY DaysInPolicy DESC) AS Identifier
FROM
Employees
The query to remove duplicates is:
;WITH CTE AS (
SELECT ID, ROW_NUMBER()
OVER (PARTITION BY FirstName, LastName ORDER BY DaysInPolicy DESC) AS Identifier
FROM
Employees
)
DELETE E
FROM
Employees E
INNER JOIN CTE C ON C.ID = E.ID
WHERE
C.Identifier > 1
You could delete using an exists operator where you remove any row that has the same first and last name, but with a newer date:
DELETE FROM employees e1
WHERE EXISTS (SELECT *
FROM employees e2
WHERE e1.FirstName = e2.FirstName AND
e1.LastName = e2.LastName AND
e1.DaysInPolicy < e2.DaysInPolicy)
Try this:
SELECT * FROM
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY Last_Name, First_Nmae ORDER BY DaysInPolicy DESC) AS RowNum
FROM Employees
) AS Emp
WHERE Emp.RowNum > 1
How to get 7th highest salary from table in SQL Server?
I tried this:
SELECT max(salary)
FROM emptable
WHERE salary < (SELECT max(salary)
FROM emptable);
SELECT salary
FROM (
SELECT salary
, DENSE_RANK()OVER(ORDER BY salary) DR
FROM emptable
) T
WHERE T.DR = 7
From SQL Server 2012 and onwards:
SELECT DISTINCT salary
FROM emptable
ORDER BY salary
OFFSET 6 ROWS
FETCH NEXT 1 ROWS ONLY;
You can as the below:
SELECT MAX(salary)
FROM (SELECT DISTINCT TOP 7 salary FROM emptable ORDER BY salary) A
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)
A table consists of employee name, address, phone, department, salary:
How to get the highest paid employee row from each department?
I tried with
select dept, max(salary) from employee group by dept
but it gives only two columns. But I want to select an entire row. How to do it?
Alternatively how to add more columns to the result?
(I am using SQL Server 2008)
You simply need to join the query you currently have back to the employee table to get the full employee information.
select e.*
from employee e
inner join (select dept, max(salary) ms from employee group by dept) m
on e.dept = m.dept and e.salary = m.ms
SELECT name,
address,
phone,
department,
salary,
dept
FROM (SELECT name,
address,
phone,
department,
salary,
dept,
row_number() OVER(PARTITION BY dept ORDER BY salary DESC) AS rn
FROM employee) AS e
WHERE e.rn = 1
Using row_number() will give you one row if there is a tie for the highest salary. If you want all the highest salaries for each department you should use rank() instead.
SELECT name,
address,
phone,
department,
salary,
dept
FROM (SELECT name,
address,
phone,
department,
salary,
dept,
rank() OVER(PARTITION BY dept ORDER BY salary DESC) AS rn
FROM employee) AS e
WHERE e.rn = 1
Something like this?
select * from employee where salary = (select max(salary) from employee)
with cte as (
select *, rank() over (partition by dept order by salary desc) as [r]
from employees
)
select * from cte where [r] = 1;
select * from employee
where salary in
(select max(salary) from employee group by dept);
If situation like you have both employee details and department in same table and you have to find the highest paid employee from each department like given below
EmployeeId EmployeeName Department Salary
1 Neeraj Dot Net 45000
2 Ankit Java 5000
3 Akshay Java 6000
4 Ramesh Dot Net 7600
5 Vikas Java 4000
7 Neha Php 8500
8 Shivika Php 4500
9 Tarun Dot Net 9500
Then you can solve it by using below solutions
Solution - 1
SELECT t.EmployeeName,t.Department,t.Salary
FROM(SELECT MAX(Salary) AS TotalSalary,Department FROM Employee GROUP BY Department)
AS TempNew Inner Join Employee t ON TempNew.Department=t.Department
and TempNew.TotalSalary=t.Salary
ORDER BY t.Department ASC
Solution -2
;WITH EmployeeDetails AS (
SELECT EmployeeName, Department, DENSE_RANK() OVER(PARTITION BY Department
ORDER BY Salary DESC) AS SalaryRank, Salary FROM Employee )
SELECT EmployeeName, Department, Salary FROM EmployeeDetails WHERE SalaryRank=1
OUTPUT
EmployeeName Department Salary
Neeraj Dot Net 45000
Akshay Java 6000
Neha Php 8500
SELECT region, person, sum(dollars) as thousands
FROM sales
GROUP BY region, person
ORDER BY region, sum(dollars) desc
The SQL above produces a complete list of sales people per region like this
region person thousands
canada mike smith $114
canada joe blog $76
canada pete dodd $45
usa john doe $253
usa jane smyth $120
europe pieter tsu $546
europ mike lee $520
If I'm only interested in showing the top salesperson per region (as below), how can I best do that?
region person thousands
canada mike smith $114
usa john doe $253
europe pieter tsu $546
I've done something like burnall suggested. I wasn't getting much love with the "top 1 with ties" part, so I made the whole thing a subquery and chose rows where ranking = 1.
select *
from
(
select region,
person,
rank() over(partition by region order by sum(dollars) desc) as ranking
from sales
group by region,
person
) temp
where ranking = 1
Note that this also works for ties since rank() seems to place the same ranking on sums that are equal.
Using Sql Server 2005+ you could do this using a ROW_NUMBER()
Have a look at this full example.
DECLARE #sales TABLE(
region VARCHAR(50),
person VARCHAR(50),
Sales FLOAT
)
INSERT INTO #sales SELECT 'canada','mike smith',1
INSERT INTO #sales SELECT 'canada','mike smith',1
INSERT INTO #sales SELECT 'canada','mike smith',1
INSERT INTO #sales SELECT 'canada','mike smith',1
INSERT INTO #sales SELECT 'canada','joe blog',1
INSERT INTO #sales SELECT 'canada','joe blog',1
INSERT INTO #sales SELECT 'canada','pete dodd',1
INSERT INTO #sales SELECT 'usa','john doe',1
INSERT INTO #sales SELECT 'usa','john doe',1
INSERT INTO #sales SELECT 'usa','jane smyth',1
INSERT INTO #sales SELECT 'europe','pieter tsu',1
INSERT INTO #sales SELECT 'europe','pieter tsu',1
INSERT INTO #sales SELECT 'europe','mike lee',1
;WITH Counts AS(
SELECT region,
person,
count(*) as thousands
FROM #sales
GROUP BY region,
person
), CountVals AS(
SELECT *,
ROW_NUMBER() OVER(PARTITION BY region ORDER BY thousands DESC) ROWID
FROM Counts
)
SELECT *
FROM CountVals
WHERE ROWID = 1
In SQL Server 2005 and above use ROW_NUMBER with PARTITION BY. Following should work (not tested, and probably can be shortened):
WITH total_sales
AS (SELECT region, person, count(*) as thousands
FROM sales
GROUP BY region, person
ORDER BY region, count(*) desc
)
, ranked_sales
AS (SELECT region, person, thousands,
ROW_NUMBER() OVER (PARTITION BY region ORDER BY thousands DESC, person) AS region_rank
FROM total_sales
)
SELECT region, person, thousands
FROM ranked_sales
WHERE region_rank = 1
First of all I do not understand why count(*) is in $.
My solution is similar to existing, but shorter and I believe faster
select top 1 with ties region, person, rank() over(partition by region order by count(*) desc)
from sales
group by region, person
order by 3
This isn't too difficult. This query will do exactly what you want.
select distinct region,
(select top 1 person
from Sales s2 where s2.region = s1.region
group by person
order by SUM(dollars) desc) as person,
(select top 1 SUM(dollars)
from Sales s2 where s2.region = s1.region
group by person
order by SUM(dollars) desc) as thousands
from sales s1
You can use the max() aggregate. It's probably less efficient than the other alternatives because you'll be doing group by twice
SELECT region,person,max(thousands) FROM
(SELECT region, person, count(*) as thousands
FROM sales
GROUP BY region, person) tmp
GROUP BY region, person
ORDER BY region, max(thousands) desc
to find top 5 salesperson by sales for each region
select *
from
(
select region,
[Customer Name],
rank() over(partition by region order by sum(sales) desc) as ranking
from Orders
group by region, [Customer Name]
) temp
where ranking between 1 and 5