Sql server 使用CTE而不是循环执行逻辑

Sql server 使用CTE而不是循环执行逻辑,sql-server,tsql,common-table-expression,Sql Server,Tsql,Common Table Expression,假设我有一张桌子 Declare @table table ( id int, month_col varchar(10), present_col bit, absent_col bit, leave_col bit ); insert in

假设我有一张桌子

Declare @table table
               ( 
                   id int,
                   month_col varchar(10),
                   present_col bit, 
                   absent_col bit,
                   leave_col bit
               );

insert into @table
values (1, 'Jan', 1, 0, 0),
       (2, 'Jan', 1, 0, 0),
       (3, 'Jan', 0, 1, 0),
       (4, 'Jan', 1, 0, 0),
       (5, 'Jan', 0, 1, 0),
       (6, 'Jan', 1, 0, 0),
       (7, 'Jan', 1, 0, 0);
在更新一些行时,我需要检查所有以前的行,以便对当前行作出决定,这需要对所有行都执行,我已经通过类似这样的While循环实现了这一点

while(for all rows)
begin
    update @table
    set l = mylogic_function((select count(leave_col) 
                              from @table 
                              where id<currentrow.ID)) 
    where id = currentrow.ID
end

但是我想用一个CTE来做这个逻辑。

我不知道你的函数是怎么做的,例如,我创建了一个函数,它接受一个输入,当这个数字可以被3整除时返回一个1。显然,您可以根据需要更改逻辑

CREATE FUNCTION dbo.someFunction(@x INT) RETURNS BIT AS BEGIN RETURN (SIGN(@x%3)-1) END;
您不希望使用循环来实现这一点是很好的,但是如果您正在寻找一个使用递归CTE的解决方案,那么该解决方案的性能可能会很差,并且对于您正在尝试的操作来说会过于复杂。设置为基础始终是一条路要走

要获取当前行之前所有行的计数,只需使用以下语法:

COUNT(t.leave_col) OVER (ORDER BY t.Id)
这将返回与上面相同的内容,但速度更快:

ROW_NUMBER() OVER (ORDER BY t.Id)
此查询将执行您正在查找的操作,并且比使用循环或递归CTE更快:


但请记住,当任何一行得到更新时,其结果将包含在下一行更新中。简单理解:当一行使用最近更新的行的记录进行更新时,使用相同的查询。使用您使用的数据库标记您的问题。预期的结果也会有所帮助。我不明白你想要实现的逻辑。mylogic_函数的作用是什么?@GordonLinoff我正在使用sql server 2008,mylogic_函数正在检查来自其他来源的休假记录,并使用上一次休假记录数据做出决定,但此列必须具有最新值。请澄清更新行时的含义。可能有一个窗口函数在有序查询中使用秩、密秩或不同计数??可能会向我们展示输入和预期输出。
-- Sample data
Declare @table table(id int,month_col varchar(10),present_col bit, absent_col bit,leave_col bit);
insert into @table values
(1,'Jan',1,0,0),
(5,'Jan',1,0,0),
(13,'Jan',0,1,0),
(14,'Jan',1,0,0),
(25,'Jan',0,1,0),
(26,'Jan',1,0,0),
(37,'Jan',1,0,0);

-- Solution
WITH Prep(leave_col_count, leave_col) AS 
(
  SELECT ROW_NUMBER() OVER (ORDER BY t.Id), t.leave_col
  FROM   @table AS t
)
UPDATE Prep 
SET    leave_col = dbo.someFunction(Prep.leave_col_count)
FROM   Prep;