2016-04-02 59 views
1

嘗試在update語句中使用用戶定義函數更新表時出現問題。SQL Server - 如何正確使用用戶定義的函數更新表在更新語句中?

我大大簡化了現有的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] 

回答

3

這是一個評論太長了一些簡單的示例代碼。

update聲明作爲單個事務完成。這意味着在提交事務之前對錶的更改不可見。

您的代碼似乎假定更新一次提交一行 - 每次調用該函數都會看到不同的表格版本。但是,這不是SQL的工作原理。更新正在執行時,對錶的任何引用都會看到「舊」值。在提交發生之前,「新」值不明顯。

+0

事實上,一個事務可以看到自己的修改,這個問題大概是語句級別Haloween保護。 –

+0

是的,我認爲必須是這種情況,只有在更新聲明完成之後才能看到更改。那麼,我怎樣才能以不同的方式編寫這個查詢來獲得我期待的結果呢?在我提供的簡單示例中,我使用了300行,但真正的代碼將每分鐘更新1000行。所以我正在尋找一些相當有效的東西。 –

+0

我可以通過使用遊標並一次循環一行來獲得此功能,但我認爲必須有一種更高效的快速方法來完成此操作? –

相關問題