mit der Liste aller möglichen Daten ein Kalender-Tabelle zu haben, ist praktisch, aber in diesem Fall können wir, ohne es zu tun.
Ich verallgemeinere deine Frage ein wenig. Anstatt sich nur auf das aktuelle Quartal wollen wir zwei Parameter, die den Datumsbereich definieren, die Sie interessiert sind:
DECLARE @ParamStartDate date;
DECLARE @ParamEndDate date;
Zuerst müssen wir alle Zeilen aus Absence
erhalten, die eine Reihe FromDate
-UntilDate
haben, dass schneidet sich mit der gegebenen Periode.
SELECT
...
FROM
Absence
WHERE
ABS_REASON='SICK'
-- all absence periods, which overlap with the given period
AND FromDate <= @ParamEndDate
AND UntilDate >= @ParamStartDate
Zwei Perioden A und B überlappen, wenn (StartA <= EndB)
und (EndA >= StartB)
.
Dann müssen wir berechnen, wie viele Tage im Schnittpunkt der beiden Perioden sind.
Der Schnittpunkt darf nicht größer sein als der angegebene Datumsbereich (@ParamStartDate
bis @ParamEndDate
).
Der Schnittpunkt darf nicht größer sein als die Dauer der Erkrankung (FromDate
bis UntilDate
).
So ist der Beginn der Kreuzung ist das jüngste von FromDate
und @ParamStartDate
, dh MAX(FromDate, @ParamStartDate)
Das Ende der Kreuzung ist das früheste von UntilDate
und @ParamEndDate
, dh MIN(UntilDate, @ParamEndDate)
Schließlich ist die Dauer der Kreuzung in Tagen ist
DATEDIFF(day, MAX(FromDate, @ParamStartDate), MIN(UntilDate, @ParamEndDate))
Aber nur, wenn es positiv ist. Wenn es negativ ist, bedeutet dies, dass die Krankheitsperiode vor dem Beginn des angegebenen Quartals endete (oder die Krankheit begann nach dem Ende des angegebenen Quartals).
Es gibt keine integrierten MIN-, MAX-Funktionen, die zwei Parameter benötigen, also brauche ich CROSS APPLY
, um sie zu berechnen. Außerdem berechne ich die Anzahl der Tage im angegebenen Quartal, nur der Vollständigkeit halber. Die letzte Abfrage sieht wie folgt aus:
SELECT
1+DATEDIFF(day, @ParamStartDate, @ParamEndDate) AS QuarterDays
,CASE WHEN 1+DATEDIFF(day, CTE_MaxStartDate.AbsenceStartDate, CTE_MinEndDate.AbsenceEndDate) > 0
THEN 1+DATEDIFF(day, CTE_MaxStartDate.AbsenceStartDate, CTE_MinEndDate.AbsenceEndDate)
ELSE 0 END AS AbsenceDays
FROM
Absence
CROSS APPLY
(
SELECT CASE WHEN UntilDate < @ParamEndDate THEN UntilDate ELSE @ParamEndDate END AS AbsenceEndDate
) AS CTE_MinEndDate
CROSS APPLY
(
SELECT CASE WHEN FromDate > @ParamStartDate THEN FromDate ELSE @ParamStartDate END AS AbsenceStartDate
) AS CTE_MaxStartDate
WHERE
ABS_REASON='SICK'
-- all absence periods, which overlap with the given period
AND FromDate <= @ParamEndDate
AND UntilDate >= @ParamStartDate
I 1-DATEDIFF
fügen Sie eine Dauer von einem Tag zu bekommen, wenn Start- und Enddatum der Periode gleich sind.
können Sie Beispieldaten der Tabelle 'ABSENCE' teilen? –
Sie benötigen alle Abwesenheiten, die vor dem Ende des Quartals begonnen haben und nach dem Beginn des Quartals beendet wurden (oder "NULL" sind, wenn Sie nicht wissen, wann sie zurückkommen), also Ihre 'WHERE'-Klausel richtig (es sei denn, Sie müssen für "NULL" "UNTILDATE" sorgen). Dann müssen Sie nur die Tage innerhalb des aktuellen Quartals und den Abwesenheitsbereich zählen, und dafür müssen Sie wissen, welche Daten Arbeitstage sind, wie von Rob Farley vorgeschlagen. –