CiAgICA8IS0tIExpbmtlZEluIC0tPgogICAgPHNjcmlwdCB0eXBlPSJ0ZXh0L2phdmFzY3JpcHQiPgogICAgICAgIF9saW5rZWRpbl9wYXJ0bmVyX2lkID0gIjEyMzUwNzMiOwogICAgICAgIHdpbmRvdy5fbGlua2VkaW5fZGF0YV9wYXJ0bmVyX2lkcyA9IHdpbmRvdy5fbGlua2VkaW5fZGF0YV9wYXJ0bmVyX2lkcyB8fCBbXTsKICAgICAgICB3aW5kb3cuX2xpbmtlZGluX2RhdGFfcGFydG5lcl9pZHMucHVzaChfbGlua2VkaW5fcGFydG5lcl9pZCk7CiAgICA8L3NjcmlwdD48c2NyaXB0IHR5cGU9InRleHQvamF2YXNjcmlwdCI+CiAgICAgICAgKGZ1bmN0aW9uKCl7dmFyIHMgPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgic2NyaXB0IilbMF07CiAgICAgICAgICAgIHZhciBiID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgic2NyaXB0Iik7CiAgICAgICAgICAgIGIudHlwZSA9ICJ0ZXh0L2phdmFzY3JpcHQiO2IuYXN5bmMgPSB0cnVlOwogICAgICAgICAgICBiLnNyYyA9ICJodHRwczovL3NuYXAubGljZG4uY29tL2xpLmxtcy1hbmFseXRpY3MvaW5zaWdodC5taW4uanMiOwogICAgICAgICAgICBzLnBhcmVudE5vZGUuaW5zZXJ0QmVmb3JlKGIsIHMpO30pKCk7CiAgICA8L3NjcmlwdD4KICAgIDxub3NjcmlwdD4KICAgICAgICA8aW1nIGhlaWdodD0iMSIgd2lkdGg9IjEiIHN0eWxlPSJkaXNwbGF5Om5vbmU7IiBhbHQ9IiIgc3JjPSJodHRwczovL3B4LmFkcy5saW5rZWRpbi5jb20vY29sbGVjdC8/cGlkPTEyMzUwNzMmZm10PWdpZiIgLz4KICAgIDwvbm9zY3JpcHQ+CiAgICA8IS0tIEVuZCBMaW5rZWRJbiAtLT4KICAgIA==
Generic filters
Exact matches only
Search in title
Search in excerpt
Search in content

Arbeitstagkalender

Zur Berechnung von Kennzahlen, die von der genauen Anzahl der Arbeitstage abhängen, ist es notwendig, diese im Modell korrekt abzubilden. Die Bundesländer in Deutschland haben unterschiedlich viele Feiertage, was die Anzahl der Arbeitstage beeinflusst. In diesem Artikel wird gezeigt, wie mit Hilfe der von ETL zur Verfügung gestellten Funktionen dbo.F_BC_Holiday und dbo.F_BC_Holiday2 die Arbeitstage pro Bundesland ermittelt werden können.

Arbeitstagskalender

In manchen Projekten ist es erforderlich, Arbeitstage tagesgenau abzubilden. Dabei sind die arbeitsfreien Tage exakt abzubilden – dies können Samstage, Sonntage und auch Feiertage sein. Da die Bundesländer in Deutschland keine einheitlichen Feiertage haben, müssen diese jeweils pro Bundesland ermittelt werden. Der vorliegende Blog-Beitrag zeigt, wie dies mit Hilfe der von ETL zur Verfügung gestellten Funktionen dbo.F_BC_Holiday und dbo.F_BC_Holiday2 unkompliziert umgesetzt werden kann.

Funktion F_BC_Holiday

dbo.F_BC_Holiday (@Year INT, @include_weekend INT = 0)

Parameter:

@Year – Kalenderjahr, für welches die Feiertage ermittelt werden soll

@include_weekend – Wochenenden in Ermittlung einschließen = 1 oder nicht = 0

Beispiel:

SELECT * FROM dbo.F_BC_Holiday (2024, 1)

 

Ergebnis:

HolidayDate                HolidayDesc

2024-01-01 00:00:00 Neujahrstag

2024-01-06 00:00:00 Heilige Drei Könige (BW, BY, ST)

2024-03-29 00:00:00 Karfreitag

2024-03-31 00:00:00 Ostersonntag

2024-04-01 00:00:00 Ostermontag

2024-05-01 00:00:00 Tag der Arbeit

2024-05-09 00:00:00 Christi Himmelfahrt

2024-05-19 00:00:00 Pfingstsonntag

2024-05-20 00:00:00 Pfingstmontag

2024-05-30 00:00:00 Fronleichnam (BW, BY, HE, NW, RP, SL)

2024-08-15 00:00:00 Mariä Himmelfahrt (SL)

2024-10-03 00:00:00 Tag der deutschen Einheit

2024-10-31 00:00:00 Reformationstag (BB, HB, HH, MV, NI, SN, ST, SH, TH)

2024-11-01 00:00:00 Allerheiligen (BW, BY, NW, RP, SL)

2024-11-20 00:00:00 Buß- und Bettag (SN)

2024-12-25 00:00:00 1. Weihnachtstag

2024-12-26 00:00:00 2. Weihnachtstag

2024-01-07 00:00:00 Wochenende

2024-01-13 00:00:00 Wochenende

(alle Wochenenden bis Ende Dezember 2024 folgen in der Ausgabe)

Die Funktion gibt die Feiertage nicht pro Bundesland aus, sondern vermerkt hinter dem Namen des jeweiligen Feiertages die Kürzel der Bundesländer, in denen er gilt.

Funktion F_BC_Holiday2

Die Funktion ermittelt die Feiertage pro Jahr und pro Bundesland, als Basis dient oben beschriebene Funktion dbo.F_BC_Holiday.

Parameter:

@Year – Kalenderjahr, für welches die Feiertage ermittelt werden soll

@include_weekend – Wochenenden in Ermittlung einschließen = 1 oder nicht = 0

@BundeslandID – Kürzel des gewünschten Bundeslandes

Beispiel:

SELECT * FROM dbo.F_BC_Holiday2 (2024, 0, 'BY')

 

Ergebnis:

HolidayDate               HolidayDesc

2024-01-01 00:00:00 Neujahrstag

2024-01-06 00:00:00 Heilige Drei Könige (BW, BY, ST)

2024-03-29 00:00:00 Karfreitag

2024-03-31 00:00:00 Ostersonntag

2024-04-01 00:00:00 Ostermontag

2024-05-01 00:00:00 Tag der Arbeit

2024-05-09 00:00:00 Christi Himmelfahrt

2024-05-19 00:00:00 Pfingstsonntag

2024-05-20 00:00:00 Pfingstmontag

2024-05-30 00:00:00 Fronleichnam (BW, BY, HE, NW, RP, SL)

2024-10-03 00:00:00 Tag der deutschen Einheit

2024-11-01 00:00:00 Allerheiligen (BW, BY, NW, RP, SL)

2024-12-25 00:00:00 1. Weihnachtstag

2024-12-26 00:00:00 2. Weihnachtstag

In diesem Beispiel werden die Feiertage für das Bundesland Bayern (BY) und das Jahr 2024 ohne zusätzliche Anzeige der Wochenenden ausgegeben.

Ermitteln der einzelnen Arbeitstage

Auf der Basis dieser Funktionen können wir einen Arbeitstagkalender bzw. eine Datenbanktabelle, die alle Tage als Arbeitstag oder freien Tag markiert, erstellen.

Dafür sind im Anhang zwei Prozeduren für das Befüllen einer Arbeitstagstabelle abgelegt:

P_APP_Fuellen_Arbeitstagskalender und P_APP_Fuellen_Arbeitstagkalender_2

Beide Prozeduren benötigen als Parameter das Jahr und das Bundesland. Die erforderlichen Kürzel der Bundesländer sind in den Prozeduren aufgeführt. In den Prozeduren wird zunächst das Vorhandensein einer Tabelle dbo.T_S_Arbeitstagkalender geprüft und ob bereits Datensätze zu dem angegebenen Jahr und Bundesland existieren, um zu verhindern, dass Datensätze doppelt angelegt werden.

Danach wird die Tabelle dbo.T_S_Arbeitstagkalender angelegt und befüllt oder die bereits vorhandene Tabelle mit den neuen Daten befüllt.

Dafür werden zunächst alle Tage eines Jahres und das jeweilige Bundesland in die Tabelle dbo.T_S_Arbeitstagkalender geschrieben und als Arbeitstag gekennzeichnet. Als Basis hierfür kann die von ETL bereitgestellte View dbo.V_S_Periode dienen (dbo.P_APP_Fuellen_Arbeitstagskalender). Ist diese View nicht verfügbar, kann stattdessen die Prozedur dbo.P_APP_Fuellen_Arbeitstagskalender_2 verwendet werden, in welcher die Tage mittels der SQL-Datumsfunktionen per Rekursion eingefügt werden.

Im Anschluss werden die Feiertage und auch die Wochenenden über die ETL-Funktionen dbo.F_BC_Holiday bzw, dbo.F:BC_Holiday2 neu als Feiertag oder Wochenende markiert.

Wichtig ist: Die Spracheinstellung der Datenbank bzw. des Datenbankservers definiert die IDs, welche den einzelnen Wochentagen zugeordnet sind. In der deutschen Spracheinstellung sind Samstage und Sonntage mit der ID 6 bzw. 7 hinterlegt, in der englischen Spracheinstellung mit ID = 7 für Samstag und ID = 1 für Sonntag. Die jeweils eingestellte Sprache kann mit: SELECT @@LANGUAGE AS ‘Language Name’ auf Datenbankebene ermittelt werden. Die hier beschriebenen Prozeduren gehen bei der Ermittlung der Wochenenden von einer deutschen Spracheinstellung aus.

Verwendet man für die Kennzeichnung neben der Bezeichnung des Feiertages/Wochenendes einen numerischen Schlüssel wie z.B. 0 für kein Arbeitstag und 1 für Arbeitstag, kann pro Woche, Monat oder Jahr die konkrete Anzahl der Arbeitstage für einen Standort anhand seines Bundeslandes durch das Anlegen einer entsprechenden Kennzahl bestimmt werden. Durch die Einbeziehung der Anzahl der Arbeitstage in die Berechnung werden Kennzahlen, die von der Produktivität o. ä. Kennzahlen abhängen, zwischen den Bundesländern besser vergleichbar.

Anhang

P_APP_Fuellen_Arbeitstagskalender.sql


ALTER PROC [dbo].[P_APP_Fuellen_Arbeitstagskalender] (@Jahr int, @Bundesland varchar(50))
AS
BEGIN

-- Ermitteln Anzahl Arbeitstage pro Bundesland ohne Wochenende 
-- Basis für Ermitteln Wochenende (Samstag und Sonntag) und Feiertage = F_BC_Holiday2 und V_S_Periode

-- Kürzel für die Bundesländer:
--	BE - Berlin
--  BB - Brandenburg
--  BW - Baden-Württemberg
--  BY - Bayern
--  HB - Bremen
--  HE - Hessen
--  HH - Hamburg
--  MV - Mecklenburg-Vorpommern
--  NI - Niedersachsen
--  NW - Nordrhein-Westfalen
--  RP - Rheinland-Pfalz
--  SL - Saarland
--  SN - Sachsen
--  ST - Sachsen-Anhalt
--  SH - Schleswig-Holstein
--  TH - Thüringen

-- Aufruf der Prozedur (Beispiel): EXEC dbo.P_APP_Fuellen_Arbeitstagskalender @Jahr = 2023, @Bundesland = 'BY'


	DECLARE @Msg varchar(500)
	, @Beschreibung varchar(100) = 'Arbeitstag'

	IF EXISTS(SELECT * FROM sys.objects so WHERE so.[name] = 'T_S_Arbeitstagkalender' AND so.schema_id = (SELECT sc.schema_id FROM sys.schemas sc WHERE sc.[name] = 'dbo'))
	-- Tabelle existiert
	BEGIN
		-- Prüfen, ob Tage bereits in der Tabelle existieren
		IF EXISTS(SELECT * FROM dbo.T_S_Arbeitstagkalender WHERE YEAR(TagID) = @Jahr AND Bundesland = @Bundesland)
		BEGIN
			SET @Msg = 'Arbeitstage für ' + CAST(@Jahr AS varchar) + ' und Bundesland ' + @Bundesland + ' sind bereits vorhanden!'
			RAISERROR(@Msg,16,1) return
		END
		ELSE
		BEGIN
			INSERT INTO dbo.T_S_Arbeitstagkalender (TagID, Arbeitstag, Beschreibung, Bundesland)
			-- alle Tage in Tabelle T_S_Arbeitstagkalender füllen und zunächst als Arbeitstag kennzeichnen
			SELECT
				vp.TagID
				, 1
				, @Beschreibung
				, @Bundesland
			FROM dbo.V_S_Periode vp
			WHERE vp.JahrID = @Jahr

		END
	END
	ELSE
	BEGIN
		-- Tabelle existiert noch nicht
		-- alle Tage in Tabelle T_S_Arbeitstagkalender füllen und zunächst als Arbeitstag kennzeichnen
		SELECT
			vp.TagID AS TagID
			, 1 AS Arbeitstag
			, @Beschreibung AS Beschreibung
			, @Bundesland AS Bundesland
		INTO dbo.T_S_Arbeitstagkalender
		FROM dbo.V_S_Periode vp
		WHERE vp.JahrID = @Jahr

	END

	-- Kennzeichnen Wochenende und Feiertage als Nicht-Arbeitstage
	UPDATE k
	SET 
		k.Arbeitstag = 0
		, k.Beschreibung = HolidayDesc
	FROM dbo.[F_BC_Holiday2] (@Jahr, 1, @Bundesland)
	INNER JOIN dbo.T_S_Arbeitstagkalender k
		ON k.TagID = CAST(HolidayDate AS date)
END

P_APP_Fuellen_Arbeitstagskalender_2.sql


ALTER PROC [dbo].[P_APP_Fuellen_Arbeitstagskalender_2] (@Jahr int, @Bundesland varchar(50))
AS
BEGIN

-- Ermitteln Anzahl Arbeitstage pro Bundesland ohne Wochenende 
-- Basis für Ermitteln Wochenende (Samstag und Sonntag) -  Rekursion
-- Ermitteln Feiertage je Bundesland - F_BC_Holiday2

-- Kürzel für die Bundesländer:
--	BE - Berlin
--  BB - Brandenburg
--  BW - Baden-Württemberg
--  BY - Bayern
--  HB - Bremen
--  HE - Hessen
--  HH - Hamburg
--  MV - Mecklenburg-Vorpommern
--  NI - Niedersachsen
--  NW - Nordrhein-Westfalen
--  RP - Rheinland-Pfalz
--  SL - Saarland
--  SN - Sachsen
--  ST - Sachsen-Anhalt
--  SH - Schleswig-Holstein
--  TH - Thüringen

-- Aufruf der Prozedur (Beispiel): EXEC dbo.P_APP_Fuellen_Arbeitstagskalender_2 @Jahr = 2023, @Bundesland = 'BY'

	DECLARE @Msg varchar(500)
	, @Startdatum date 
	, @Enddatum date
	, @Beschreibung varchar(100) = 'Arbeitstag'

	SET @Startdatum = CONVERT(date, CAST(@Jahr*10000 + 1 * 100 + 1 AS varchar))
	SET @Enddatum = CONVERT(date, CAST(@Jahr*10000 + 12 * 100 + 31 AS varchar))

	IF EXISTS(SELECT * FROM sys.objects so WHERE so.[name] = 'T_S_Arbeitstagkalender' AND so.schema_id = (SELECT sc.schema_id FROM sys.schemas sc WHERE sc.[name] = 'dbo'))
	-- Tabelle existiert
	BEGIN
		-- Prüfen, ob Tage bereits in der Tabelle existieren
		IF EXISTS(SELECT * FROM dbo.T_S_Arbeitstagkalender WHERE TagID between @Startdatum AND @Enddatum AND Bundesland = @Bundesland)
		BEGIN
			SET @Msg = 'Arbeitstage für ' + CAST(@Jahr AS varchar) + ' und Bundesland ' + @Bundesland + ' sind bereits vorhanden!'
			RAISERROR(@Msg,16,1) return
		END
		ELSE
		BEGIN
			WITH cte_kalender
			AS
			(
				SELECT @Startdatum AS Tag
				UNION ALL
				SELECT DATEADD(DD,1,Tag) FROM cte_kalender
					WHERE DATEADD(DD,1,Tag) <= @Enddatum
			)
			-- Spracheinstellungen auf Datenbankserver/Datenbank berücksichtigen, hier Sprachinstellung = deutsch und damit Samstag = 6 und Sonntag = 7
			INSERT INTO dbo.T_S_Arbeitstagkalender (TagID, Arbeitstag, Beschreibung, Bundesland)
			SELECT 
				Tag
				, CASE WHEN DATEPART(WEEKDAY,Tag) in (6,7)		 
					THEN 0
					ELSE 1
				  END
				, CASE WHEN DATEPART(WEEKDAY,Tag) in (6,7)
					THEN 'Wochenende'
					ELSE 'Arbeitstag'
				  END
				, @Bundesland
			FROM cte_kalender
			OPTION (MAXRECURSION 0)
		END
	END
	ELSE
	BEGIN
		-- Tabelle existiert noch nicht
		WITH cte_kalender
		AS
		(
			SELECT @Startdatum AS Tag
			UNION ALL
			SELECT DATEADD(DD,1,Tag) FROM cte_kalender
				WHERE DATEADD(DD,1,Tag) <= @Enddatum
		)

		SELECT 
			Tag AS TagID
			, CASE WHEN DATEPART(WEEKDAY,Tag) in (6,7)
				THEN 0
				ELSE 1
			  END
			AS Arbeitstag
			, CASE WHEN DATEPART(WEEKDAY,Tag) in (6,7)
				THEN CAST('Wochenende' AS varchar(100))
				ELSE @Beschreibung
			  END 
			AS Beschreibung
			, @Bundesland AS Bundesland
		INTO dbo.T_S_Arbeitstagkalender
		FROM cte_kalender k
		OPTION (MAXRECURSION 0)
	END

	---- Feiertage eintragen
	UPDATE k
	SET 
		k.Arbeitstag = 0
		, k.Beschreibung = HolidayDesc
	FROM dbo.[F_BC_Holiday2] (@Jahr, 0, @Bundesland)
	INNER JOIN dbo.T_S_Arbeitstagkalender k
		ON k.TagID = HolidayDate


END

Nicolas Bissantz

Diagramme im Management

Besser entscheiden mit der richtigen Visualisierung von Daten

Erhältlich im Haufe-Onlineshop.