T-SQL для поиска последовательных возрастающих значений - PullRequest
4 голосов
/ 08 ноября 2011

Допустим, у меня есть следующая очень простая схема:

Create Table MyTable (
   PrimaryKey int,
   Column1 datetime.
   Column2 int
)

Мне нужен запрос, который упорядочивает данные на основе Column1 и находит первые 10 последовательных строк, где значение Column2 в текущей строке больше, чем значение column2 в предыдущей строке.

1 Ответ

5 голосов
/ 09 ноября 2011

Q используется для получения значения рейтинга rn, упорядоченного по Column1.Добавлен в PrimaryKey, если есть связи в Column1.C - это рекурсивный CTE, который зацикливается сверху, упорядоченным по rn с увеличением cc для каждого возрастающего значения Column2.Он прервется из рекурсии, когда cc достигнет 10. Наконец, получите последние 10 строк из C.Предложение where учитывает случай, когда нет 10 последовательных увеличивающихся значений.

with Q as
(
  select PrimaryKey,
         Column1,
         Column2,
         row_number() over(order by Column1, PrimaryKey) as rn
  from MyTable
),
C as
(
  select PrimaryKey,
         Column1,
         Column2,
         rn,
         1 as cc
  from Q
  where rn = 1
  union all
  select Q.PrimaryKey,
         Q.Column1,
         Q.Column2,
         Q.rn,
         case 
           when Q.Column2 > C.Column2 then C.cc + 1
           else 1
         end  
  from Q
    inner join C
      on Q.rn - 1 = C.rn
  where C.cc < 10     
)
select top 10 *
from C
where 10 in (select cc from C)
order by rn desc
option (maxrecursion 0)

Версия 2 Как Martin Smith , указанный в комментарииВышеупомянутый запрос имеет действительно плохую производительность.Виновником является первый CTE.Версия ниже использует переменную таблицы для хранения ранжированных строк.Директива primary key для rn создает индекс, который будет использоваться в соединении в рекурсивной части запроса.Помимо табличной переменной это делает то же самое, что и выше.

declare @T table
(
   PrimaryKey int,
   Column1 datetime,
   Column2 int,
   rn int primary key
);

insert into @T
select PrimaryKey,
       Column1,
       Column2,
       row_number() over(order by Column1, PrimaryKey) as rn
from MyTable;

with C as
(
  select PrimaryKey,
         Column1,
         Column2,
         rn,
         1 as cc
  from @T
  where rn = 1
  union all
  select T.PrimaryKey,
         T.Column1,
         T.Column2,
         T.rn,
         case 
           when T.Column2 > C.Column2 then C.cc + 1
           else 1
         end  
  from @T as T
    inner join C
      on T.rn = C.rn + 1
  where C.cc < 10     
)
select top 10 *
from C
where 10 in (select cc from C)
order by rn desc
option (maxrecursion 0)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...