Twee vragen, één oplossing

De afgelopen weken kreeg ik van twee verschillende klanten een vrijwel identieke vraag. De ene klant wilde een uitbreiding in een bestaand programma om bij een bepaalde datum de eerstvolgende werkdag te bepalen. De andere wilde in een document een datum afdrukken waarop uiterlijk gereageerd kan worden. Voor deze datum geldt als regel dat men 20 dagen de tijd krijgt om te reageren. Als oplossing voor beide vragen heb ik een SQL functie gebruikt.

UDF

User Defined Functies zijn mogelijk vanaf SQL Server 2000.  Tot nu toe heb ik hier echter maar sporadisch gebruik van gemaakt.  Voor deze toepassing leek een functie me echter wel heel geschikt.  Als je gaat rekenen met werkdagen zijn er echter wel een paar dingen waar je rekening mee moet houden.

Hoezo dag 1?

Met de SQL functie Datepart kun je oa. bepalen wat het dagnummer is van een bepaalde datum. Het eerste waar je dan tegenaan loopt, is dat de dagnummers per server kunnen verschillen. Soms is zondag dag 1, soms kiest men voor maandag.  Ik heb dat opgelost door voor een datum waarvan ik weet dat het een maandag is, het dagnummer te bepalen. Ook kun je hiervoor de standaardfunctie @@Datefirst gebruiken.

Feestdagen

Verder is het handig om bij het bepalen van de feestdagen rekening te houden met de feestdagen. Eén van beide databases had al een tabel met feestdagen. In de andere database heb ik zo’n tabel toegevoegd. In principe volstaat hiervoor een tabel met twee kolommen: datum + omschrijving. Feestdagen die in het weekend vallen kun je buiten beschouwing laten.

Recursief

Wat deze functie doet is eerst het gewenste aantal werkdagen bij de startdatum optellen en vervolgens controleren of er in die periode nog een doordeweekse feestdag valt. Als dit zo is, wordt de functie opnieuw aangeroepen, net zo lang tot je het gewenste aantal dagen hebt bereikt.

CREATE FUNCTION [dbo].[BepaalDatumPlusAantalWerkdagen](@StartDatum datetime, @Werkdagen int)
 
returns datetime
AS
BEGIN
	DECLARE @BeginVanDeWeek datetime,
		@DagenVoor	int,
		@EindDatum	datetime,
		@Feestdagen	int,
		-- maandag kan dag 1 of dag 2 zijn: dit is serverafhankelijk
		@maandag	int,
		@vrijdag	int
 
		-- 28-12-2009 valt op een maandag
	SET	@maandag = Datepart(weekday,'20091228')
	SET	@vrijdag = @maandag + 4
 
	SET	@DagenVoor	= (DATEPART(dw,@StartDatum) + @@datefirst - 2)%7
		-- bepaal de maandag van de startweek
	SET	@BeginVanDeWeek = @StartDatum - @DagenVoor
	SET	@Werkdagen	= @Werkdagen +
		CASE
		WHEN	@DagenVoor kleiner_dan 5
                THEN	@DagenVoor
                ELSE	4
                END
 	SET	@EindDatum = @BeginVanDeWeek + @Werkdagen/5*7 + @Werkdagen%5
        SELECT	@Feestdagen =  count (*)
        FROM	DBO.tblFeestdag
        WHERE	Datum groter_dan @StartDatum
	AND	Datum  kleiner_dan = @EindDatum
        -- feestdag in weekend hier niet meetellen
        AND	Datepart(weekday,datum) BETWEEN @maandag AND @vrijdag
        IF	@Feestdagen groter_dan 0
		BEGIN
			SET @Einddatum = DBO.BepaalDatumPlusAantalWerkdagen(@EindDatum, @Feestdagen)
		END
 
	RETURN @Einddatum
END
 
-- test
-- SELECT Datum = DBO.BepaalDatumPlusAantalWerkdagen('20091225', 1)

PS: wanneer je bovenstaande code wilt gebruiken, vervang dan de woorden kleiner_dan en groter_dan door < en >:

En de klanten: hoe is het daarmee afgelopen? Doordat ik deze ene functie voor beide applicaties kan gebruiken, denk ik dat ik op tijd kan opleveren, zodat ik in ieder geval niet hoef te werken tijdens de feestdagen.

Stem of voeg toe aanUitleg over het gebruik van deze icons :Voeg dit artikel toe aan Del.icio.us Voeg toe aan je Google bladwijzers Plaats dit bericht op Twitter Geef dit als tip aan je Hyves-vrienden Voeg toe aan je Facebook-profiel Deel met je LinkedIn-contacten Abonneer je op de RSS-feed van deze site Verstuur deze pagina per e-mail via Feedburner Print deze pagina of genereer een PDF-bestand