假设我有以下非常简单的架构:
Create Table MyTable (
PrimaryKey int,
Column1 datetime.
Column2 int
)
我需要一个基于Column1对数据进行排序的查询,并查找前10行,其中当前行中Column2的值大于前一行中column2的值。
答案 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)