'How select results with a range of at most 300 points difference
I have this registers:
ID, Points
----------
1, 100
2, 130
3, 400
4, 299
5, 50
6, 600
7, 800
How select first 4 results with a range of at most 300 points difference? Example of results I expect:
ID, Points
----------
--------------->
5, 50 -----
1, 100 ----
2, 130 ---- first 4 ids with points range 300
4, 299 ----
--------------->
...
Other example:
ID, Points
----------
22, 700
20, 800
21, 850
23, 970
Solution 1:[1]
(Not quite sure what's more important: the fact that you need 4 ids or that you need a range that it close to 300.
In your question you have the value 800 twice, with different ids.
However, ...)
Maybe you can use a combination of a analytic functions (window functions) and a self join for this.
TABLE (see also: dbfiddle)
ID POINTS
1 100
2 130
3 400
4 299
5 50
6 600
7 800
22 700
20 800
21 850
23 970
Row numbers and ordering
select id, points
, row_number() over ( order by points ) rn_
from t ;
-- result
ID POINTS RN_
5 50 1
1 100 2
2 130 3
4 299 4
3 400 5
6 600 6
22 700 7
7 800 8
20 800 9
21 850 10
23 970 11
Use this query for a self join that satisfies the required conditions ..
select
t1.id, t1.points as from_
, t2.id, t2.points as to_
from (
select id, points
, row_number() over ( order by points ) rn_
from t
) t1 join (
select id, points
, row_number() over ( order by points ) rn_
from t
) t2 on t2.points <= t1.points + 300 and t2.rn_ - t1.rn_ = 3 ;
-- result
ID FROM_ ID TO_
5 50 4 299
1 100 3 400
6 600 20 800
22 700 21 850
7 800 23 970
If you only want to have the first row of this output, just add a "limit" (using Oracle eg fetch first row only -> see dbfiddle).
EDIT
Considering your comments, it appears that you need 4 player IDs, which will be removed from the database (table) if they are playing, which depends on their scores being in the range (of 300 points). In order to achieve this, maybe the following views will be helpful (Why views? Because they will make the DELETE statement easier to read.)
VIEW 1 - get the IDs of the 4 players with the lowest points
create or replace view fourplayers
as
select id, points
from (
select id, points
, row_number() over ( order by points ) rn_
from t
)
where rn_ <= 4 ;
-- test
select * from fourplayers ;
-- result
ID POINTS
5 50
1 100
2 130
4 299
VIEW 2 - should the 4 players play?
create or replace view rangeandplay
as
select
count(*) numberofplayers
, min( points ) minpoints
, max( points ) maxpoints
, max( points ) - min( points ) range
, case when max( points ) - min( points ) <= 300 then 'Y' else 'N' end play
from (
select id, points from fourplayers
) ;
-- test
select * from rangeandplay ;
-- result
NUMBEROFPLAYERS MINPOINTS MAXPOINTS RANGE PLAY
4 50 299 249 Y
DELETE the 4 players, if the PLAY flag is set to 'Y'
delete from t
where id in (
select id from fourplayers
) and (
( select play from rangeandplay ) = 'Y'
) ;
commit ;
If we now run SELECT * FROM rangeandplay, we see ...
select * from rangeandplay ;
-- result
NUMBEROFPLAYERS MINPOINTS MAXPOINTS RANGE PLAY
4 400 800 400 N
-> The DELETE would not execute now, as PLAY is set to 'N'. If another player eg with 450 points is INSERTed into the table, DELETE would remove the first 4 players again. See dbfiddle.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
