Remove minimum rank rows in SQL Server - sql

I have a table like below.
Customer Order Rank
1 12 3
1 14 7
2 15 6
2 16 4
2 17 2
2 21 1
3 24 5
3 25 6
3 27 7
Now, I want to select all rows except for rows with minimum ranks for each customer. It should look like below.
Customer Order Rank
1 14 7
2 15 6
2 16 4
2 17 2
3 25 6
3 27 7

You can use a CTE + ROW_NUMBER:
WITH CTE AS
(
SELECT Customer, [Order], Rank,
RN = ROW_NUMBER() OVER (PARTITION BY Customer ORDER BY Rank)
FROM dbo.Customers
)
SELECT Customer, [Order], Rank
FROM CTE
WHERE RN > 1
ORDER BY Customer, Rank DESC
Demo: http://sqlfiddle.com/#!6/444be/3/0

WITH CTE AS (
SELECT Customer,Order,Rank,
ROW_NUMBER() OVER (PARTITION BY Customer ORDER BY Rank ) as rn FROM t
)
SELECT Customer,Order,Rank FROM CTE
WHERE rn >1

Related

Select commonly chosen desires collage by students after first 5 rows each group

With subquery I need to select after first five rows for each group of id_student and must common values of id_desireCollage between id_student.
More explain : select common collages for each student desires after his five chosen desires
ID
id_desireCollage
id_student
1
1
1
2
2
1
3
3
1
4
4
1
5
5
1
6
8
1
7
9
1
8
7
1
9
2
2
10
12
2
11
1
2
12
3
2
13
6
2
14
5
2
15
8
2
16
9
2
17
7
2
18
4
3
19
3
3
20
2
3
21
1
3
22
8
3
23
9
3
24
7
3
25
5
3
Something like
select id_desireCollage
from
(select *
from desires ds
where ds.id_desireCollage = desires.id_desireCollage)
group by (id_student)
having count(*) > 5
Expected result is:
id_desireCollage
7
9
Try the following:
select id_desireCollage
from
(
select d.*,
row_number() over (partition by id_student order by ID) as rn
from desires d
) T
where rn > 5
group by id_desireCollage
order by count(*) desc
fetch first 1 row with ties
If you don't want to use the row number function (as you commented), you may try the following - supposing there are no gaps in the ID column:
select id_desireCollage
from desires d
where id >=
(
select min(id)+5
from desires t
where t.id_student = d.id_student
)
group by id_desireCollage
order by count(*) desc
fetch first 1 row with ties
See demo
As suggested by #MatBailie, if you meant by common, that all students have selected the id_desireCollage value then you could use the following:
select id_desireCollage
from desires d
where id >=
(
select min(id)+5
from desires t
where t.id_student = d.id_student
)
group by id_desireCollage
having count(*)=
(
select count(distinct id_student)
from desires
)

SQL Ignoring duplicate values if ID difference larger than

Lets say I have a simple table:
ID value
1 15
2 30
3 **10**
4 **10**
5 16
6 20
7 **15**
8 **15**
9 40
10 70
11 **50**
12 **50**
13 19
14 11
15 3
My select should ignore consecutive double values. I know how to do that - I am using lead function
But this eliminates all consecutive duplicates.
SELECT [DetectorParameterValue]
FROM (
SELECT lead(DetectorParameterValue,1) over (partition by runid order by runtime) AS prev_DetectorParameterValue
FROM table_Detector
WHERE RunID = #run_id
) AS [InnerDetector]
WHERE (prev_DetectorParameterValue is null or or prev_DetectorParameterValue <> DetectorParameterValue
But it should ignore them only if ID diff is more than 5.
So my select should be
ID Value
1 15
2 30
3 10
5 16
6 20
7 15
8 15
9 40
10 70
11 50
13 19
14 11
15 3
ID 4 and 12 should be ignored but ID 8 should not because ID 8 - ID 4 is not > 5.
Is there a way to do this?
Thanks in advance.
This is a gaps and islands problem in disguise. One approach uses the difference in row numbers method.
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (ORDER BY ID) rn1,
ROW_NUMBER() OVER (PARTITION BY value ORDER BY ID) rn2
FROM yourTable
),
cte2 AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY value, rn1 - rn2 ORDER BY ID) rn
FROM cte
)
SELECT ID, value
FROM cte2
WHERE rn = 1
ORDER BY ID;

Find first N rows that have unique value with mod(id, N)

For example, N is 10 and a table looks like
id
1
2
3
4
5
6
7
10
11
12
13
108
109
111
112
113
Need to find first N rows that have unique value with mod(id, N).
Expected result is
mod10
1
2
3
4
5
6
7
10
108
109
I've tried something like
select *
from
(
select id, id % 10 as seq_id
from accounts order by id
) as s1
group by s1.seq_id limit 10;`
but not working.
You can use window function here -
SELECT id
FROM (SELECT id, ROW_NUMBER() OVER(PARTITION BY id % 10 ORDER BY id) RN
FROM table_name
) X
WHERE RN = 1
ORDER BY id
You can try the below one - using row_number()
DEMO
with cte as
(
select id, row_number() over(partition by seq_id order by id) as rn
from
(
select id, id % 10 as seq_id from tablename
)A
)
select id from cte where rn=1 order by id
OUTPUT:
id
1
2
3
4
5
6
7
10
108
109

How to select top 2 values for each id

I have a table with values
id sales date
1 5 "2015-01-04"
1 3 "2015-01-03"
1 1 "2015-01-01"
1 1 "2015-01-01"
2 7 "2015-01-05"
2 6 "2015-01-04"
2 4 "2015-01-03"
3 11 "2015-01-08"
3 10 "2015-01-07"
3 9 "2015-01-06"
3 8 "2015-01-05"
I want to select top two values of each id as shown in desired output.
Desired output:
id sales date
1 5 "2015-01-04"
1 3 "2015-01-03"
2 7 "2015-01-05"
2 6 "2015-01-04"
3 11 "2015-01-08"
3 10 "2015-01-07"
My attempt:
can someone help me with this. Thank you in advance!
select transactions.salesperson_id, transactions.id, transactions.date
from transactions
ORDER BY transactions.salesperson_id ASC, transactions.date DESC;
This can be done using window functions:
select id, sales, "date"
from (
select id, sales, "date",
dense_rank() over (partition by id order by "date" desc) as rnk
from transactions
) t
where rnk <= 2;
If there are multiple rows on the same date this might return more than two rows for the same ID. If you don't want that, use row_number() instead of dense_rank()
row_number() will get what you want.
select * from
(select row_number() over (partition by id order by date) as rn, sales, date from transactions) t1
where t1.rn <= 2

Select and aggregate last records base on order

I have different versions of the charges in a table. I want to grab and sum the last charge grouped by Type.
So I want to add 9.87, 9.63, 1.65.
I want the Parent ID , sum(9.87 + 9.63 + 1.65) as the results of this query.
We use MSSQL
ID ORDER CHARGES TYPE PARENT ID
1 1 6.45 1 1
2 2 1.25 1 1
3 3 9.87 1 1
4 1 6.54 2 1
5 2 5.64 2 1
6 3 0.84 2 1
7 4 9.63 2 1
8 1 7.33 3 1
9 2 5.65 3 1
10 3 8.65 3 1
11 4 5.14 3 1
12 5 1.65 3 1
WITH recordsList
AS
(
SELECT Type, Charges,
ROW_NUMBER() OVER (PArtition BY TYPE
ORDER BY [ORDER] DESC) rn
FROM tableName
)
SELECT SUM(Charges) totalCharge
FROM recordsLIst
WHERE rn = 1
SQLFiddle Demo
Use row_number() to identify the rows to be summed, and then sum them:
select SUM(charges)
from (select t.*,
ROW_NUMBER() over (PARTITION by type order by id desc) as seqnum
from t
) t
where seqnum = 1
Alternatively you could use a window aggregate MAX():
SELECT SUM(Charges)
FROM (
SELECT
[ORDER],
Charges,
MaxOrder = MAX([ORDER]) OVER (PARTITION BY [TYPE])
FROM atable
) s
WHERE [ORDER] = MaxOrder
;
SELECT t.PARENT_ID, SUM(t.CHARGES)
FROM dbo.test73 t
WHERE EXISTS (
SELECT 1
FROM dbo.test73
WHERE [TYPE] = t.[TYPE]
HAVING MAX([ORDER]) = t.[ORDER]
)
GROUP BY t.PARENT_ID
Demo on SQLFiddle