2009-04-30 27 views
49

Sto cercando di confrontare il tempo in un campo datetime in una query SQL, ma non lo so è giusto. Non voglio confrontare la parte della data, solo la parte del tempo.Come posso confrontare il tempo in SQL Server?

sto facendo questo:

SELECT timeEvent 
FROM tbEvents 
WHERE convert(datetime, startHour, 8) >= convert(datetime, @startHour, 8) 

E 'corretto?

Sto chiedendo questo perché ho bisogno di sapere se '08: 00: 00 'è minore o maggiore di '07: 30: 00' e non voglio confrontare la data, solo la parte del tempo.

Grazie!

+0

Perché devo convertire in VARCHAR in modo da poter confrontare se un tempo è maggiore rispetto agli altri? Non potrei in questo modo confrontare le stringhe con le stringhe ?? – AndreMiranda

+0

La funzione DateDiff accetta i campi datetime come input, in modo che tu possa superare la gobba. – Eric

risposta

69

tuo confrontare funzionerà, ma sarà lenta a causa le date vengono convertite in una stringa per ogni riga. Per confrontare in modo efficace due parti di tempo, provare:

declare @first datetime 
set @first = '2009-04-30 19:47:16.123' 
declare @second datetime 
set @second = '2009-04-10 19:47:16.123' 

select (cast(@first as float) - floor(cast(@first as float))) - 
     (cast(@second as float) - floor(cast(@second as float))) 
     as Difference 

lunga spiegazione: una data in SQL Server viene memorizzato come un numero in virgola mobile. Le cifre prima del punto decimale rappresentano la data. Le cifre dopo il punto decimale rappresentano l'ora.

Quindi, ecco una data di esempio:

declare @mydate datetime 
set @mydate = '2009-04-30 19:47:16.123' 

Facciamo convertirlo in un float:

declare @myfloat float 
set @myfloat = cast(@mydate as float) 
select @myfloat 
-- Shows 39931,8244921682 

Ora prendete la parte dopo la cifra, cioè il tempo:

set @myfloat = @myfloat - floor(@myfloat) 
select @myfloat 
-- Shows 0,824492168212601 

Converti nuovamente in un datetime:

declare @mytime datetime 
set @mytime = convert(datetime,@myfloat) 
select @mytime 
-- Shows 1900-01-01 19:47:16.123 

Il 1900-01-01 è solo la data "zero"; è possibile visualizzare la parte di tempo con convert, specificando ad esempio formato di 108, che è solo il tempo:

select convert(varchar(32),@mytime,108) 
-- Shows 19:47:16 

conversioni tra datetime e galleggiante sono abbastanza veloce, perché sono fondamentalmente memorizzati nello stesso modo.

+0

Questo è grandioso, grazie! Ho fatto un sacco di conversione varchar, questo mi sembra un modo migliore (anche se non è immediatamente evidente a guardarlo). – Alex

2

Uso Datepart funzione: DATEPART (datepart, data)

Eg #

SELEZIONA DatePart (@YourVar, hh) * 60) + DatePart (@YourVar, mi) * 60)

Questo vi darà l'ora del giorno in minuti che consente di confrontare più facilmente.

È possibile utilizzare DateDiff se le date stanno per essere lo stesso, altrimenti sarà necessario per togliere la data come sopra

0
SELECT timeEvent 
    FROM tbEvents 
WHERE CONVERT(VARCHAR,startHour,108) >= '01:01:01' 

Questo indica a SQL Server per convertire la data/ora in un varchar usando lo stile 108, che è "hh: mm: ss". Puoi anche sostituire '01: 01: 01 ', che convertirà se necessario.

0

Io parto dal presupposto vostra colonna StartHour e variabile @startHour sono entrambi DATETIME; In tal caso, si dovrebbe essere la conversione in una stringa:

SELECT timeEvent 
FROM tbEvents 
WHERE convert(VARCHAR(8), startHour, 8) >= convert(VARCHAR(8), @startHour, 8) 
+0

Chris, perché devo convertire in VARCHAr per confrontare i tempi? In questo modo, non confrontarei stringa con stringa? – AndreMiranda

+1

Due motivi: 1) Il metodo CONVERT() è pensato per convertire da un tipo all'altro; Se CONVERTITI un DATETIME a DATETIME, non succede nulla. 2) Il terzo parametro di CONVERT() (l'8) è un codice per la formattazione dei dati quando si passa a un tipo di stringa; Non ha alcun significato quando si converte in DATETIME. –

2

aggiunta alle altre risposte:

è possibile creare una funzione per tagliare la data da un datetime

CREATE FUNCTION dbo.f_trimdate (@dat datetime) RETURNS DATETIME AS BEGIN 
    RETURN CONVERT(DATETIME, CONVERT(FLOAT, @dat) - CONVERT(INT, @dat)) 
END 

Quindi questo :

DECLARE @dat DATETIME 
SELECT @dat = '20080201 02:25:46.000' 
SELECT dbo.f_trimdate(@dat) 

tornerà 1900-01-01 02:25:46.000

+0

lanciare in round INT, il che renderebbe il risultato non sempre accurato, FLOOR è la strada da percorrere – murki

+0

Ecco il motivo dell'esempio: Arrotondare data base, in modo che possiamo lavorare solo sul campo tempo. L'hai provato? –

11

Se stai usando SQL Server 2008, si può fare questo:

WHERE CONVERT(time(0), startHour) >= CONVERT(time(0), @startTime) 

Ecco un test completo:

DECLARE @tbEvents TABLE (
    timeEvent int  IDENTITY, 
    startHour datetime 
) 

INSERT INTO @tbEvents (startHour) SELECT DATEADD(hh, 0, GETDATE()) 
INSERT INTO @tbEvents (startHour) SELECT DATEADD(hh, 1, GETDATE()) 
INSERT INTO @tbEvents (startHour) SELECT DATEADD(hh, 2, GETDATE()) 
INSERT INTO @tbEvents (startHour) SELECT DATEADD(hh, 3, GETDATE()) 
INSERT INTO @tbEvents (startHour) SELECT DATEADD(hh, 4, GETDATE()) 
INSERT INTO @tbEvents (startHour) SELECT DATEADD(hh, 5, GETDATE()) 

--SELECT * FROM @tbEvents 

DECLARE @startTime datetime 

SET @startTime = DATEADD(mi, 65, GETDATE()) 

SELECT 
    timeEvent, 
    CONVERT(time(0), startHour) AS 'startHour', 
    CONVERT(time(0), @startTime) AS '@startTime' 
FROM @tbEvents 
WHERE CONVERT(time(0), startHour) >= CONVERT(time(0), @startTime) 
+0

Rob, sto usando 2005 :-( – AndreMiranda

+0

Grazie Rob, il "DATEADD" era quello che stavo cercando! – Neville

17
convert(varchar(5), thedate, 108) between @leftTime and @rightTime 

Spiegazione:

se avete varchar(5) otterrete HH:mm

se avete varchar(8) si ottenere HH:mm ss

108 ottiene solo l'ora a partire dalla data di SQL

@leftTime e @rightTime sono due variabili per confrontare

+0

aiuta anche me :). –

1

Non mi piace fare affidamento sugli interni di archiviazione (che datetime è un float con numero intero = giorno e frazione = ora), ma faccio la stessa cosa della risposta Jhonny D. Cano. Questo è il modo in cui tutti gli sviluppatori di db che conosco lo fanno. Sicuramente non convertire in stringa. Se è necessario evitare l'elaborazione come float/int, l'opzione migliore è estrarre ora/minuto/secondo/millisecondi con DatePart()

3

Uno (possibilmente piccolo) problema che ho notato con le soluzioni finora è che esse tutti sembrano richiedere una chiamata di funzione per elaborare il confronto. Ciò significa che il motore di query dovrà eseguire una scansione completa della tabella per cercare le righe che si stanno cercando e non essere in grado di utilizzare un indice. Se il tavolo non diventerà particolarmente grande, probabilmente questo non avrà alcun effetto negativo (e puoi tranquillamente ignorare questa risposta).

Se, d'altra parte, la tabella potrebbe diventare piuttosto grande, le prestazioni della query potrebbero risentirne.

So che hai dichiarato che non desideri confrontare la parte della data, ma c'è una data effettiva che viene archiviata nella colonna datetime o la stai usando per memorizzare solo l'ora? In quest'ultimo caso, è possibile utilizzare un semplice operatore di confronto, che riduce l'utilizzo della CPU e consente al motore di query di utilizzare statistiche e indici (se presenti) per ottimizzare la query.

Se, tuttavia, la colonna datetime viene utilizzata per memorizzare sia la data che l'ora dell'evento, ovviamente non funzionerà. In questo caso, se è possibile modificare l'app e la struttura della tabella, separare la data e l'ora in due colonne datetime separate o creare una vista indicizzata che seleziona tutte le colonne (rilevanti) della tabella di origine e un'ulteriore colonna che contiene il elemento temporale che si desidera cercare (utilizzare una delle risposte precedenti per calcolarlo) e modificare l'app per interrogare la vista.

3

L'utilizzo del galleggiante non funziona.

DECLARE @t1 datetime, @t2 datetime 
SELECT @t1 = '19000101 23:55:00', @t2 = '20001102 23:55:00' 
SELECT CAST(@t1 as float) - floor(CAST(@t1 as float)), CAST(@t2 as float) - floor(CAST(@t2 as float)) 

Vedrai che i valori non sono gli stessi (SQL Server 2005). Volevo utilizzare questo metodo per verificare i tempi intorno a mezzanotte (il metodo completo ha più dettagli) in cui stavo confrontando l'ora corrente tra le 23:55:00 e le 00:05:00.

1

È possibile creare due variabili di data/ora e impostare solo l'ora di data che è necessario confrontare.

declare @date1 datetime; 
declare @date2 datetime; 

select @date1 = CONVERT(varchar(20),CONVERT(datetime, '2011-02-11 08:00:00'), 114) 
select @date2 = CONVERT(varchar(20),GETDATE(), 114) 

La data sarà "1900-01-01", è possibile confrontarlo

if @date1 <= @date2 
    print '@date1 less then @date2' 
else 
    print '@date1 more then @date2' 
0

sotto query che si dà il tempo dalla data

select DateAdd(day,-DateDiff(day,0,YourDateTime),YourDateTime) As NewTime from Table 
4
if (cast('2012-06-20 23:49:14.363' as time) between 
    cast('2012-06-20 23:49:14.363' as time) and 
    cast('2012-06-20 23:49:14.363' as time)) 
0

rilanci @ronmurp una preoccupazione valida: l'approccio cast/floor restituisce valori diversi per lo stesso tempo. Seguendo le linee della risposta di @littlechris e per una soluzione più generale che risolve i tempi con un componente di minuti, secondi e millisecondi, è possibile utilizzare questa funzione per contare il numero di millisecondi dall'inizio della giornata.

Create Function [dbo].[MsFromStartOfDay] (@DateTime datetime) 
Returns int 
As 
    Begin 
     Return (
       (Datepart(ms , @DateTime)) + 
       (Datepart(ss , @DateTime) * 1000) + 
       (Datepart(mi , @DateTime) * 1000 * 60) + 
       (Datepart(hh , @DateTime) * 1000 * 60 * 60) 
      ) 
    End 

Ho verificato che restituisce lo stesso int per due date diverse con lo stesso tempo

declare @first datetime 
set @first = '1900-01-01 23:59:39.090' 
declare @second datetime 
set @second = '2000-11-02 23:56:39.090' 
Select dbo.MsFromStartOfDay(@first) 
Select dbo.MsFromStartOfDay(@second) 

Questa soluzione non restituisce sempre la int che ci si aspetterebbe. Ad esempio, prova il seguente in SQL 2005, restituisce un int che termina in '557' invece di '556'.

set @first = '1900-01-01 23:59:39.556' 
set @second = '2000-11-02 23:56:39.556' 

Penso che questo abbia a che fare con la natura di DateTime memorizzato come float. È comunque possibile confrontare i due numeri. E quando ho usato questo approccio su un dataset "reale" di DateTime catturato in .NET usando DateTime.Now() e memorizzato in SQL, ho scoperto che i calcoli erano accurati.

+0

note: le prestazioni sembrano non essere così buone con questo approccio – SFun28

2

Basta cambiare convertire datetime di tempo che dovrebbe fare il trucco:

SELECT timeEvent 
FROM tbEvents 
WHERE convert(time, startHour) >= convert(time, @startHour) 
Problemi correlati