none
Ungültige Verwendung des Operators mit Nebenwirkungen RRS feed

  • Frage

  • Hallo,

    ich habe eine einfache UDF erstellt, welche mir eine Tabelle mit Monaten zwischen einem Start und Enddatum wiedergeben soll.

    Beim Ausführen wird vom SQL-Server aber die Fehlermeldung:

    Ungültige Verwendung des Operators mit Nebenwirkungen oder Zeitabhängigkeit in 'INSERT' innerhalb einer Funktion.

    gesetzt. 

    Woran könnte das liegen?

    --------------------------------------------------------------------------------------------

    -- Die Funktion gibt eine Tabelle der zwischen Start und End-Datum liegende Monate zurück
    -- (1 Monat = 1 DS)

    CREATE
    FUNCTION ar.TabMonate(@StartDATE datetime = getdate, @EndDATE datetime = getdate)

    RETURNS

     @tabMonate TABLE (ID int primary key NOT NULL, Monat int NOT NULL, Jahr int NOT NULL)

    AS

    BEGIN

    DECLARE
    @ID INT -- Tabellen ID
    DECLARE @EMonat INT -- Ende Monat
    DECLARE @EJahr INT -- Ende Jahr
    DECLARE @AMonat INT -- Aktueller Monat
    DECLARE @AJahr INT
    -- Aktuelles Jahr

    SET @ID = 1
    SET @AMonat = DATEPART(mm,@StartDATE)
    SET @AJahr = DATEPART(yy,@StartDATE)
    SET @EMonat = DATEPART(mm,@EndDATE)
    SET @EJahr = DATEPART(yy,@EndDATE)

    WHILE (@AJahr * 100 + @AMonat <= @EJahr * 100 + @EMonat) -- Alle Monate durchgehen bis Ende Jahr und Monat erreicht ist
    BEGIN

       INSERT INTO tabMonate (ID, Monat, Jahr) VALUES (@ID, @AMonat, @AJahr); -- Aktuelle Werte in der Ergebnis-Tabelle speichern
       SET @AMonat = @AMonat +1; -- Aktuellen Monat inkrementieren 
       if (@AMonat > 12) BEGIN SET @AMonat = 1; SET @AJahr = @AJahr+1; END -- Bei Jahresberschreitung: Monat zurcksetzen und Jahr inkrementieren   
       SET
    @ID = @ID + 1; -- ID inkrementieren
    END
    RETURN;
    END;

    • Bearbeitet perlfred Montag, 21. November 2011 16:12 Formatierung
    Montag, 21. November 2011 14:11

Antworten

  • Hallo!
    Beim INSERT INTO fehlt ein @ vor dem Namen der Tabellenvariablen.

    Hier mal ein ganz anderer Ansatz, um solche Tabellenfunktionen mit verschiedensten Anforderungen zu realisieren! Die ursprüngliche Idee kommt von Steve Kass.

    create function udf_Numbers
    (
     @from as bigint,
     @to as bigint
    )
    returns table with schemabinding
    as
    return
         with
         t0(n) as
                 (
                 select 1
                         union all                                                -- Erzeugt zwei Sätze = 2^0
                 select 1
                 ),
         t1(n) as
                 (
                 select 1                                                        -- Cross Join erzeugt 4 Sätze = 
    2^2
                 from        t0 as a,
                                 t0 as b
                 ),
         t2(n) as
                 (
                 select 1                                                        -- Cross Join erzeugt 16 Sätze = 
    2^4
                 from        t1 as a,
                                 t1 as b
                 ),
         t3(n) as
                 (
                 select 1                                                        -- Cross Join erzeugt 256 Sätze 
    = 2^8
                 from        t2 as a,
                                 t2 as b
                 ),
         t4(n) as
                 (
                 select 1
                 from t3 as a, t3 as b                                -- Cross Join erzeugt 65.536 
    Sätze = 2^16
                 ),
         t5(n) as
                 (
                 select 1 from t4 as a, t4 as b                -- Cross Join erzeugt 
    4.294.967.296 Sätze = 2^32
                 ),
         Numbers(n) as                                                        -- nummeriert die Sätze durch 
    beginnend bei 1
                 (
                 select row_number() over (order by n) as n
                 from t5
                 )
         select @from + n - 1 as n                        -- addiert die laufende Nummer auf 
    den Startwert
         from Numbers
         where n <= @to - @from + 1                        -- so lange die Anzahl der Zeilen 
    eingehalten wird
    go
     Select *
    from udf_Numbers(1, 10000);
    
    --
    -- Erzeuge mir die Daten für die Monate ab Startdatum heute
    --
    Declare @StartDatum datetime = getdate(),
                 @EndeDatum datetime ;
    
    Select @EndeDatum = dateadd(M, 14, @StartDatum);
    
    select dateadd(M,n,convert(char(8),DATEADD(MONTH, DATEDIFF(MONTH, 0,
    @StartDatum), 0),112)) as Kalender
    from dbo.udf_Numbers(1, datediff(MONTH,@StartDatum,@EndeDatum)) ;
     --
    -- Droppe die Funktion wieder
    -- Ignoriere den Fehler, falls Funktion nicht vorhanden
    --
    Begin Try DROP FUNCTION udf_Numbers end Try Begin Catch end Catch;
    

    Einen schönen Tag noch,
    Christoph
    --
    Microsoft SQL Server MVP
    www.insidesql.org/blogs/cmu

    • Als Antwort markiert perlfred Dienstag, 22. November 2011 11:23
    Dienstag, 22. November 2011 10:13

Alle Antworten

  • Hallo!
    Beim INSERT INTO fehlt ein @ vor dem Namen der Tabellenvariablen.

    Hier mal ein ganz anderer Ansatz, um solche Tabellenfunktionen mit verschiedensten Anforderungen zu realisieren! Die ursprüngliche Idee kommt von Steve Kass.

    create function udf_Numbers
    (
     @from as bigint,
     @to as bigint
    )
    returns table with schemabinding
    as
    return
         with
         t0(n) as
                 (
                 select 1
                         union all                                                -- Erzeugt zwei Sätze = 2^0
                 select 1
                 ),
         t1(n) as
                 (
                 select 1                                                        -- Cross Join erzeugt 4 Sätze = 
    2^2
                 from        t0 as a,
                                 t0 as b
                 ),
         t2(n) as
                 (
                 select 1                                                        -- Cross Join erzeugt 16 Sätze = 
    2^4
                 from        t1 as a,
                                 t1 as b
                 ),
         t3(n) as
                 (
                 select 1                                                        -- Cross Join erzeugt 256 Sätze 
    = 2^8
                 from        t2 as a,
                                 t2 as b
                 ),
         t4(n) as
                 (
                 select 1
                 from t3 as a, t3 as b                                -- Cross Join erzeugt 65.536 
    Sätze = 2^16
                 ),
         t5(n) as
                 (
                 select 1 from t4 as a, t4 as b                -- Cross Join erzeugt 
    4.294.967.296 Sätze = 2^32
                 ),
         Numbers(n) as                                                        -- nummeriert die Sätze durch 
    beginnend bei 1
                 (
                 select row_number() over (order by n) as n
                 from t5
                 )
         select @from + n - 1 as n                        -- addiert die laufende Nummer auf 
    den Startwert
         from Numbers
         where n <= @to - @from + 1                        -- so lange die Anzahl der Zeilen 
    eingehalten wird
    go
     Select *
    from udf_Numbers(1, 10000);
    
    --
    -- Erzeuge mir die Daten für die Monate ab Startdatum heute
    --
    Declare @StartDatum datetime = getdate(),
                 @EndeDatum datetime ;
    
    Select @EndeDatum = dateadd(M, 14, @StartDatum);
    
    select dateadd(M,n,convert(char(8),DATEADD(MONTH, DATEDIFF(MONTH, 0,
    @StartDatum), 0),112)) as Kalender
    from dbo.udf_Numbers(1, datediff(MONTH,@StartDatum,@EndeDatum)) ;
     --
    -- Droppe die Funktion wieder
    -- Ignoriere den Fehler, falls Funktion nicht vorhanden
    --
    Begin Try DROP FUNCTION udf_Numbers end Try Begin Catch end Catch;
    

    Einen schönen Tag noch,
    Christoph
    --
    Microsoft SQL Server MVP
    www.insidesql.org/blogs/cmu

    • Als Antwort markiert perlfred Dienstag, 22. November 2011 11:23
    Dienstag, 22. November 2011 10:13
  • Weil DATEPART() nicht deterministisch ist. Nimm MONTH() und YEAR() und dann sollte es gehen.
    Dienstag, 22. November 2011 10:25
    Moderator
  • Hallo Christoph!

    Da muss ich mich wohl schämen! Ein Syntax-Fehler!! Da bin ich von den jetzigen IDE's zu sehr verwöhnt... (wenigstens farblich hätte...)

    Deine Beispiel-Funktion ist so was von flexibel. Ist ja ein richtiger Datensatz-Generator.

    Vielen Dank!

    Fred.

    Dienstag, 22. November 2011 12:59
  • Hallo Stefan!

    war ein Syntaxfehler meinerseits. Das es mit deterministischen Funktionen nicht funktioniert hatte ich auch gelesen, aber niergens eine Auflistung gefunden welche Funktionen deterministisch sind.

    Trotzdem Danke für deine Bemühung(en).

    Fred.

    Dienstag, 22. November 2011 13:04