2014-12-16 6 views
6

Ich habe eine SQL Server-Tabelle, die die Liste aller Mitarbeiter und ihre Krankheit enthält.SQL Count Krankheitstage

Ich muss in der Lage sein, zu berechnen, wie viele Tage sie im laufenden Quartal krank hatten

Die Frage ist, können einige Leute so ein Jahr lang krank gewesen sein, zum Beispiel die FROMDATE 2013-12- sein könnte 31 und der UNTILDATE könnte 2014-12-31 sein (1 Jahr Krankheitsurlaub). Es sollte jedoch nur die Tage von dieser Krankheit, die im laufenden Quartal auftreten, zählen. Es sollten also rund 90 Krankheitstage sein, statt das ganze Jahr zu zählen.

Aktuelle SQL

select SUM(a.WORKDAYS) as Total 
from ABSENCE a 
where a.FROMDATE < GETDATE() and 

a.UNTILDATE > DATEADD(MONTH, -3, GETDATE()) 
and 
a.ABS_REASON='SICK' 

Also im Moment, es von jedem from nimmt die korrekt ist, wie ich für die Menschen berücksichtigen müssen, die bereits krank waren, bevor das Quartal begonnen, aber immer noch krank in das laufende Quartal geht aber sollte nur die Anzahl der Tage vom Beginn des Quartals bis zum Ende des Quartals zählen.

Jede Hilfe würde sehr geschätzt werden.

+1

können Sie Beispieldaten der Tabelle 'ABSENCE' teilen? –

+1

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. –

Antwort

0
SELECT SUM(a.WORKDAYS) as Total 
FROM ABSENCE a 
WHERE (a.FROMDATE >= DATEADD(MONTH, -3, GETDATE()) OR a.UNTILDATE >= DATEADD(MONTH, -3, GETDATE())) 
AND a.ABS_REASON = 'SICK' 

Viertel Spezifische

SELECT SUM(a.WORKDAYS) as Total 
FROM ABSENCE a 
WHERE (a.FROMDATE >= DATEADD(quarter, -1, GETDATE()) OR a.UNTILDATE >= DATEADD(quarter, -1, GETDATE())) 
AND a.ABS_REASON = 'SICK' 
+1

Dies würde nicht funktionieren, da das Datum vor mehr als einem Jahr hätte sein können, wenn jemand langfristig krank ist. Es sollte nur die Anzahl der Tage krank in der Reihe im laufenden Quartal zählen –

+1

Die Logik besteht darin, nur die Kranken Tage aus den letzten 3 Monaten zu zählen? – Matt

+0

aktualisierte Antwort, um alle Abwesenheiten aus dem aktuellen Quartal einzuschließen – Matt

1

Mit einer Tabelle von Daten, Sie bequem die Anzahl der Termine finden konnten, wo das Datum zwischen zwei Daten von Interesse ist, und wo gibt es eine Beurlaubung, die sie umgibt es. Sie können Ihre Daten auch so filtern, dass nicht-geschäftliche Tage und gesetzliche Feiertage ausgeschlossen werden.

Es gibt viele Möglichkeiten, um eine solche Tabelle von Daten zu generieren, und viele beschrieben sowohl auf Stackoverflow und dba.stackexchange.

0

Nicht sicher über Ihre Spalten. Sie sollten nur sql, die Datensätze zwischen 2013-12-31 und 2014-12-31 gibt und dann stellen Sie Ihr Problem.

die Sie interessieren,

select SUM(Case when datepart(MM, a.FROMDATE) IN (10,11,12) Then a.WORKDAYS Else End) 
as Total 
    from ABSENCE a 
    where a.FROMDATE >= '2013-12-31' and 
    a.UNTILDATE <= '2014-12-31' 
    and 
    a.ABS_REASON='SICK' 
0

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.

+1

@DavidHayward, Wie haben Sie das Problem schließlich gelöst? Waren einige der bereitgestellten Antworten für Sie nützlich? Wenn ja, können Sie sie aufwerten und eine Antwort annehmen, die am nützlichsten ist. –