2010-04-14 14 views
11

Se ho un valore di data come 2010-03-01 17:34:12.018Qual è il modo migliore per troncare una data in SQL Server?

Qual è il modo più efficiente per trasformare questo in 2010-03-01 00:00:00.000?

Come domanda secondaria, qual è il modo migliore per emulare la funzione Oracle TRUNC, che consentirà di troncare in base a anno, trimestre, mese, settimana, giorno, ora, minuto e secondo limite?

+0

Ecco una domanda simile con una bella spiegazione: http://stackoverflow.com/questions/923295/how-to-truncate-a-datetime-in-sql-server – Alex

risposta

25

per arrotondare al più vicino intera giornata, ci sono tre approcci in largo uso. Il primo utilizza datediff per trovare il numero di giorni dal 0 datetime. Il tempo di produzione 0 corrisponde al 1 ° gennaio 1900. Aggiungendo la differenza di giorno alla data di inizio, hai arrotondato a un giorno intero;

select dateadd(d, 0, datediff(d, 0, getdate())) 

Il secondo metodo è testuale: tronca la descrizione testo con varchar(10), lasciando solo la parte data:

select convert(varchar(10),getdate(),111) 

Il terzo metodo utilizza il fatto che un datetime è davvero una virgola mobile che rappresenta il numero di giorni dal 1900. Quindi, arrotondandolo a un numero intero, ad esempio utilizzando floor, si ottiene l'inizio della giornata:

select cast(floor(cast(getdate() as float)) as datetime) 

Per rispondere alla seconda domanda, l'inizio della settimana è più complicato. Un modo è quello di sottrarre il giorno-of-the-settimana:

select dateadd(dd, 1 - datepart(dw, getdate()), getdate()) 

Questo restituisce una parte di tempo anche, in modo che avrebbe dovuto combinare con uno dei metodi tempo-stripping per arrivare al primo appuntamento . Ad esempio, con @start_of_day come variabile per migliorare la leggibilità:

declare @start_of_day datetime 
set @start_of_day = cast(floor(cast(getdate() as float)) as datetime) 
select dateadd(dd, 1 - datepart(dw, @start_of_day), @start_of_day) 

La inizio anno, il mese, l'ora ei minuti ancora lavorare con la "differenza dal 1900" approccio:

select dateadd(yy, datediff(yy, 0, getdate()), 0) 
select dateadd(m, datediff(m, 0, getdate()), 0) 
select dateadd(hh, datediff(hh, 0, getdate()), 0) 
select dateadd(mi, datediff(mi, 0, getdate()), 0) 

Arrotondare al secondo richiede un approccio diverso, poiché il numero di secondi dal 0 dà un overflow. Un modo per aggirare che sta usando l'inizio della giornata, invece del 1900, come data di riferimento:

declare @start_of_day datetime 
set @start_of_day = cast(floor(cast(getdate() as float)) as datetime) 
select dateadd(s, datediff(s, @start_of_day, getdate()), @start_of_day) 

Per giro di 5 minuti, regolare il metodo di arrotondamento minuto. Prendere il quoziente della differenza minuto, ad esempio utilizzando /5*5:

select dateadd(mi, datediff(mi,0,getdate())/5*5, 0) 

Questo funziona per i quarti e le mezze ore pure.

+0

Quale sarà il migliore? –

+0

Per quanto ne so, la differenza di prestazioni è troppo piccola per essere misurata – Andomar

+0

Questo è quello che voglio sapere anche io !!! Io uso il secondo nel mio codice, ma ero curioso di sapere se c'era un modo più veloce per farlo. Il primo è costituito da due funzioni di data con una terza chiamata di funzione, quindi ci sono almeno tre operazioni di parsing, mentre la seconda è un cast singolo per la stringa con un formato applicato (ma qui sta lo sfregamento, cosa succede nelle librerie?) .. – jcolebrand

2

Prova:

SELECT DATEADD(dd, DATEDIFF(dd, 0, GETDATE()), 0) 

UPDATE: risposta sulla seconda questione: per anni si potrebbe usare un po 'di bit versione modificata della mia risposta:

SELECT DATEADD(yy, DATEDIFF(yy, 0, GETDATE()), 0) 

per un quarto:

SELECT DATEADD(qq, DATEDIFF(qq, 0, GETDATE()), 0) 

e così via.

Ho controllato, fino a minuti - è OK. Ma in pochi secondi ho un messaggio di overflow:

La differenza di due colonne datetime ha causato overflow in fase di esecuzione.

Un altro aggiornamento: un'occhiata al seguente risposta alla stessa question

15

Se si utilizza SQL Server 2008, è possibile utilizzare la nuova Date tipo di dato in questo modo:

select cast(getdate() as date) 

Se ancora bisogno del vostro valore di essere un tipo di dati DateTime, si può fare questo:

select cast(cast(getdate() as date) as datetime) 

Un metodo che dovrebbe funzionare su tutte le versioni di SQL Server è:

select cast(floor(cast(getdate() as float)) as datetime) 
+0

Scommetto che questo è il più veloce, evitando del tutto l'aritmetica. –

1

Questo è in ritardo, ma produrrà i risultati esatti richiesti nel post. Ritengo inoltre che sia molto più intuitivo rispetto all'uso di dateadd, ma questa è la mia preferenza.

declare @SomeDate datetime = '2010-03-01 17:34:12.018' 
SELECT 
DATEFROMPARTS(
    YEAR(@SomeDate) 
    ,MONTH(@SomeDate) 
    ,'01' 
    ) AS CUR_DATE_FROM_PARTS 
,DATETIMEFROMPARTS(
    YEAR(@SomeDate)      
    ,MONTH(@SomeDate)     
    ,'01' --DAY(@SomeDate)     
    ,'00' --DATEPART(HOUR,@SomeDate)   
    ,'00' --DATEPART(MINUTE,@SomeDate)  
    ,'00' --DATEPART(SECOND,@SomeDate)  
    ,'00' --DATEPART(MILLISECOND,@SomeDate) 
    ) AS CUR_DATETIME_FROM_PARTS 
,@SomeDate       AS CUR_DATETIME 
,YEAR(@SomeDate)     AS CUR_YEAR 
,MONTH(@SomeDate)     AS CUR_MONTH 
,DAY(@SomeDate)     AS CUR_DAY 
,DATEPART(HOUR,@SomeDate)   AS CUR_HOUR 
,DATEPART(MINUTE,@SomeDate)  AS CUR_MINUTE 
,DATEPART(SECOND,@SomeDate)  AS CUR_SECOND 
,DATEPART(MILLISECOND,@SomeDate) AS CUR_MILLISECOND 
FROM Your_Table 

troncato Data: 2010-03-01

troncato DateTime: 2010-03-01 00: 00: 00.000

DateTime: 2010-03-01 17: 34: 12,017

Problemi correlati