Мне пришлось решить аналогичную проблему, но мне нужно было учитывать ситуации, когда мы всегда получали одинаковое количество строк, даже если требуемая строка была в верхней или нижней части набора результатов (то есть не совсем в середине). * +1001 *
Это решение - твик из ответа OMG Ponies, но в котором максимальное значение rownum в желаемой строке:
set @id = 7;
SELECT natSorted.id
FROM (
SELECT gravitySorted.* FROM (
SELECT Media.id, IF(id <= @id, @gravity := @gravity + 1, @gravity := @gravity - 1) AS gravity
FROM Media, (SELECT @gravity := 0) g
) AS gravitySorted ORDER BY gravity DESC LIMIT 10
) natSorted ORDER BY id;
Вот пример того, что происходит:
ПРИМЕЧАНИЕ. В приведенном ниже примере я создал таблицу с 20 строками и удалил идентификаторы 6 и 9, чтобы гарантировать, что разрыв в идентификаторах не влияет на результаты
Сначала мы присваиваем каждой строке значение силы тяжести, центрированное вокруг конкретной строки, которую вы ищете (в данном случае, когда id равно 7). Чем ближе строка к нужной строке, тем выше будет значение:
SET @id = 7;
SELECT Media.id, IF(id <= @id, @gravity := @gravity + 1, @gravity := @gravity - 1) AS gravity
FROM Media, (SELECT @gravity := 0) g
возвращается:
+----+---------+
| id | gravity |
+----+---------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
| 5 | 5 |
| 7 | 6 |
| 8 | 5 |
| 10 | 4 |
| 11 | 3 |
| 12 | 2 |
| 13 | 1 |
| 14 | 0 |
| 15 | -1 |
| 16 | -2 |
| 17 | -3 |
| 18 | -4 |
| 19 | -5 |
| 20 | -6 |
| 21 | -7 |
+----+---------+
Далее мы упорядочиваем все результаты по значению силы тяжести и ограничиваем желаемое количество строк:
SET @id = 7;
SELECT gravitySorted.* FROM (
SELECT Media.id, IF(id <= @id, @gravity := @gravity + 1, @gravity := @gravity - 1) AS gravity
FROM Media, (SELECT @gravity := 0) g
) AS gravitySorted ORDER BY gravity DESC LIMIT 10
возвращается:
+----+---------+
| id | gravity |
+----+---------+
| 7 | 6 |
| 5 | 5 |
| 8 | 5 |
| 4 | 4 |
| 10 | 4 |
| 3 | 3 |
| 11 | 3 |
| 2 | 2 |
| 12 | 2 |
| 1 | 1 |
+----+---------+
На данный момент у нас есть все желаемые идентификаторы, нам просто нужно отсортировать их в исходном порядке:
set @id = 7;
SELECT natSorted.id
FROM (
SELECT gravitySorted.* FROM (
SELECT Media.id, IF(id <= @id, @gravity := @gravity + 1, @gravity := @gravity - 1) AS gravity
FROM Media, (SELECT @gravity := 0) g
) AS gravitySorted ORDER BY gravity DESC LIMIT 10
) natSorted ORDER BY id;
возвращается:
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 7 |
| 8 |
| 10 |
| 11 |
| 12 |
+----+