У меня есть стол

 CREATE TABLE tblHistory
    (
      ID INT IDENTITY
             PRIMARY KEY ,
      Added DATETIME ,
      value1 INT ,
      Value2 INT
    )

С большим количеством исторических данных.

В результате я хочу максимум 100 строк, но от начала до конца.

В этом примере SQL Fiddle у меня 197 строк данных в моей таблице.

В этом примере мне нужно не более 100 строк от начала до конца ... каждая вторая строка в моем результате, так что у меня не более 100 строк.

Если в моей таблице History 500 записей, я хочу, например, каждую пятую запись из моей таблицы History и так далее ...

Я надеюсь, что кто-то может помочь мне.

Заранее спасибо.

1
WhoisIt 30 Апр 2014 в 17:44

5 ответов

Лучший ответ

Если предположить, что id не имеет пробелов, следующее должно делать то, что вы хотите, относительно эффективно:

select h.*
from tblHistory h cross join
     (select count(*) as cnt from tblHistory) as c
where floor(id * 100.0 / cnt) <> floor((id + 1) * 100.0 / cnt);

Это позволит выбрать около 100 строк, равномерно распределенных в данных. Если id не соответствует этим условиям, используйте row_number() в подзапросе.

3
Gordon Linoff 30 Апр 2014 в 13:50

Чтобы получить каждую пятую запись, попробуйте следующее:

select *
  from tblHistory
 where id % 5 = 0

Поэтому, если вы хотите получить около 100 записей, попробуйте что-нибудь вроде этого:

select *
  from tblHistory
 where id % (select round(count(*)/100,0) from tblHistory) = 0

Где вы берете количество записей в tblHistory, делите его на 100 и используете это как количество записей, которые нужно пропускать каждый раз

2
Brett Schneider 30 Апр 2014 в 13:49

Это двухэтапный процесс:

  1. Найдите знаменатель дроби в строке ... множитель строки. Если вы хотите 1 из каждых 2 строк, вам понадобится 2. Если вы хотите 1 из каждых 5 строк, это 5. Предполагается, что вы берете достаточно малую выборку, в которой числитель всегда будет 1. Если вы хотите что-то вроде 2 из каждых 3 строк, это значительно изменится.
  2. Выберите строки, соответствующие этому фактору

Вы можете объединить оба шага в один оператор:

select *
from (
   select *, row_number() over (order by Added) Row
   from tblHistory
) h
where h.Row % (SELECT ceiling(COUNT(*) / cast(@DesiredRows as float)) As RowFactor FROM tblHistory) = 0
2
Joel Coehoorn 30 Апр 2014 в 13:56

Если вы действительно хотите получить всего 100 строк со всей таблицы, отсортированных по Added, вы можете использовать этот код:

WITH GroupedData AS
(
    SELECT 
        h.ID, h.Added, h.Value1, h.Value2,
        GroupNo = NTILE(100) OVER(ORDER BY Added DESC)
    FROM dbo.tblHistory
), 
GroupedDataWithRownum AS
(
    SELECT 
        ID, Added, Value1, Value2,
        RowNum = ROW_NUMBER() OVER (PARTITION BY GroupNo ORDER BY Added DESC)
    FROM GroupedData
)
SELECT * 
FROM GroupedDataWithRownum
WHERE ROwNUm = 1

Первый CTE GroupedData добавляет GroupNo от 1 до 100 к каждой строке вашей таблицы, в основном разделяя вашу таблицу на 100 более или менее равных групп строк.

Второй CTE GroupedDataWithRownum затем добавляет последовательные числа в каждую группу - начиная с 1.

Поэтому, если вы хотите получить первую запись для каждой из 100 определенных групп - просто выберите из второго CTE с помощью RowNum = 1 и вуаля - вы получите ровно 100 строк, красиво распределенных по вашей таблице - и это работает независимо от того, как много строк в исходной таблице.

1
marc_s 30 Апр 2014 в 13:59

Вот рабочая скрипка, которая никоим образом не оптимизировалась, но с которой можно работать:

SQL Fiddle

SELECT * FROM tblHistory
WHERE ID in (    
    SELECT min(ID) as Id 
    FROM
    (
      SELECT ID, ntile(100) OVER(ORDER BY Id) AS ntile_rank
      FROM (SELECT DISTINCT Id FROM tblHistory) AS History
) AS ranking
GROUP BY ntile_rank)

Это в основном разбивает ваш набор результатов на 100 блоков с помощью функции ntile, а затем с использованием первого Id для каждого блока для фильтрации вашего списка.

1
Tanner 30 Апр 2014 в 14:00