2014-12-16 13 views
6

Ho una tabella SQL Server che contiene l'elenco di tutto il personale e la loro malattia.Giorni con numero SQL per malattia

ho bisogno di essere in grado di calcolare quanti giorni hanno avuto malati nel trimestre in corso

Il problema è che alcune persone potrebbero essere stati malati per un anno in modo, ad esempio, il FROMDATE potrebbe essere 2013-12- 31 e l'UNTILDATE potrebbero essere 2014-12-31 (congedo per malattia di 1 anno). Tuttavia dovrebbe contare solo i giorni di quella malattia che si verificano nel trimestre corrente. Quindi dovrebbe essere circa 90 giorni di malattia, piuttosto che contare l'intero anno.

SQL corrente

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' 

Quindi al momento, ci vogliono da qualsiasi fromdate che è corretto come ho bisogno di tenere conto di persone che erano già malato prima il trimestre iniziato, ma ancora malati che entrano il trimestre in corso, ma dovrebbe contare solo il numero di giorni da quando il trimestre è iniziato fino alla fine del trimestre.

Qualsiasi aiuto sarebbe molto apprezzato.

+1

puoi condividere i dati di esempio della tabella 'ASSENZA'? –

+1

Hai bisogno di tutte le assenze che sono iniziate prima della fine del trimestre e terminate dopo l'inizio del trimestre (o sono 'NULL' se non sai quando torneranno ancora), quindi la tua clausola' WHERE' è corretto (a meno che non sia necessario provvedere a 'NULL'' UNTILDATE'). Quindi è necessario contare solo i giorni nel trimestre corrente e l'intervallo di assenza, e per questo è necessario sapere quali date sono giorni di lavoro, come suggerito da Rob Farley. –

risposta

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' 

quartiere specifico

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

Questo non funzionerebbe come la data di scadenza avrebbe potuto essere più di un anno fa se qualcuno è malato a lungo termine. Dovrebbe solo contare il numero di giorni ammalati nell'intervallo nel trimestre corrente –

+1

La logica è di contare solo i giorni di malattia degli ultimi 3 mesi? – Matt

+0

risposta aggiornata per includere tutte le assenze dal trimestre corrente – Matt

1

Con una tabella di date, si potrebbe facilmente trovare il conteggio di date dove la data è tra le due date di interesse, e dove esiste un periodo di congedo che circonda esso. Puoi anche filtrare le date per escludere i giorni non lavorativi e i giorni festivi.

Ci sono molti modi per generare un tale tavolo di date, e molto descritto sia su stackoverflow che su dba.stackexchange.

0

Non sei sicuro delle tue colonne. Devi solo fornire sql che registri i record tra il 2013-12-31 e il 2014-12-31 e quindi chiedere il tuo problema.

Prova questo,

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

Avere un tavolo calendario con l'elenco di tutte le possibili date è a portata di mano, ma in questo caso si può fare a meno.

Genererò la tua domanda un po '. Invece di guardare solo al trimestre in corso cerchiamo di avere due parametri che definiscono l'intervallo di date che si sono interessati a:

DECLARE @ParamStartDate date; 
DECLARE @ParamEndDate date; 

In un primo momento abbiamo bisogno di ottenere tutte le righe da Absence che hanno una gamma FromDate-UntilDate che si interseca con il periodo indicato.

SELECT 
    ... 
FROM 
    Absence 
WHERE 
    ABS_REASON='SICK' 
    -- all absence periods, which overlap with the given period 
    AND FromDate <= @ParamEndDate 
    AND UntilDate >= @ParamStartDate 

Due periodi A e B si sovrappongono quando (StartA <= EndB) e (EndA >= StartB).

Quindi abbiamo bisogno di calcolare quanti giorni sono nell'intersezione dei due periodi.

Il periodo di intersezione non può essere maggiore dell'intervallo di date date (@ParamStartDate a @ParamEndDate).

Il periodo di intersezione non può essere maggiore della durata della malattia (FromDate a UntilDate).

Così, l'inizio della intersezione è l'ultimo di FromDate e @ParamStartDate, cioè MAX(FromDate, @ParamStartDate)

La fine di intersezione è il più antico di UntilDate e @ParamEndDate, cioè MIN(UntilDate, @ParamEndDate)

Infine, la durata del intersezione in giorni è

DATEDIFF(day, MAX(FromDate, @ParamStartDate), MIN(UntilDate, @ParamEndDate)) 

Ma, solo se è positivo. Se è negativo, significa che il periodo di malattia è terminato prima dell'inizio del trimestre (o la malattia è iniziata dopo che il trimestre è terminato).

Non ci sono funzioni MIN, MAX incorporate che richiedono due parametri a seconda delle esigenze, quindi utilizzo CROSS APPLY per calcolarli. Inoltre, calcolo il numero di giorni nel trimestre dato, solo per completezza. La query finale è simile al seguente:

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 

aggiungo 1-DATEDIFF per ottenere una durata di un giorno, se sono le stesse date di inizio e di fine del periodo.

+1

@DavidHayward, come hai risolto il problema? Qualcuna delle risposte fornite ti è stata utile? Se sì, puoi invitarli e accettare una risposta che è stata più utile. –

Problemi correlati