none
Anzahl Pro Stunde und Tag RRS feed

  • Frage

  • Guten Tag

    Ich bräuchte wiedermal ein wenig Hilfe.

    Ich habe zwei Datenfelder

    Eingang = 02.02.2015 08:10:15

    Ausgang = 04.02.2015 09:10:20

    Nun möchte ich eine Abfrage generieren welche mir folgendes Resultat anzeigt (Anzahl pro Stunde):

    

    Der Hintergrund ist, die Patienten kommen auf einen bestimmten Zeitpunkt und verlassen auf einen bestimmten Zeitpunkt die Abteilung. Nun versuche ich herauszufinden, wieviele Betten sind zu einem bestimmten Zeitabschnitt besetzt, gruppiert nach Tag.

    Mein Ansatz war:

    sum(case When DATEPART(hour, Eingang) <= 00 AND DATEPART(hour, Ausgang) >=00 THEN 1 ELSE 0 END) as T00

    und das für jede Stunde.

    Was ich aber nicht hingekriegt habe, wie teile ich das noch auf die Tage auf.

    Herzlichen Dank für die Hilfe

    Freundliche Grüsse

    Walo Beck



    • Bearbeitet W_Beck Montag, 30. März 2015 08:12 Fehler korrigiert
    Montag, 30. März 2015 07:59

Antworten

  • Hallo Walo,

    weiter aufteilen kann man es, in dem man den Datumsanteil  mit einer Kalendertabelle verknüpft. Ähnliches kann man auch mit den Stunden machen.

    Eine angefangene Lösung:

    -- eine (partielle) Kalendertabelle
    CREATE TABLE #Kalender (Datum Date NOT NULL CONSTRAINT PK_Kalender PRIMARY KEY);
    INSERT INTO #Kalender(Datum)
    SELECT DATEADD(dd, number, '2015-01-01')
    FROM master..spt_values WHERE type = 'P';
    
    -- für Stunden (ggf. weiter aufteilen nach Wochentage etc.)
    CREATE TABLE #Stunden (Stunde int NOT NULL CONSTRAINT PK_Stunde PRIMARY KEY,
    	StundeText varchar(30) CONSTRAINT UK_Stunde_Text UNIQUE);
    DECLARE @Stunde int = 0;
    WHILE @Stunde < 24
    BEGIN
    	INSERT INTO #Stunden (Stunde, StundeText) VALUES (@Stunde,
    			CAST(@Stunde AS varchar) + ':00-' + CAST(@Stunde + 1 AS varchar) + ':00');
    	SET @Stunde += 1;
    END;
    
    -- eine Belegung (partiell)
    CREATE TABLE #Belegung (
    	BelegungId int NOT NULL,
    	Eingang Datetime2 NOT NULL,
    	Ausgang Datetime2 NOT NULL);
    
    INSERT INTO #Belegung VALUES 
    	(1, '2015-02-02 08:10:15', '2015-02-04 09:10:20'),
    	(2, '2015-02-03 18:00:15', '2015-02-04 12:15:20'),
    	(3, '2015-02-04 10:00:15', '2015-02-04 15:30:20');
    
    
    -- liefert alle belegten Stunden
    SELECT k.Datum, s.Stunde, COUNT(*)
    FROM #Belegung AS b
    INNER JOIN #Kalender AS k ON k.Datum >= CAST(b.Eingang AS date) AND k.Datum <= CAST(b.Ausgang AS date)
    INNER JOIN #Stunden AS s ON (k.Datum = CAST(b.Eingang AS date) AND s.Stunde >= DATEPART(hour, b.Eingang))
    			OR (k.Datum = CAST(b.Ausgang AS date) AND s.Stunde <= DATEPART(hour, b.Ausgang))
    			OR (k.Datum > CAST(b.Eingang AS date) AND k.Datum < CAST(b.Ausgang AS date))
    GROUP BY k.Datum, s.Stunde
    ORDER BY k.Datum, s.Stunde;
    
    -- erweitert um belegte und nicht belegte via CROSS APPLY
    SELECT k.Datum, s.Stunde, SUM(s.Belegt)
    FROM #Belegung AS b
    INNER JOIN #Kalender AS k ON k.Datum >= CAST(b.Eingang AS date) AND k.Datum <= CAST(b.Ausgang AS date)
    CROSS APPLY (SELECT Stunde, -- oder StundeText
    				CASE WHEN (k.Datum = CAST(b.Eingang AS date) AND s.Stunde >= DATEPART(hour, b.Eingang))
    					OR (k.Datum = CAST(b.Ausgang AS date) AND s.Stunde <= DATEPART(hour, b.Ausgang))
    					OR (k.Datum > CAST(b.Eingang AS date) AND k.Datum < CAST(b.Ausgang AS date))
    					THEN 1 ELSE 0 END AS Belegt
    		FROM #Stunden AS s) AS s(Stunde, Belegt)
    GROUP BY k.Datum, s.Stunde
    ORDER BY k.Datum, s.Stunde;

    Den Teil mit PIVOT oder wie Du es gelöst hast über SUM(CASE...) habe ich mir vorerst geschenkt.

    Gruß Elmar


    • Bearbeitet Elmar Boye Montag, 30. März 2015 09:25
    • Als Antwort markiert W_Beck Dienstag, 31. März 2015 11:30
    Montag, 30. März 2015 09:25

Alle Antworten

  • Hallo Walo,
    um die Frage sinnvoll beantworten zu können, benötigen wir ein kleines Repro-Skript.
    Darin sollten das DDL für die Tabelle und die Inserts für die Beispiele, sowie das gewünschte Ergebnis enthalten sein.

    Wie man sich eine Hilfstabelle für die Stunden über die Tage aufbaut, hatten wir gerade erst letzte Woche im forum:
    https://social.msdn.microsoft.com/Forums/sqlserver/de-DE/6efe9b72-ba7a-41d9-b85d-fd551eba0792/print-ausgabe-einer-variable-bergeben?forum=sqlserver

    Darüber könnte ich mir einen Join mit den Patientendaten vorstellen und dann eine entsprechende Auswertung.

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

    Montag, 30. März 2015 09:15
    Beantworter
  • Hallo Walo,

    weiter aufteilen kann man es, in dem man den Datumsanteil  mit einer Kalendertabelle verknüpft. Ähnliches kann man auch mit den Stunden machen.

    Eine angefangene Lösung:

    -- eine (partielle) Kalendertabelle
    CREATE TABLE #Kalender (Datum Date NOT NULL CONSTRAINT PK_Kalender PRIMARY KEY);
    INSERT INTO #Kalender(Datum)
    SELECT DATEADD(dd, number, '2015-01-01')
    FROM master..spt_values WHERE type = 'P';
    
    -- für Stunden (ggf. weiter aufteilen nach Wochentage etc.)
    CREATE TABLE #Stunden (Stunde int NOT NULL CONSTRAINT PK_Stunde PRIMARY KEY,
    	StundeText varchar(30) CONSTRAINT UK_Stunde_Text UNIQUE);
    DECLARE @Stunde int = 0;
    WHILE @Stunde < 24
    BEGIN
    	INSERT INTO #Stunden (Stunde, StundeText) VALUES (@Stunde,
    			CAST(@Stunde AS varchar) + ':00-' + CAST(@Stunde + 1 AS varchar) + ':00');
    	SET @Stunde += 1;
    END;
    
    -- eine Belegung (partiell)
    CREATE TABLE #Belegung (
    	BelegungId int NOT NULL,
    	Eingang Datetime2 NOT NULL,
    	Ausgang Datetime2 NOT NULL);
    
    INSERT INTO #Belegung VALUES 
    	(1, '2015-02-02 08:10:15', '2015-02-04 09:10:20'),
    	(2, '2015-02-03 18:00:15', '2015-02-04 12:15:20'),
    	(3, '2015-02-04 10:00:15', '2015-02-04 15:30:20');
    
    
    -- liefert alle belegten Stunden
    SELECT k.Datum, s.Stunde, COUNT(*)
    FROM #Belegung AS b
    INNER JOIN #Kalender AS k ON k.Datum >= CAST(b.Eingang AS date) AND k.Datum <= CAST(b.Ausgang AS date)
    INNER JOIN #Stunden AS s ON (k.Datum = CAST(b.Eingang AS date) AND s.Stunde >= DATEPART(hour, b.Eingang))
    			OR (k.Datum = CAST(b.Ausgang AS date) AND s.Stunde <= DATEPART(hour, b.Ausgang))
    			OR (k.Datum > CAST(b.Eingang AS date) AND k.Datum < CAST(b.Ausgang AS date))
    GROUP BY k.Datum, s.Stunde
    ORDER BY k.Datum, s.Stunde;
    
    -- erweitert um belegte und nicht belegte via CROSS APPLY
    SELECT k.Datum, s.Stunde, SUM(s.Belegt)
    FROM #Belegung AS b
    INNER JOIN #Kalender AS k ON k.Datum >= CAST(b.Eingang AS date) AND k.Datum <= CAST(b.Ausgang AS date)
    CROSS APPLY (SELECT Stunde, -- oder StundeText
    				CASE WHEN (k.Datum = CAST(b.Eingang AS date) AND s.Stunde >= DATEPART(hour, b.Eingang))
    					OR (k.Datum = CAST(b.Ausgang AS date) AND s.Stunde <= DATEPART(hour, b.Ausgang))
    					OR (k.Datum > CAST(b.Eingang AS date) AND k.Datum < CAST(b.Ausgang AS date))
    					THEN 1 ELSE 0 END AS Belegt
    		FROM #Stunden AS s) AS s(Stunde, Belegt)
    GROUP BY k.Datum, s.Stunde
    ORDER BY k.Datum, s.Stunde;

    Den Teil mit PIVOT oder wie Du es gelöst hast über SUM(CASE...) habe ich mir vorerst geschenkt.

    Gruß Elmar


    • Bearbeitet Elmar Boye Montag, 30. März 2015 09:25
    • Als Antwort markiert W_Beck Dienstag, 31. März 2015 11:30
    Montag, 30. März 2015 09:25
  • Hallo Elmar

    Habe Deinen Vorschlag auf meine Bedürfnisse angepasst und es funktioniert tadellos wie gewünscht.

    Herzlichen Danke für die Hilfe

    Freundliche Grüsse

    Walo Beck

    Dienstag, 31. März 2015 11:30