2013-01-21 18 views
9

Devo calcolare la lunghezza totale in termini di ore, minuti, secondi e la lunghezza media, dati alcuni dati con ora di inizio e ora di fine.DATEDIFF in HH: MM: formato SS

Ad esempio il risultato deve essere qualcosa come 45:15:10 che significa 45 ore 15 min 10 sec, o 30:07 per 30 min 07 sec.

Stiamo utilizzando SQL Server 2008 R2 e la conversione non è riuscita quando il tempo è superiore a 24:59:59. Qualche idea su come potrei fare questo?

Per informazioni, le colonne della tabella sono Id, StartDateTime, EndDateTime, ecc ho bisogno di fare un rapporto mensile contenente contano le registrazioni del mese, la lunghezza totale di questi record, e la lunghezza media. Mi piacerebbe sapere se c'è un modo semplice per eseguire tutto questo.

+2

Convertire tutto in secondi, sommarlo e quindi convertire manualmente in formato leggibile. – Kermit

risposta

5

Non dovresti essere convertito in time - è pensato per memorizzare un punto nel tempo su un singolo orologio 24 ore, non una durata o un intervallo (anche uno che è vincolato da solo a < 24 ore, che chiaramente il tuo i dati non lo sono). Invece puoi prendere il datediff nell'intervallo minimo richiesto (nel tuo caso, secondi), e poi eseguire alcune manipolazioni matematiche e di stringa per presentarlo nel formato di output che ti serve (potrebbe anche essere preferibile restituire i secondi all'applicazione o Segnala lo strumento e fallo fare questo lavoro).

DECLARE @d TABLE 
(
    id INT IDENTITY(1,1), 
    StartDateTime DATETIME, 
    EndDateTime DATETIME 
); 

INSERT @d(StartDateTime, EndDateTime) VALUES 
(DATEADD(DAY, -2, GETDATE()), DATEADD(MINUTE, 15, GETDATE())), 
(GETDATE()     , DATEADD(MINUTE, 22, GETDATE())), 
(DATEADD(DAY, -1, GETDATE()), DATEADD(MINUTE, 5, GETDATE())), 
(DATEADD(DAY, -4, GETDATE()), DATEADD(SECOND, 14, GETDATE())); 

;WITH x AS (SELECT id, StartDateTime, EndDateTime, 
    d = DATEDIFF(SECOND, StartDateTime, EndDateTime), 
    a = AVG(DATEDIFF(SECOND, StartDateTime, EndDateTime)) OVER() 
    FROM @d 
) 
SELECT id, StartDateTime, EndDateTime, 
    [delta_HH:MM:SS] = CONVERT(VARCHAR(5), d/60/60) 
    + ':' + RIGHT('0' + CONVERT(VARCHAR(2), d/60%60), 2) 
    + ':' + RIGHT('0' + CONVERT(VARCHAR(2), d % 60), 2), 
    [avg_HH:MM:SS] = CONVERT(VARCHAR(5), a/60/60) 
    + ':' + RIGHT('0' + CONVERT(VARCHAR(2), a/60%60), 2) 
    + ':' + RIGHT('0' + CONVERT(VARCHAR(2), a % 60), 2) 
FROM x; 

Risultati:

id StartDateTime  EndDateTime   delta_HH:MM:SS avg_HH:MM:SS 
-- ------------------- ------------------- -------------- ------------ 
1 2013-01-19 14:24:46 2013-01-21 14:39:46 48:15:00  42:10:33 
2 2013-01-21 14:24:46 2013-01-21 14:46:46 0:22:00  42:10:33 
3 2013-01-20 14:24:46 2013-01-21 14:29:46 24:05:00  42:10:33 
4 2013-01-17 14:24:46 2013-01-21 14:25:00 96:00:14  42:10:33 

Questo non è esattamente quello che hai chiesto, in quanto non mostrerà solo MM: SS per delta < 1 ora. È possibile regolare che con un semplice CASE espressione:

;WITH x AS (SELECT id, StartDateTime, EndDateTime, 
    d = DATEDIFF(SECOND, StartDateTime, EndDateTime), 
    a = AVG(DATEDIFF(SECOND, StartDateTime, EndDateTime)) OVER() 
    FROM @d 
) 
SELECT id, StartDateTime, EndDateTime, 
    [delta_HH:MM:SS] = CASE WHEN d >= 3600 THEN 
    CONVERT(VARCHAR(5), d/60/60) + ':' ELSE '' END 
    + RIGHT('0' + CONVERT(VARCHAR(2), d/60%60), 2) 
    + ':' + RIGHT('0' + CONVERT(VARCHAR(2), d % 60), 2), 
    [avg_HH:MM:SS] = CASE WHEN a >= 3600 THEN 
    CONVERT(VARCHAR(5), a/60/60) + ':' ELSE '' END 
    + RIGHT('0' + CONVERT(VARCHAR(2), a/60%60), 2) 
    + ':' + RIGHT('0' + CONVERT(VARCHAR(2), a % 60), 2) 
FROM x; 

Questa query cambia la colonna delta nel 2 ° riga del risultato di cui sopra 0:22:00-22:00.

1

Se si desidera calcolare la media, l'approccio migliore consiste nel convertire in secondi o in frazioni di un giorno. Giorno frazioni sono convenienti in SQL Server, perché si possono fare cose come:

select avg(cast(endtime - starttime) as float) 
from t 

È possibile riconvertirlo in un datetime utilizzando il cast inversa:

select cast(avg(cast(endtime - starttime as float) as datetime) 
from t 

L'aritmetica per ottenere le volte in formato che vuoi . . questo è un dolore. Si potrebbe prendere in considerazione anche giorni nel formato finale, e l'utilizzo di:

select right(convert(varchar(255), <val>, 120), 10) 

Per ottenere le ore eccedenti 24, qui è un altro approccio:

select cast(floor(cast(<val> as float)*24) as varchar(255))+right(convert(varchar(255), <val>, 120), 6) 

Esso utilizza convert per i minuti ei secondi, che dovrebbe essere imbottito con 0 s a sinistra. Quindi aggiunge le ore come valore separato.

4
SELECT CONVERT(time, 
       DATEADD(mcs, 
         DATEDIFF(mcs, 
           '2007-05-07 09:53:00.0273335', 
           '2007-05-07 09:53:01.0376635'), 
         CAST('1900-01-01 00:00:00.0000000' as datetime2) 
        ) 
      ) 
0

Ho leggermente modificato la risposta di Avinash in quanto potrebbe terminare con errore se la differenza è troppo grande.Se è necessario solo HH: mm: ss è sufficiente distinguerlo al livello di secondi in questo modo:

SELECT CONVERT(time, 
    DATEADD(s, 
    DATEDIFF(s, 
     '2018-01-07 09:53:00', 
     '2018-01-07 11:53:01'), 
    CAST('1900-01-01 00:00:00.0000000' as datetime2) 
    ) 
) 
Problemi correlati