Хорошо, не говорите, что я вас не предупреждал (согласно разделу комментариев выше). Это написано для MSSQL; Я не знаком с MySQL, поэтому я постарался сократить несобственные вещи. Вероятно, все это можно сделать одним большим уродливым запросом, но тогда это будет еще более неразборчиво, поэтому я разбил его на этапы.
Сначала настройте некоторые переменные:
DECLARE
@Items real = 32 -- How many items you wish to display
,@From int = 16000 -- Low range delimiter on your target data set
,@Thru int = 17500 -- High range delimiter on your target data set
,@Total real -- Used to store how many items are actually in the target range
Краткое тестирование показало, что что-то не получается, если @Items меньше 2 или больше, чем некоторое большое кратное @Total. Требуется обработка ошибок или тестирование входных данных. Я использую реальный тип данных, чтобы деление производило десятичные значения, а не усеченные целые числа; не забудьте установить их с целочисленными значениями, или я не знаю, что произойдет.
Этот следующий бит создает таблицу "Tally" или "таблицу чисел". Это просто таблица из восходящих целых чисел, состоящая из одного столбца, начиная с 1 и доходя до верхнего предела. Здесь я ограничил его 256, так как 32 - ваш максимум. (Этот конкретный код довольно тупой, но он может генерировать миллионы строк за очень короткое время, поэтому я вырезал и вставлял его всякий раз, когда мне нужны такие вещи.)
CREATE TABLE #Tally (Num int not null)
-- "Table of numbers" data generator, as per Itzik Ben-Gan (from multiple sources)
-- Modified to generate 1 through 256
;WITH
L0 AS (SELECT 1 AS C UNION ALL SELECT 1), --2 rows
L1 AS (SELECT 1 AS C FROM L0 AS A, L0 AS B),--4 rows
L2 AS (SELECT 1 AS C FROM L1 AS A, L1 AS B),--16 rows
L3 AS (SELECT 1 AS C FROM L2 AS A, L2 AS B),--256 rows
num AS (SELECT ROW_NUMBER() OVER(ORDER BY C) AS N FROM L3)
insert #Tally (Num)
select N FROM num
Получить количество строк в целевом наборе данных:
SELECT @Total = count(*)
from Time
where TimeId between @From and @Thru
Запрос на просмотр, перечисляет целевой диапазон в порядке с ранжированием (позиция, например, 1, 2, 3, 4 и т. Д.) В наборе. Это будет обрабатывать повторяющиеся значения. (Я основал свои тесты на нашей общей таблице «Время», которая выглядит почти как любая таблица измерения времени в любом хранилище данных.)
SELECT
row_number() over (order by TimeId) Ranking
,TimeId
from Time
where TimeId between @From and @Thru
Еще один обзорный запрос. Это возвращает набор чисел, который идентифицирует «точки останова» вашего окончательного набора. Например, если у вас есть 30 предметов и вы хотите 7, это даст {5, 10, 15, 20, 25, 30}; в сочетании с 1, это семерка, которую вы хотите (если у меня возникла проблема).
SELECT distinct ceiling((Num - 1) * @Total / (@Items - 1)) from #Tally
Вот рабочая лошадка, содержащая два вышеупомянутых запроса. По сути, берите все из первого запроса, где его ранг / позиция совпадает с идентифицированной «точкой останова» во втором запросе. Я бросил в первом элементе ИЛИ, так как это проще, чем пытаться втиснуть его математически.
SELECT xx.Ranking, xx.TimeId
from (select
row_number() over (order by TimeId) Ranking
,TimeId
from Time
where TimeId between @From and @Thru) xx
where Ranking in (select distinct ceiling((Num - 1) * @Total / (@Items - 1)) from #Tally)
or Ranking = 1
Как я уже сказал, он слишком сложный и может не работать для некоторых входных данных - но, скорее всего, он должен работать быстрее, чем процедурная альтернатива.