简体   繁体   中英

Mysql Query maximum records in n*2 format with range

referring to my previous question I'm asking this new question with similar issue.

I'm having table records like this

---- ---------     ------
 id     name       points
---- ---------     ------
 1      aaaa         90
 2      bbbb         87
 3      cccc         90
 4      dddd         80
 5      eeee         86
 6      ffff         82
 7      gggg         87
 8      hhhh         85
 10     iiii         86
 11     iiii         86
 12     iiii         86
 13     iiii         86
 14     iiii         87
 15     iiii         73
 16     iiii         86
 17     iiii         73
 18     hhhh         85
 19     hhhh         73
 20     hhhh         73
 21     hhhh         70
 22     hhhh         65
 23     hhhh         70
 24     hhhh         50

form the table, I want to select the records with the following condition

  1. For the first maximum record, Highest Points will be on top. (But only one record). I have two record with the highest point 90, Here the recent one should be displayed (maximum id)

  2. From second record onwards, the fields should be retrieved in the format of (n*2). I mean, for the 2nd maximum records I can allow 4 values to be fallen (2*2=4) with in the range from 2nd maximum record-10. ie in the table I select only recent 4 records (Maximum id) with in the range of 77 to 87 (87-10=77). now the 3rd maximum record, should be less than or equal to 76 (77-1) ie in the table it was 73. similarly for 3rd maximum, I can allow 3*2=6 records to be fallen within 63-73 (73-10=63) .. and so on..

Currently, I'm using answer from my another question

SELECT id, name, points FROM (
    SELECT
    t.*
    , @n := IF(@prev_points != points, @n + 1, @n) AS n
    , @row := IF(@prev_points != points, 1, @row + 1) AS row
    , @prev_points := points
    FROM
    t
    , (SELECT @prev_points := null, @n := 1, @row := 0) var_init_subquery
    ORDER BY points DESC, id DESC
) sq
WHERE row <= CASE WHEN n = 1 THEN 1 ELSE n * 2 END
;

But it limits to only one same record. Is there any possibilities to use count or any other relevant functions in this query based on the need. Hope you help me.

The output should look like this,

---- ---------     ------
 id     name       points
---- ---------     ------
 3      cccc         90      -- maximum (only one)

 14     iiii         87      |
 7      gggg         87      | -- 2nd maximum (allow 2*2 =4 only)
 2      bbbb         87      |
 16     iiii         86      |

 20     hhhh         73      |
 19     hhhh         73      | -- 3rd maximum (allow 3*2 =6 only)
 17     iiii         73      |
 14     iiii         73      |
 23     hhhh         70      | and so on for 4th and 5th
 21     hhhh         70      |

 24     hhhh         50      | -- 4th 4*2 = 8
/*Sample data*/
CREATE TABLE t
    (`id` int, `name` varchar(4), `points` int)
;

INSERT INTO t
    (`id`, `name`, `points`)
VALUES
    (1, 'aaaa', 90),
    (2, 'bbbb', 87),
    (3, 'cccc', 90),
    (4, 'dddd', 80),
    (5, 'eeee', 86),
    (6, 'ffff', 82),
    (7, 'gggg', 87),
    (8, 'hhhh', 85),
    (10, 'iiii', 86),
    (11, 'iiii', 86),
    (12, 'iiii', 86),
    (13, 'iiii', 86),
    (14, 'iiii', 87),
    (15, 'iiii', 73),
    (16, 'iiii', 86),
    (17, 'iiii', 73),
    (18, 'hhhh', 85),
    (19, 'hhhh', 73),
    (20, 'hhhh', 73),
    (21, 'hhhh', 70),
    (22, 'hhhh', 65),
    (23, 'hhhh', 70),
    (24, 'hhhh', 50)
;

/*Query*/
(
  SELECT id, name, points, 'maximum (only one)' AS maximum, 'just the max' AS group_range
  FROM t
  ORDER BY points DESC, id DESC
  LIMIT 1
)
UNION ALL
(
SELECT id, name, points, CONCAT(n, ' maximum'), CONCAT('range from ', group_max, ' to ', group_max - 10) FROM (
    SELECT
    t.*
    , @n := IF(points < @group_max - 10, @n + 1, @n) AS n
    , @group_max := IF(@n != @prev_n, @group_max - 11, @group_max) AS group_max

    , @row := IF(@n != @prev_n, 1, @row + 1)
    , IF(@row > @n * 2, 0, 1) AS select_it
    , @prev_n := @n
    FROM
    t
    , (SELECT @prev_n := 2, @max := points, @group_max := (SELECT points FROM t WHERE points != (SELECT MAX(points) FROM t) ORDER BY points DESC LIMIT 1), @n := 2, @row := 0 FROM t ORDER BY points DESC LIMIT 1) var_init_subquery
    WHERE points != @max
    ORDER BY points DESC, id DESC
) sq
WHERE select_it = 1
);

Note, you messed up your desired result a bit I think. Added two columns to prove that :)

/*Result*/
| ID | NAME | POINTS |            MAXIMUM |         GROUP_RANGE |
|----|------|--------|--------------------|---------------------|
|  3 | cccc |     90 | maximum (only one) |        just the max |
| 14 | iiii |     87 |          2 maximum | range from 87 to 77 |
|  7 | gggg |     87 |          2 maximum | range from 87 to 77 |
|  2 | bbbb |     87 |          2 maximum | range from 87 to 77 |
| 16 | iiii |     86 |          2 maximum | range from 87 to 77 |
| 20 | hhhh |     73 |          3 maximum | range from 76 to 66 |
| 19 | hhhh |     73 |          3 maximum | range from 76 to 66 |
| 17 | iiii |     73 |          3 maximum | range from 76 to 66 |
| 15 | iiii |     73 |          3 maximum | range from 76 to 66 |
| 23 | hhhh |     70 |          3 maximum | range from 76 to 66 |
| 21 | hhhh |     70 |          3 maximum | range from 76 to 66 |
| 22 | hhhh |     65 |          4 maximum | range from 65 to 55 |
| 24 | hhhh |     50 |          5 maximum | range from 54 to 44 |

Update after clarification:

(
  SELECT id, name, points, 'maximum (only one)' AS maximum, 'just the max' AS group_range
  FROM t
  ORDER BY points DESC, id DESC
  LIMIT 1
)
UNION ALL
(
SELECT id, name, points, CONCAT(n, ' maximum'), CONCAT('range from ', group_max, ' to ', group_max - 10) FROM (
    SELECT
    t.*
    , @n := IF(points < @group_max - 10, @n + 1, @n) AS n
    , @group_max := IF(@n != @prev_n, points, @group_max) AS group_max

    , @row := IF(@n != @prev_n, 1, @row + 1)
    , IF(@row > @n * 2, 0, 1) AS select_it
    , @prev_n := @n
    FROM
    t
    , (SELECT @prev_n := 2, @max := points, @group_max := (SELECT points FROM t WHERE points != (SELECT MAX(points) FROM t) ORDER BY points DESC LIMIT 1), @n := 2, @row := 0 FROM t ORDER BY points DESC LIMIT 1) var_init_subquery
    WHERE points != @max
    ORDER BY points DESC, id DESC
) sq
WHERE select_it = 1
);

| ID | NAME | POINTS |            MAXIMUM |         GROUP_RANGE |
|----|------|--------|--------------------|---------------------|
|  3 | cccc |     90 | maximum (only one) |        just the max |
| 14 | iiii |     87 |          2 maximum | range from 87 to 77 |
|  7 | gggg |     87 |          2 maximum | range from 87 to 77 |
|  2 | bbbb |     87 |          2 maximum | range from 87 to 77 |
| 16 | iiii |     86 |          2 maximum | range from 87 to 77 |
| 20 | hhhh |     73 |          3 maximum | range from 73 to 63 |
| 19 | hhhh |     73 |          3 maximum | range from 73 to 63 |
| 17 | iiii |     73 |          3 maximum | range from 73 to 63 |
| 15 | iiii |     73 |          3 maximum | range from 73 to 63 |
| 23 | hhhh |     70 |          3 maximum | range from 73 to 63 |
| 21 | hhhh |     70 |          3 maximum | range from 73 to 63 |
| 24 | hhhh |     50 |          4 maximum | range from 50 to 40 |

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM