【问题标题】:Perform logic using a CTE instead of loop使用 CTE 而不是循环执行逻辑
【发布时间】:2019-10-02 17:03:38
【问题描述】:

假设我有一张桌子

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);

在更新某些行时,我需要检查所有先前的行离开 col 以决定当前行,这需要对所有行进行,我已经通过这样的 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 来执行此逻辑。

【问题讨论】:

  • 但请记住,当行得到更新时,它的结果将包含在下一行更新中
  • 简单易懂:当一行正在更新时,最近更新的那些行的记录是同一个查询。
  • 用您正在使用的数据库标记您的问题。期望的结果也会有所帮助。我不明白你想要实现的逻辑。 mylogic_function() 是做什么的?
  • @GordonLinoff 我正在使用 sql server 2008,mylogic_function() 正在检查其他来源的请假记录,并使用上次的 leave_col 数据做出决定,但此列必须具有最新值。
  • 请澄清“更新行时”的含义。在有序查询中可能存在使用秩、密集秩或不同计数的窗口函数。 . ??也许向我们展示输入和预期输出。

标签: sql-server tsql common-table-expression


【解决方案1】:

我不知道您的函数是做什么的,在我的示例中,我创建了一个函数,该函数接受输入并在该数字可被三整除时返回 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 更快:

-- 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;

【讨论】:

    猜你喜欢
    • 2015-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多