none
Datum vergleichen RRS feed

  • Frage

  • Hey,

    ich habe über einen Trigger einen Status zu setzten. Dieser ist von verschiedenen Eigenschaften in der Tabelle abhängig.

    Eine IF/ELSE - Verzweigungen würde mich tierisch voranbringen, kann ich die verwenden und wenn ja wie? Im Moment mache ich x-UpdateStatements hintereinander, so dass das letzte trifft, das kann aber doch nicht Sinn und Zweck sein ODER???

    Außerdem habe ich das Problem, dass ich ein Datum auf 21 Jahre und einen Tag prüfen muss. 21 Jahre ist kein Problem:

    UPDATE Projekt
    SET Status = 'Erledigt'
    From Projekt
    Where Projekt.Anfang < (SELECT DATEADD(year, -21, GETDATE()))

    aber was mache ich mit dem einen Tag extra?

    Für Hilfe immer dankbar

    motofish

     

    Donnerstag, 27. Mai 2010 14:34

Antworten

  • Hallo motofisch,

    in der Form lässt sich das mit einem CASE Ausdruck erschlagen:

    UPDATE dbo.Projekte
    SET StatusGL = 
    	CASE 
    		WHEN Projekte.Zuruecknahme = 1 
    			OR Projekte.Anmeldetag < (DATEADD(day, -1,(DATEADD(year, -21, GETDATE())))
    			THEN 'Tot'
    		WHEN Projekte.Nichtgk = 1 THEN 'Nichtigk. / Löschung'
    		WHEN /*??? AktenExt. ???*/ Beschwerde = 1 THEN 'Beschwerde'
    		WHEN Projekte.Einspruch = 1 IS NOT NULL THEN 'Einspruch'
    		WHEN Projekte.Erteilungsdatum IS NOT NULL THEN 'Erteilt'
    		WHEN Projekte.Anmeldetag IS NOT NULL THEN 'Angemeldet' 
    		ELSE 'Offen' 
    	END
    -- Für Trigger (INSERTED/UPDATED
    -- ID ist der Primary/Unique Key der Tabelle
    WHERE Projekte.ID IN (SELECT i.ID FROM inserted)
    
    
    
    

    Ich habe die Reihenfolge umgedreht, da CASE WHEN von oben nach unten ausgewertet wird.
    "Gewinnen" wird also der Ausdruck, der als erster zutrifft und wenn keiner der ELSE-Zweig.

    Für einen Trigger sollte zusätzlich INSERTED abgefragt werden.

    Wobei Du diesen Ausdruck auch als Ausdrucks-Spalte in einer Sicht
    oder selbst in der Tabelle hinterlegen kannst - wobei GETDATE() nicht
    deterministisch ist und ich letzteres deswegen nicht empfehlen würde.

    Wenn man die Spalte nur gelegentlich sehen muß/will,
    wäre eine Sicht einem Trigger vorzuziehen.

    Gruß Elmar

    Donnerstag, 27. Mai 2010 20:12
  • Hallo motofisch,

    der Tag ist erledigt, in dem man DATEADD zweimal verwendet (und das SELECT überflüssig):

    WHERE Projekt.Anfang < DATEADD(Day, 1, DATEADD(year, -21, GETDATE()))

    (wobei GETDATE() auch die aktuelle Uhrzeit enthält).

    Allerdings ist eine Aktualisierungsabfrage in einem Trigger, die nicht auf inserted (oder deleted)
    zurückgreift kaum zu empfehlen, da sie auf alle Zeilen (für die die Bedingung zutrifft) zugreift.
    Das fordert Blockierungen und Deadlocks geradezu heraus.

    Um die Abfrage auf die veränderten Projekt-Zeilen zu beschränken,
    ergänze die Bedingung um eine Abfrage auf den Primärschlüssel:

    WHERE Projekt.ID IN (SELECT i.id FROM inserted AS i)
    	AND Projekt.Anfang < (SELECT DATEADD(year, -21, GETDATE()))
    
    
    (vorausgesetzt der Trigger ist auf Projekt selber und die Primärschlüsselspalte heisst ID).

    Alle weitere Bedingungen kannst Du mit AND/OR und ggf. via weitere JOINS, CASE usw.
    einbauen. Um das konkreter zu beschreiben, müsste man Deine Bedingungen kennen.

    Gruß Elmar

    Donnerstag, 27. Mai 2010 16:50

Alle Antworten

  • Hallo motofisch,

    der Tag ist erledigt, in dem man DATEADD zweimal verwendet (und das SELECT überflüssig):

    WHERE Projekt.Anfang < DATEADD(Day, 1, DATEADD(year, -21, GETDATE()))

    (wobei GETDATE() auch die aktuelle Uhrzeit enthält).

    Allerdings ist eine Aktualisierungsabfrage in einem Trigger, die nicht auf inserted (oder deleted)
    zurückgreift kaum zu empfehlen, da sie auf alle Zeilen (für die die Bedingung zutrifft) zugreift.
    Das fordert Blockierungen und Deadlocks geradezu heraus.

    Um die Abfrage auf die veränderten Projekt-Zeilen zu beschränken,
    ergänze die Bedingung um eine Abfrage auf den Primärschlüssel:

    WHERE Projekt.ID IN (SELECT i.id FROM inserted AS i)
    	AND Projekt.Anfang < (SELECT DATEADD(year, -21, GETDATE()))
    
    
    (vorausgesetzt der Trigger ist auf Projekt selber und die Primärschlüsselspalte heisst ID).

    Alle weitere Bedingungen kannst Du mit AND/OR und ggf. via weitere JOINS, CASE usw.
    einbauen. Um das konkreter zu beschreiben, müsste man Deine Bedingungen kennen.

    Gruß Elmar

    Donnerstag, 27. Mai 2010 16:50
  • Hallo Elmar,

    vielen Dank für die Antwort. 

    Das mit den Deadlocks ist eines der Probleme, die ich durchaus sehe. Ich arbeite mich in die Thematik Trigger und Co. erst ein und gehe Schritt für Schritt vor. Ich habe gelesen, dass man auf den bearbeiteten Datensatz über die Tabelle inserted zugreifen kann. Damit könnte ich immer nur auf den Datensatz zugreifen, den ich benötige. Lt. Anleitung ist inserted auch im Fall des Updatetriggers zugreifbar.

    Leider habe ich bisher noch NIE einen erfolgreichen Zugriff auf inserted mit anschließender Verwendung in dem Update-Statement geschafft.

    Konkret:

    meine Projekte haben die Stati 'Begonnen', 'in Arbeit', und 'Erledigt. Die Einträge werden gesetzt, wenn der Beginn 21 Jahre und 1 Tag zurückliegt -> Erledigt, wenn Bit 'unterwegs' gesetzt ist -> in Arbeit bzw. Wenn dies alles nicht und nur das Anfangsdatum eingetragen ist -> 'Begonnen'

    Das ist ein sehr rudimentäres Beispiel, das aber in etwa mein Problem abbildet. Am liebsten würde ich jetzt mit If arbeiten, habe aber keine Möglichkeit in Triggern bzw. T-SQL gefunden. Ich könnte mir schon vorstellen, eine Stored Procedure zu schreiben, bin aber in dem Thema noch gar nicht drin. Sollte eigentlich erst  später kommen.

    Wenn hier noch ein Tipp möglich wäre, wie ich weiterkomme wäre klasse!

     

    Danke

    motofish

     

     

    Donnerstag, 27. Mai 2010 18:40
  • Hallo motofisch,

    bevor ich jetzt versuche, Deinen Absatz zu verstehen und in SQL umzusetzen,
    poste doch bitte was Du bisher hast. (Auch Anfänger-)Code ist da häufig eindeutiger.

    Gruß Elmar

    Donnerstag, 27. Mai 2010 18:59
  •  

    CREATE TRIGGER [dbo].[tr_StatusGL_Insert_Update] ON [dbo].[Projekte]
    FOR INSERT, UPDATE
    AS
    BEGIN
       SET NOCOUNT ON;
    
    
    Update dbo.Projekte
    SET StatusGL = 'Offen'
    
    Update dbo.Projekte
    SET StatusGL = 'Angemeldet'
    From dbo.Projekte
    Where Projekte.Anmeldetag IS NOT NULL
    
    Update dbo.Projekte
    SET StatusGL = 'Erteilt'
    From dbo.Projekte
    Where Projekte.Erteilungsdatum IS NOT NULL
    
    Update dbo.Projekte
    SET StatusGL = 'Einspruch'
    From dbo.ProjekteWhere Projekte.Einspruch = 1
    
    Update dbo.Projekte
    SET StatusGL = 'Beschwerde'
    From dbo.Projekte
    Where AktenExt.Beschwerde = 1
    
    
    Update dbo.Projekte
    SET StatusGL = 'Nichtigk. / Löschung'
    From dbo.Projekte
    Where Projekte.Nichtgk = 1
    Update dbo.Projekte
    SET StatusGL = 'Tot'
    From dbo.Projekte
    Where Projekte.Zuruecknahme = 1
    
    Update dbo.Projekte
    SET StatusGL = 'Tot'
    From dbo.Projekte
    Where Projekte.Anmeldetag < (DATEADD(day, -1,(DATEADD(year, -21, GETDATE())))
    
    END

    So sieht das nu bei mir im Moment aus und ist sicherlich nicht das gelbe vom Ei. Aber danke für die Ermutigung mit dem Anfängercode ...

     

    Gruß

    motofish

     

    Donnerstag, 27. Mai 2010 19:09
  • Hallo motofisch,

    in der Form lässt sich das mit einem CASE Ausdruck erschlagen:

    UPDATE dbo.Projekte
    SET StatusGL = 
    	CASE 
    		WHEN Projekte.Zuruecknahme = 1 
    			OR Projekte.Anmeldetag < (DATEADD(day, -1,(DATEADD(year, -21, GETDATE())))
    			THEN 'Tot'
    		WHEN Projekte.Nichtgk = 1 THEN 'Nichtigk. / Löschung'
    		WHEN /*??? AktenExt. ???*/ Beschwerde = 1 THEN 'Beschwerde'
    		WHEN Projekte.Einspruch = 1 IS NOT NULL THEN 'Einspruch'
    		WHEN Projekte.Erteilungsdatum IS NOT NULL THEN 'Erteilt'
    		WHEN Projekte.Anmeldetag IS NOT NULL THEN 'Angemeldet' 
    		ELSE 'Offen' 
    	END
    -- Für Trigger (INSERTED/UPDATED
    -- ID ist der Primary/Unique Key der Tabelle
    WHERE Projekte.ID IN (SELECT i.ID FROM inserted)
    
    
    
    

    Ich habe die Reihenfolge umgedreht, da CASE WHEN von oben nach unten ausgewertet wird.
    "Gewinnen" wird also der Ausdruck, der als erster zutrifft und wenn keiner der ELSE-Zweig.

    Für einen Trigger sollte zusätzlich INSERTED abgefragt werden.

    Wobei Du diesen Ausdruck auch als Ausdrucks-Spalte in einer Sicht
    oder selbst in der Tabelle hinterlegen kannst - wobei GETDATE() nicht
    deterministisch ist und ich letzteres deswegen nicht empfehlen würde.

    Wenn man die Spalte nur gelegentlich sehen muß/will,
    wäre eine Sicht einem Trigger vorzuziehen.

    Gruß Elmar

    Donnerstag, 27. Mai 2010 20:12
  • Hallo Elmar,

     

    vielen Dank, es ist immer wieder erhebend Deine Antworten zu lesen!

     

    motofish

    Donnerstag, 27. Mai 2010 21:22