sql服务器计数表中的递归

时间:2018-11-06 09:17:00

标签: sql-server

我现在拥有的是这样的表

Sub foo() Dim rng As Range retry: Set rng = Application.InputBox("Please choose a range", "Obtain Range Object", Type:=8) If MsgBox("Your choice " & rng.Address & " ?", vbYesNo, "Confirm") = vbYes Then GoTo continue: Else GoTo retry: End If continue: rng.Copy Worksheets("Sheet2").Range("A1").PasteSpecial xlPasteAll End Sub

我需要一个新的colum,我将其称为Cycle,它能够“计数”状态从0到不同于0的任何次数(表示此描述的机器进程的开始)并保持不同于0的次数。 (当它返回到0时,它定义进程已完成一个周期)。 我试图使用与变量绑定的计数器来分配一个值,该值根据状态值逐行更改,以将值分配给循环列。

Visual Studio不允许我尝试说固定值已分配给该列,因此它无法分配该值。

有人建议使用排名功能,但我从MS文档中无法清楚地了解它的工作原理,从而无法解决该问题

4 个答案:

答案 0 :(得分:2)

必须有一个更漂亮的方法来执行此操作,但此刻我很沮丧。我用您的示例数据创建了一个表变量,您所说的此附加列包含一个日期,可用于订购。由于我缺乏想象力,因此我改用int,但逻辑应该起作用。

declare @t table (Status int not null, Cycle int not null, ReallyDate int not null)
insert into @t(Status,Cycle,ReallyDate) values
(0,0,1 ),    (2,1,2 ),    (5,1,3 ),    (6,1,4 ),    (2,1,5 ),    (3,1,6 ),
(0,1,7 ),    (1,2,8 ),    (2,2,9 ),    (5,2,10),    (3,2,11),    (0,2,12),
(0,2,13),    (0,2,14),    (1,3,15),    (2,3,16),    (2,3,17),    (5,3,18),
(6,3,19),    (2,3,20),    (5,3,21),    (3,3,22),    (0,3,23);

With Numbered as (
    select
        *,
        ROW_NUMBER() OVER (ORDER BY ReallyDate) as rn
    from @t
), Roots as (
    select
        t1.*,
        ROW_NUMBER() OVER (ORDER BY t1.ReallyDate) as CyclePrime
    from
        Numbered t1
            left join
        Numbered t2
            on
                t1.rn = t2.rn - 1 and
                t2.Status = 0
    where
        t1.Status = 0 and
        t2.rn is null
)
select
    n.*,
    COALESCE(r.CyclePrime,0) as Cycle
from
    Numbered n
        left join
    Roots r
        left join
    Roots r_anti
        on
            r_anti.CyclePrime = r.CyclePrime + 1
        on
            n.rn > r.rn and
            n.rn <= r_anti.rn

当然,我的数据已经有一个我可以使用的列,而不是Numbered CTE,但是您有一个datetime列,并且需要生成类似rn的内容。

然后Roots是一个棘手的人。它标识了0行,紧接着没有其他0行。这些我们用来分配周期号。

在最后一个选择中,我们尝试将正在处理的任何行连接到上一个Root行,并从该行中获取循环号。

结果(包括奖金栏):

Status      Cycle       ReallyDate  rn                   Cycle
----------- ----------- ----------- -------------------- --------------------
0           0           1           1                    0
2           1           2           2                    1
5           1           3           3                    1
6           1           4           4                    1
2           1           5           5                    1
3           1           6           6                    1
0           1           7           7                    1
1           2           8           8                    2
2           2           9           9                    2
5           2           10          10                   2
3           2           11          11                   2
0           2           12          12                   2
0           2           13          13                   2
0           2           14          14                   2
1           3           15          15                   3
2           3           16          16                   3
2           3           17          17                   3
5           3           18          18                   3
6           3           19          19                   3
2           3           20          20                   3
5           3           21          21                   3
3           3           22          22                   3
0           3           23          23                   3

答案 1 :(得分:2)

我认为以下是您所追求的:

  • 根据项目的顺序生成顺序ID(GeneratedId);这样,我们可以通过在当前值上加1来判断表中的下一条记录是什么;因此我们可以轻松地逐步浏览查询中的记录。
  • 按顺序浏览记录,每次我们找到先前记录的status=0和当前记录的status=1时,将一个添加到循环计数器;对于所有其他值,请取上一条记录的计数器值。

小提琴示例:https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=c89c13ede9fe5b752368ded49e7a1c3d

create table TestData
(
    DateOrder datetime not null
    , StatusId int not null
)
insert TestData(DateOrder, StatusId)
values ('2018-11-06 01:00', 0)
, ('2018-11-06 02:00', 1)
, ('2018-11-06 03:00', 2)
, ('2018-11-06 04:00', 0)
, ('2018-11-06 05:00', 0)
, ('2018-11-06 06:00', 0)
, ('2018-11-06 07:00', 2)
, ('2018-11-06 08:00', 1)
, ('2018-11-06 09:00', 3)
, ('2018-11-06 10:00', 0)
, ('2018-11-06 11:00', 1)

;with cte (DateOrder, StatusId, GeneratedId) as 
(
    select DateOrder, StatusId, row_number() over (order by DateOrder) GeneratedId
    from TestData
)
, cte2 (DateOrder, StatusId, GeneratedId, Cycle) as
(
    select DateOrder, StatusId, GeneratedId, 0 
    from cte
    where GeneratedId = 1

    union all

    select cte.DateOrder, cte.StatusId, cte.GeneratedId
    , case 
        when cte2.StatusId = 0 and cte.StatusId != 0 then cte2.Cycle + 1  
        else cte2.Cycle 
    end Cycle
    from cte2
    inner join cte 
    on cte.GeneratedId = cte2.GeneratedId + 1
)
select * from cte2 order by DateOrder

答案 2 :(得分:0)

SELECT SUM(循环) FROM表名;

答案 3 :(得分:-1)

选择计数(DISTINCT循环) 周期> 0   FROM表名