用于查找连续增加值的T-SQL

时间:2011-11-08 17:13:15

标签: sql-server-2008

假设我有以下非常简单的架构:

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

我需要一个基于Column1对数据进行排序的查询,并查找前10行,其中当前行中Column2的值大于前一行中column2的值。

1 个答案:

答案 0 :(得分:5)

Q用于获取rn排序的排名值Column1。如果Column1中存在关联,则在PrimaryKey中添加。 C是一个递归CTE,从rn递增cc的{​​{1}}每个递增值Column2开始,从顶部开始循环。当cc达到10时,它将从递归中断。最后从C获取最后10行。当没有10个连续增加的值时,where子句负责处理这种情况。

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)