Radical_Activity
Radical_Activity

Reputation: 2738

How to rank MySQL results, based on different values?

I have 2 different tables in my database by the name of: rank, settings.

Here is how each table looks like with a few records in them:

Table #rank:

id  points userid
--  ----- ------
 1    500      1
 2    300      2    
 3    900      3
 4   1500      4
 5    100      5
 6    700      6
 7    230      7
 8    350      8
 9    850      9
10    150     10

Table #settings:

userid    active 
------    ------
     1         0
     2         1
     3         1
     4         1
     5         1
     6         0
     7         1
     8         1
     9         0
    10         1

What I basically want to achieve is to select a specific row from #rank by ID, sort it by points and select 3 rows above the specific ID and 3 row below the specific ID but only for rows where the active column (from #settings) for the user equals 1.

For example: I would like to select from #rank the ID of 8, and it should return me the following:

rank points userid
---- ----- ------
   2   150     10   
   3   230      7
   4   300      2
   5   350      8
   6   900      3
   7   1500     4

I have created quite an extensive query for this, but the problem is, that it is ranking the columns before it decides that the user is active or not. However I need to rank the columns after it is decided that the user is active or not.

SELECT  sub2.sort, sub2.points, sub2.userid
FROM
(
    SELECT  @sort1 := @sort1 + 1 AS sort, puu.points, puu.userid
    FROM    rank as puu,
    (SELECT @sort1 := 0) s
    LEFT JOIN 
    (
        settings as p11 
    )
    ON puu.userid = p11.userid,
    WHERE p11.active = 1
    ORDER BY puu.points DESC
) sub1
INNER JOIN
(
    SELECT @sort2:=@sort2+1 AS sort, p2.points, p2.userid 
    FROM rank as p2,
    (SELECT @sort2 := 0) s
            LEFT JOIN
    (
            settings as p12
    ) 
    ON p2.userid = p12.userid,
    WHERE p12.active = 1
    ORDER BY points DESC
) sub2
ON sub1.userid = :userid
AND sub2.sort BETWEEN (sub1.sort - 5) AND (sub1.sort + 5)

Can you guys find any solution for my problem? If you can provide an SQLfiddle demo, that would be really awesome!

Upvotes: 1

Views: 309

Answers (2)

Kickstart
Kickstart

Reputation: 21513

Possibly using 2 unioned queries to get the values before the ranking:-

SELECT @rank:=@rank+1 AS rank, points, userid
FROM
(
    SELECT id, points, userid
    FROM
    (
        SELECT rank.id, rank.points, rank.userid
        FROM rank
        INNER JOIN
        (
            SELECT points
            FROM rank
            WHERE id = 8
        ) sub0
        ON rank.points >= sub0.points
        INNER JOIN settings
        ON rank.userid = settings.userid
        WHERE settings.active = 1
        ORDER BY rank.points LIMIT 3
    ) sub1
    UNION ALL
    SELECT id, points, userid
    FROM
    (
        SELECT rank.id, rank.points, rank.userid
        FROM rank
        INNER JOIN
        (
            SELECT points
            FROM rank
            WHERE id = 8
        ) sub0
        ON rank.points < sub0.points
        INNER JOIN settings
        ON rank.userid = settings.userid
        WHERE settings.active = 1
        ORDER BY rank.points DESC LIMIT 3
    ) sub1
) sub2
CROSS JOIN (SELECT @rank:=0) sub3
ORDER BY points 

Upvotes: 0

colburton
colburton

Reputation: 4715

SELECT sort, points, user_id, active FROM (
    SELECT @pos := @pos + 1 AS sort, id, points, r.user_id, s.active,
    IF(user_id = :userid, @userpos := @pos, 0)
  FROM rank r
  JOIN settings s USING(user_id)
  JOIN (SELECT @pos := 0, @userpos := 0) p
  WHERE s.active = 1
  ORDER BY points DESC
) list
WHERE sort BETWEEN @userpos - 3 AND @userpos + 3

I made a fiddle here: sqlfiddle

Upvotes: 1

Related Questions