web-dev-qa-db-fra.com

Comment comparer le temps dans SQL Server?

J'essaie de comparer le temps dans un champ datetime dans une requête SQL, mais je ne sais pas si c'est vrai. Je ne veux pas comparer la partie date, mais seulement la partie heure.

Je fais ça:

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

Est-ce correct? 

Je pose la question parce que j’ai besoin de savoir si 08:00:00 est inférieur ou supérieur à 07:30:00 et je ne veux pas comparer la date, mais simplement la partie heure .

Merci!

54
AndreMiranda

Votre comparaison fonctionnera, mais elle sera lente car les dates sont converties en chaîne pour chaque ligne. Pour comparer efficacement deux heures, essayez:

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

Explication longue: une date sur le serveur SQL est stockée sous forme de nombre à virgule flottante. Les chiffres avant le point décimal représentent la date. Les chiffres après le point décimal représentent l'heure.

Alors voici un exemple de date:

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

Convertissons-le en float:

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

Prenez maintenant la partie après le chiffre, c’est-à-dire le temps:

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

Reconvertissez-le en date/heure:

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

Le 1900-01-01 n'est que la date "zéro"; vous pouvez afficher la partie heure avec convert, en spécifiant par exemple le format 108, qui est simplement l'heure:

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

Les conversions entre date/heure et float sont assez rapides, car elles sont stockées de la même manière.

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

Explication:

si vous avez varchar(5) vous obtiendrez HH:mm

si vous avez varchar(8) vous obtenez HH:mm ss

108 n'obtient que l'heure à partir de la date SQL

@leftTime et @rightTime sont deux variables à comparer

18
Iralda Mitro

Si vous utilisez SQL Server 2008, vous pouvez procéder comme suit:

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

Voici un test complet:

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)
11
Rob Garrison
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))
4
Edgardo Correa

L'utilisation de float ne fonctionne pas.

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))

Vous verrez que les valeurs ne sont pas les mêmes (SQL Server 2005). Je voulais utiliser cette méthode pour vérifier les heures autour de minuit (la méthode complète contient plus de détails) pour laquelle je comparais l'heure actuelle entre 23h55 et 00h05.

3
ronmurp

Il suffit de modifier convert datetime en time qui devrait faire l'affaire:

SELECT timeEvent 
FROM tbEvents 
WHERE convert(time, startHour) >= convert(time, @startHour)
3
Yi Zhang

Un problème (peut-être mineur) que j'ai noté avec les solutions jusqu'ici est qu'elles semblent toutes nécessiter un appel de fonction pour traiter la comparaison. Cela signifie que le moteur de requête devra effectuer une analyse complète de la table pour rechercher les lignes que vous recherchez, sans pouvoir utiliser d'index. Si la table ne devient pas particulièrement grande, cela n'aura probablement aucun effet négatif (et vous pouvez volontiers ignorer cette réponse).

Si, au contraire, la table pouvait devenir assez grande, les performances de la requête pourraient en souffrir.

Je sais que vous avez indiqué que vous ne souhaitiez pas comparer la partie de la date - mais y a-t-il une date réelle stockée dans la colonne date/heure ou l'utilisez-vous pour stocker uniquement l'heure? Dans ce dernier cas, vous pouvez utiliser un simple opérateur de comparaison, ce qui réduira l'utilisation du processeur et permettra au moteur de requête d'utiliser des statistiques et des index (le cas échéant) pour optimiser la requête.

Si, toutefois, la colonne datetime est utilisée pour stocker à la fois la date et l'heure de l'événement, cela ne fonctionnera évidemment pas. Dans ce cas, si vous pouvez modifier l’application et la structure de la table, séparer la date et l’heure en deux colonnes datetime distinctes, ou créer une vue indexée qui sélectionne toutes les colonnes (pertinentes) de la table source et élément temporel que vous souhaitez rechercher (utilisez l’une des réponses précédentes pour le calculer) et modifiez l’application pour interroger la vue.

3
Jason Musgrove

Utiliser la fonction Datepart: DATEPART (datepart, date) 

Par exemple#

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

Cela vous donnera le temps total de la journée en minutes vous permettant de comparer plus facilement.

Vous pouvez utiliser DateDiff si vos dates sont identiques, sinon vous devrez supprimer la date ci-dessus.

2
littlechris

Ajouter aux autres réponses:

vous pouvez créer une fonction pour rogner la date à partir d'un datetime

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

Donc ça:

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

Je reviendrai 1900-01-01 02: 25: 46.000

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

Cela indique à SQL Server de convertir la date et l'heure actuelles en varchar en utilisant le style 108, qui est "hh: mm: ss". Vous pouvez également remplacer "01: 01: 01" qu'un autre convertisseur convertira si nécessaire.

1
northpole

Je crois que vous voulez utiliser DATEPART('hour', datetime).

La référence est ici:

http://msdn.Microsoft.com/en-us/library/ms174420.aspx

1
Paul Sonier

Je n'aime pas utiliser des ressources internes de stockage (cette date-heure est un flottant avec un nombre entier = jour et une fraction = heure), mais je fais la même chose que la réponse Jhonny D. Cano. C’est ainsi que tous les développeurs de base de données que je connais le font. Certainement pas convertir en chaîne. Si vous devez éviter le traitement en tant que float/int, la meilleure option consiste à extraire heure/minute/seconde/millisecondes avec DatePart ().

1
ahains

Vous pouvez créer deux variables datetime et définir uniquement l'heure de la date à comparer.

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 date sera "1900-01-01" vous pouvez le comparer

if @date1 <= @date2
   print '@date1 less then @date2'
else
   print '@date1 more then @date2'
1
Renato Bezerra

Je suppose que votre colonne startHour et votre variable @startHour sont toutes deux DATETIME; Dans ce cas, vous devriez convertir en chaîne:

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

@ronmurp soulève une préoccupation valable: l'approche cast/floor renvoie différentes valeurs pour le même temps. Dans le sens de la réponse de @littlechris et d’une solution plus générale permettant de résoudre les moments comportant un composant minute, secondes, millisecondes, vous pouvez utiliser cette fonction pour compter le nombre de millisecondes à partir du début de la journée.

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

J'ai vérifié qu'il renvoie le même int pour deux dates différentes avec le même temps

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 )

Cette solution ne retourne pas toujours le int que vous attendez. Par exemple, essayez ce qui suit dans SQL 2005, il retourne un int se terminant par '557' au lieu de '556'.

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

Je pense que cela a à voir avec la nature de DateTime stockée en tant que float. Vous pouvez toujours comparer les deux nombres, cependant. Et quand j'ai utilisé cette approche sur un "réel" jeu de données de DateTime capturé dans .NET à l'aide de DateTime.Now () et stocké en SQL, j'ai constaté que les calculs étaient précis.

0
SFun28

requête ci-dessous vous donne l'heure de la date 

select DateAdd(day,-DateDiff(day,0,YourDateTime),YourDateTime) As NewTime from Table
0
Darsh