Sql server 如何在SQLServer2008R2中不使用游标编写此查询?

Sql server 如何在SQLServer2008R2中不使用游标编写此查询?,sql-server,select,sql-server-2008-r2,Sql Server,Select,Sql Server 2008 R2,我有这个ScoreDetails表,有两列,还有更多,但是这个查询只需要两列。一个是记分日期,记分 结构就像 2012:03:27: 5:06:37:134 27 2012:03:27: 5:06:37:276 37 2012:03:28: 4:12:97:019 19 2012:03:29: 7:06:37:134 7 2012:03:29: 8:06:37:134 0 2012:04:03:

我有这个ScoreDetails表,有两列,还有更多,但是这个查询只需要两列。一个是记分日期,记分

结构就像

2012:03:27: 5:06:37:134           27
2012:03:27: 5:06:37:276           37
2012:03:28: 4:12:97:019           19
2012:03:29: 7:06:37:134           7
2012:03:29: 8:06:37:134           0
2012:04:03: 12:06:37:739          16
2012:04:04: 23:21:15:834          33
2012:04:04: 15:08:24:697          12
2012:04:06: 5:06:37:134           0
2012:04:09: 5:06:37:134           2
2012:04:13: 5:06:37:134           92
我想要的是编写一个select查询,而不使用临时表或游标。这样,我有一个列,从1开始,一直增加到2,3,以此类推,直到分数为非零。但一旦分数列中出现零,它就会重置为1,然后重新开始。像这样

2012:03:27: 5:06:37:134           27       1
2012:03:27: 5:06:37:276           37       2
2012:03:28: 4:12:97:019           19       3
2012:03:29: 7:06:37:134           7        4
2012:03:29: 8:06:37:134           0        0
2012:04:03: 12:06:37:739          16       1
2012:04:04: 23:21:15:834          33       2
2012:04:04: 15:08:24:697          12       3
2012:04:06: 5:06:37:134           0        0
2012:04:09: 5:06:37:134           2        1
2012:04:13: 5:06:37:134           92       2

我使用的是SQL Server 2008 R2。

我不会破坏自己寻找解决方案的乐趣,但我将为您提供一些关于如何将问题分解为更小部分的提示:

查找重置分数的所有记录。让我们将此子查询称为resetRecords。 将原始表的记录连接到resetRecords,这样每个记录都有其重置记录,即为其计数提供基础的重置记录。 用于分配数字。
试着一步一步地做这件事。注意:这不是一个简单的查询,因此使用临时表或游标的解决方案可能更容易理解和维护。

您可以使用通用表表达式来实现这一点。我定义了两个锚查询:一个用于得分为0的记录,另一个用于第一条记录。然后根据以前的结果建立结果,直到找到0分

with cte
as
(
  select ScoreDate, Score, ScoreRank, 0 as Value
  from (select ScoreDate, Score, dense_rank() over (order by ScoreDate) ScoreRank
        from ScoreDetails) X
  where Score = 0

  union all

  select ScoreDate, Score, ScoreRank, 1 as Value
  from (select ScoreDate, Score, dense_rank() over (order by ScoreDate) ScoreRank
        from ScoreDetails) X
  where Score <> 0 and ScoreRank = 1

  union all

  select X.ScoreDate, X.Score, X.ScoreRank, cte.Value + 1 as Value
  from (select ScoreDate, Score, dense_rank() over (order by ScoreDate) ScoreRank
        from ScoreDetails) X
  inner join cte
  on X.ScoreRank = cte.ScoreRank + 1
  and X.Score <> 0
)

select ScoreDate, Score, Value, ScoreRank
from cte
order by ScoreDate

试着这样做:

with x as (
select *, sum(case when Score=0 then 1 else 0 end) over(order by ScoreDate) as grp
from ScoreDetails
)
select ScoreDate, Score, row_number() over (partition by grp order by ScoreDate)
from x
order by ScoreDate

一旦分数列中出现零,它将重置为1,然后重新开始,您说

您可能想看看CTEs:谢谢,这就完成了。但是你能解释一下第三部分发生了什么吗?我是指cte内部的最后一个查询,它与cte本身有内部连接?它直冲着我的头。如何将cte连接到cte本身内部的查询?这就是cte以递归方式工作的方式。在您的问题下方的评论中有一个链接,指向解释CTE的MSDN页面。读一读就会更清楚。