SQL Server - 如何在更新语句中使用用户定义的函数正确更新表?

时间:2016-04-02 20:23:54

标签: sql sql-server tsql

尝试使用update语句中的用户定义函数更新表时遇到问题。

我已经大大简化了我现有的SQL,并提供了一些示例代码来展示我所看到的问题。

我从测试表中的300行开始,所有行都具有相同的时间戳值

我需要将MyTestTable中的300行分组为3组,每组100行,时间戳相同

我想看到的是这样的:

Timestamp               Count   
2016-04-01 15:51:00     100  
2016-04-01 15:52:00     100  
2016-04-01 15:53:00     100  

我现在看到的是使用相同时间戳更新了所有300行:

Timestamp               Count  
2016-04-01 15:51:00     300

制定此查询的最佳方法是什么?

下面是一些重现问题的简化示例代码

CREATE TABLE [MyTestTable]
(
    [ID] [int],
    [Timestamp] [smalldatetime]
) ON [PRIMARY]
GO

CREATE FUNCTION [dbo].[fn_MyTestFunction]
     (@StartTime smalldatetime,
      @EndTime smalldatetime,
      @RandomNumberOfSeconds int)
RETURNS smalldatetime
AS
BEGIN
    DECLARE @Timestamp SMALLDATETIME

    -- Find an existing Timestamp between @StartTime and @EndTime in the MyTestTable
    -- with less than 100 rows with that timestamp
    SET @Timestamp = (SELECT TOP 1 [Timestamp] 
                      FROM MyTestTable
                      WHERE [Timestamp] BETWEEN @StartTime AND @EndTime
                      GROUP BY [Timestamp]
                      HAVING COUNT(*) < 100)

    -- If no row found with timestamp between @StartTime and @EndTime
    -- or no timestamp found which has less than 100 rows with that timestamp
    -- Create a timestamp with a time somewhere between @StartTime and @EndTime
    if (@Timestamp is null)
    begin
        set @Timestamp = dateadd(ss, @RandomNumberOfSeconds, @StartTime)
    end

    return @Timestamp
END
GO

declare @Counter int
set @Counter = 0

-- Populate the test table with 300 rows, all initially with the same timestamp value
while @Counter < 300
begin
    insert MyTestTable (ID, [Timestamp]) values (@Counter, 'April 1, 2016')
    set @Counter = @Counter + 1
end

declare @StartTime smalldatetime
declare @EndTime smalldatetime
declare @RandomNumberOfSeconds float
set @RandomNumberOfSeconds = 60

set @StartTime = current_timestamp
set @EndTime = dateadd(minute, 30, @StartTime)

update MyTestTable
   set [Timestamp] = dbo.fn_MyTestFunction(@StartTime, @EndTime, @RandomNumberOfSeconds)

select [Timestamp], count(*) as "Count"
from MyTestTable
group by [Timestamp]

1 个答案:

答案 0 :(得分:3)

评论太长了。

update语句作为单个事务完成。这意味着在提交事务之前,对表的更改是不可见的。

您的代码似乎假设更新一次提交一行 - 每次调用该函数都会看到该表的不同版本。但是,这不是SQL的工作方式。在执行更新时,对表的任何引用都会看到&#34; old&#34;值。 &#34;新&#34;在提交之前,值不明显。