2016-04-02 8 views
1

Fehler beim Versuch, eine Tabelle mithilfe einer benutzerdefinierten Funktion in der Update-Anweisung zu aktualisieren.SQL Server - Wie Aktualisieren der Tabelle mit benutzerdefinierter Funktion in Update-Anweisung?

Ich habe mein vorhandenes SQL stark vereinfacht und einen Beispielcode zur Verfügung gestellt, um das Problem zu zeigen, das ich sehe.

Ich beginne mit 300 Zeilen in einer Testtabelle alle mit dem gleichen Zeitstempel Wert

ich zu einer Gruppe muß die 300 Zeilen in MyTestTable in 3 Sätze von 100 Zeilen mit demselben Zeitstempel aus

Was ich will, so etwas zu sehen ist:

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

Was ich jetzt sehen, ist alle 300 Zeilen mit dem gleichen Zeitstempel aktualisiert:

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

Was ist der beste Weg, um diese Abfrage zu formulieren?

Nachfolgend finden Sie einige vereinfachte Beispielcode, der das Problem für einen Kommentar

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] 

Antwort

3

Das ist zu lang wiedergibt.

Eine update-Anweisung wird als einzelne Transaktion abgeschlossen. Das bedeutet, dass die Änderungen an der Tabelle erst sichtbar werden, wenn die Transaktion festgeschrieben wurde.

Ihr Code scheint davon auszugehen, dass das Update eine Zeile nach der anderen festlegt - dass bei jedem Aufruf der Funktion eine andere Version der Tabelle angezeigt wird. Aber so funktioniert SQL nicht. Während das Update ausgeführt wird, werden bei jedem Verweis auf die Tabelle die "alten" Werte angezeigt. Die "neuen" Werte sind nicht ersichtlich, bis das Commit stattfindet.

+0

Tatsächlich kann eine Transaktion ihre eigenen Änderungen sehen, das Problem ist vermutlich Anweisung Haloween Protection. –

+0

Ja, ich dachte, dass das der Fall sein muss, dass Änderungen nicht sichtbar sind, bis die Update-Anweisung abgeschlossen ist. Wie könnte ich diese Abfrage anders schreiben, um die gewünschten Ergebnisse zu erhalten? In dem einfachen Beispiel, das ich zur Verfügung gestellt habe, habe ich 300 Zeilen verwendet, aber der echte Code aktualisiert jede Minute 1000 Zeilen. Ich suche also etwas ziemlich Effektives. –

+0

Ich kann dies mit einem Cursor und der Schleife durch eine Zeile zu arbeiten, aber ich denke, es muss einen effizienteren schnelleren Weg, dies zu erreichen? –

Verwandte Themen