Removing Subqueries - sql-server

I have 2 tables tab1 and tab2.
tab1:
id name monthid salary inflow
-----------------------------------------
1 mohan 1 2000 1000
1 mohan 3 3000 1000
1 mohan 4 4500 1600
1 mohan 2 2500 1200
in tab2 I want this output:
id name salary inflow
--------------------------
1 mohan 12000 1600
In tab2, salary column is the sum of salary of tab1 and inflow is the inflow of highest month.
I tried this query:
Insert into tab2(id, name, salary)
select id, name, sum(salary)
from tab1
update tab2
set inflow = (select inflow
from tab1
where monthid = max(monthid))
But I know this is not the correct method.
Can anyone help me to correct this query? And I also want to remove the subqueries.

You can use row_number as below
Insert into tab2(id, [name], [salary], inflow)
Select id, [name], Salary, inflow from (
Select id, [name], sum(salary) over(partition by id) as Salary,
inflow, RowN = Row_number() over (partition by id order by monthid desc) from tab1 ) a
Where a.RowN = 1
Without subquery you can use top(1) with ties as below
Insert into tab2(id, [name], [salary], inflow)
Select top (1) with ties id, [name], sum(salary) over(partition by id) as salary, inflow
from tab1
order by Row_number() over (partition by id order by monthid desc)

DECLARE #tab1 table(id int,name varchar(100),monthid int, salary int,inflow int)
INSERT INTO #tab1
SELECT 1,'Mohan',1,2000,1000
UNION ALL
SELECT 1,'Mohan',3,3000,1000
UNION ALL
SELECT 1,'Mohan',4,4500,1600
UNION ALL
SELECT 1,'Mohan',2,2500,1200
SELECT top 1
id, name,SUM(salary) OVER(PARTITION BY id) as salary,MAX(inflow) OVER(PARTITION BY id) as inflow
FROM #tab1
OR
SELECT DISTINCT
id, name,SUM(salary) OVER(PARTITION BY id) as salary,MAX(inflow) OVER(PARTITION BY id) as inflow
FROM #tab1

Related

How to Find Ffifth Youngest Employee by DOB in Sql Server

What will be sql query for the fifth youngest employee?
Below query is wrong? please help
SELECT EmpID, EmpName, EMPDOB,
ORDER BY EMPDOB DESC
WHERE ROWNUMBER = 5
FROM dbo.EMP
SELECT * FROM (
SELECT
ROW_NUMBER() OVER (ORDER BY EMPDOB ASC) AS rownumber,
EmpID, EmpName, EMPDOB
FROM EMPLOYEE
) AS foo
WHERE rownumber = 5
The following query will solve your problem:
SELECT TOP 1
T.EmpID
, T.EmpName
, T.EMPDOB
FROM (SELECT TOP 5 * FROM dbo.EMP ORDER BY EMPDOB DESC) AS T
Note: This solution assumes that EMPDOB is in a date or integer based format.

Count and Row_Number

I want to get the top 5 Zipcodes for each Store with the highest Customers in them (zipcodes).
Please find below my query:
SELECT T.[Store], T.[ZipCode], Count(T.[Customer])
FROM ( SELECT T.[Store], T.[ZipCode],
Count(T.[Customer]) row_number() over (Partition By T.[StoreGitanjali] Order By Count (T.[Customer]) desc) as RN
FROM [Marketing].[dbo].[Poscus] as T
Group By T.[StoreGitanjali], T.[ZipCode]) as T
where T.RN <=5
Group By T.[StoreGitanjali], T.[ZipCode]
Please let me know how to use Count here in this scenario.
Thank you!
Example
CREATE TABLE #t
(
ID INT IDENTITY(1,1),
Customer NVARCHAR(3),
Store NVARCHAR(5),
ZIP INT
)
INSERT INTO #t VALUES('a', 'XYZ', 1234)
,('b', 'XYZ', 1234)
,('c', 'PQR', 1231)
,('d', 'PQR', 1231)
,('e', 'PQR', 1231)
,('f', 'XYZ', 1232)
,('g', 'XYZ', 1232)
,('h', 'XYZ', 1232)
,('i', 'PQR', 1236)
,('j', 'PQR', 1236)
,('k', 'LMN', 1237)
SELECT * FROM #t
The solution is, Set WHERE part < 2 according to your requirement.
SELECT TotalCustomer, Store, ZIP, Part FROM (
SELECT
COUNT(1) AS TotalCustomer,
Store,
ZIP,
ROW_NUMBER() OVER (PARTITION BY Store ORDER BY Store) AS Part
FROM #t
GROUP BY Store, ZIP
) t
WHERE Part < 2
ORDER BY Part
;WITH CTE
AS(
SELECT Store
,Zip
,COUNT(DISTINCT Customer) AS CustCount
FROM #t
GROUP BY Store,Zip
--ORDER BY Store,Zip
)
SELECT A.*
FROM(
SELECT *
--,DENSE_RANK() OVER(PARTITION BY Store ORDER BY CustCount DESC) AS DenRank
,ROW_NUMBER() OVER(PARTITION BY Store ORDER BY CustCount DESC) AS DenRank
FROM CTE
--ORDER BY Store,Zip
) AS A
WHERE A.DenRank <= 2

Maximum and Minimum Rows Alternatively in SQL Server

This is an Employee table,
Id Name Salary
1 A.J 7000
2 B.S 30000
3 C.K 2000
4 D.O 10000
5 E.L 500
Now i want to display 1st highest salary then minimum salary then 2nd maximum salary then 2nd minimum salaray and so on..up to nth row.
Expected Output,
Id Name Salary
2 B.S 30000
5 E.L 500
4 D.O 10000
3 C.K 2000
1 A.J 7000
One more variant without explicit COUNT. SQL Fiddle.
Try also to add this row to sample data (6, 'X.Y', 7000) in the fiddle. The query still returns correct results.
DECLARE #Employee TABLE (ID int, Name nvarchar(50), Salary money);
INSERT INTO #Employee (ID, Name, Salary) VALUES
(1, 'A.J', 7000),
(2, 'B.S', 30000),
(3, 'C.K', 2000),
(4, 'D.O', 10000),
(5, 'E.L', 500);
WITH
CTE
AS
(
SELECT *, NTILE(2) OVER (ORDER BY Salary, ID) AS n
FROM #Employee AS E
)
SELECT
*
,SIGN(n-1.5) AS s
,SIGN(n-1.5)*Salary AS ss
,ROW_NUMBER() OVER(PARTITION BY n ORDER BY SIGN(n-1.5)*Salary DESC) AS rn
FROM CTE
ORDER BY rn, ss DESC;
Result
ID Name Salary n s ss rn
2 B.S 30000.00 2 1.0 30000.00000 1
5 E.L 500.00 1 -1.0 -500.00000 1
4 D.O 10000.00 2 1.0 10000.00000 2
3 C.K 2000.00 1 -1.0 -2000.00000 2
1 A.J 7000.00 1 -1.0 -7000.00000 3
I left intermediary columns in the output to illustrate how it works.
Using Row_Number() and Count()
Fiddle Demo
declare #count int=(select count(1) from Employee);
with cte1 as
(
select ROW_NUMBER() over(order by salary desc) as rn,0 Sort,Id,Name,Salary, count(Id) over () cnt from Employee
union all
select ROW_NUMBER() over(order by salary) as rn,1 Sort,Id,Name,Salary, count(Id) over () cnt from Employee
)
select top (#count) Id,Name,Salary from cte1 where rn <= (floor(cnt/2) + cnt%2) order by rn,sort
Below is the solution:
--Create dummy employee table
CREATE TABLE tbl_Employee
(
Id INT,
Name VARCHAR(100),
Salary NUMERIC(9, 2)
)
GO
--Insert few dummy rows in the table
INSERT INTO #Employee
(Id, Name, Salary)
VALUES(100, 'John', 7000),
(101, 'Scott', 30000),
(102, 'Jeff', 2000),
(103, 'Jimy', 10000),
(104, 'Andrew', 500),
(105, 'Alister', 100)
GO
--Get data as required
DECLARE #Cnt INT = 0, #SeqLimit INT = 0
SELECT #Cnt = COUNT(1) FROM tbl_employee
SET #SeqLimit = CEILING(#Cnt / 2.0)
SELECT * FROM
(
SELECT ROW_NUMBER() OVER(ORDER BY Salary DESC) AS SEQ, Id, Name, Salary FROM tbl_employee
)DT1
WHERE SEQ <= #SeqLimit
UNION ALL
SELECT * FROM
(
SELECT ROW_NUMBER() OVER(ORDER BY Salary ASC) AS SEQ, Id, Name, Salary FROM tbl_employee
)DT2
WHERE SEQ <= #SeqLimit - (#Cnt % 2)
ORDER BY SEQ ASC, Salary DESC
The same can be achieved with different approaches and here you can find more on this:
http://www.sqlrelease.com/order-max-and-min-value-rows-alternatively-in-sql-server

Error when using insert with CTE and ranking function

I have a table temp.Results which contain Employee info. This table contains info used by HR. All changes to the employee records are in the table.i.e.
select * from temp.Results where ID=1
1,'2 main st','salem','2009-01-01','2000-01-01'
1,'34 elm st','acton','2013-03-09','2000-01-01'
Datevalidated is when we entered latest info.DateProcessed is the first time we entered employee info.
WITH ordered as(
select ID, name, address,city, DateValidated, DateProcessed
,ROW_NUMBER() over (partition by DateValidated
order by DateValidated desc) as rn from
aa.temp.Results (nolock) where id=31
)
insert into tempResults2(ID, name, address,city, DateValidated, DateProcessed)
select ID, name, address,city, DateValidated, DateProcessed from ordered where rn = 1 ;
I tried getting the above query to get the latest info of each employee into a teable but get this error.
Invalid object name 'tempResults2'
How to resolve this?
Thanks
MR
You can use where clause with select * into .
WITH ordered as
(
select
ID, name, address,city, DateValidated, DateProcessed,
ROW_NUMBER() over (partition by DateValidated order by DateValidated desc) as rn
from aa.temp.Results where id=31
)
select * into tempResults2 from ordered where rn = 1 ;
WITH ordered as(
select ID, name, address,city, DateValidated, DateProcessed
,ROW_NUMBER() over (partition by DateValidated
order by DateValidated desc) as rn from
aa.temp.Results (nolock) where id=31
)
select ID, name, address,city, DateValidated, DateProcessed
into tempResults2
from ordered
where rn = 1 ;
You query is wrong. When you can use nolock like this
WITH ordered as(
select ID, name, address,city, DateValidated, DateProcessed
,ROW_NUMBER() over (partition by DateValidated
order by DateValidated desc) as rn from
aa.temp.Results with(nolock) where id=31
)

SQL Server 2008 R2 GROUP BY or OVER

I have this table:
ID COLOR TYPE DATE
-------------------------------
1 blue A 2012.02.05
2 white V 2010.10.23
3 white V 2014.03.05
4 black S 2013.02.14
I'd like to select only the ID, but in case of 2nd and 3rd rows I want to select the 3rd row because of its latest DATE value.
I have tried this query but it gives back all the two rows:
SELECT
ID, MAX(DATE) OVER(PARTITION BY COLOR, TYPE)
FROM
TABLE
WHERE
...
How can I select just one column value while I group the rows by other columns, please?
;WITH CTE AS
(
SELECT * , ROW_NUMBER() OVER (PARTITION BY COLOR,[TYPE] ORDER BY [DATE] DESC) rn
FROM TableName
)
SELECT ID
,COLOR
,[TYPE]
,[DATE]
FROM CTE
WHERE rn = 1
OR
SELECT ID
,COLOR
,[TYPE]
,[DATE]
FROM
(
SELECT * , ROW_NUMBER() OVER (PARTITION BY COLOR,[TYPE] ORDER BY [DATE] DESC) rn
FROM TableName
) A
WHERE rn = 1

Resources