2010-07-20 3 views
5

J'ai une table avec des horodatages, et je veux partitionner cette table en intervalles d'une heure, en commençant et en cours en arrière quelques heures. Je n'arrive pas à obtenir les résultats dont j'ai besoin avec la fonction T-SQL DATEDIFF, puisqu'elle compte le nombre de fois que l'aiguille des minutes passe 12 entre les deux dates - Je veux le nombre de fois où la main des minutes passe où elle est maintenant entre l'horodatage et maintenant.T-SQL DateDiff - partition par "full hours ago", plutôt que "times minutes turned 00 depuis"

Existe-t-il un moyen simple de faire cela dans T-SQL?

Mise à jour: En réponse aux commentaires, voici quelques exemples de données, la requête que je utilise actuellement et les résultats que je reçois, ainsi que les résultats que je veux.

données de l'échantillon:

TimeStamp 
********* 
2010-07-20 11:00:00.000 
2010-07-20 10:44:00.000 
2010-07-20 10:14:00.000 
2010-07-20 11:00:00.000 
2010-07-20 11:40:00.000 
2010-07-20 10:16:00.000 
2010-07-20 13:00:00.000 
2010-07-20 12:58:00.000 

requête actuelle:

SELECT TimeStamp, DATEDIFF(HOUR, TimeStamp, CURRENT_TIMESTAMP) AS Diff FROM ... 

Résultats:

 TimeStamp     Diff 
    *********     **** 
    2010-07-20 11:00:00.000  2 
    2010-07-20 10:44:00.000  3 
    2010-07-20 10:14:00.000  3 
    2010-07-20 11:00:00.000  2 
    2010-07-20 11:40:00.000  2 
    2010-07-20 10:16:00.000  3 
    2010-07-20 13:00:00.000  0 
    2010-07-20 12:58:00.000  1

Ce que je préfère avoir:

 -- The time is now, for the sake of the example, 13:40 

    TimeStamp     Diff 
    *********     **** 
    2010-07-20 11:00:00.000  3 -- +1 
    2010-07-20 10:44:00.000  3 
    2010-07-20 10:14:00.000  4 -- +1 
    2010-07-20 11:00:00.000  3 -- +1 
    2010-07-20 11:40:00.000  2 or 3 -- edge case, I don't really care which 
    2010-07-20 10:16:00.000  4 -- +1 
    2010-07-20 13:00:00.000  1 -- +1 
    2010-07-20 12:58:00.000  1

J'ai marqué les résultats qui ont changé avec un +1. De plus, je ne me soucie pas vraiment si cela est 0-indexé ou 1-indexé, mais au fond, si elle est maintenant 13:40 Je veux que les intervalles de temps qui obtiennent la même valeur pour être

 12:40-13:40 1 (or 0) 
    11:40-12:40 2 (or 1) 
    10:40-11:40 3 (or 2) 
    09:40-10:40 4 (or 3)
+0

Pouvez-vous expliquer que les données d'entrée et de sortie prévue avec le requête, vous avez écrit? – shahkalpesh

+0

DATEDIFF en minutes puis division entière par 60? –

Répondre

7

pouvez-vous pas utilisez simplement DATEDIFF(minute,.., puis divisez le résultat par 60 et prenez la valeur entière. par exemple.

SELECT DATEDIFF(minute, '2010-07-20 06:00', GETDATE())/60 

Je crois que ce sera jeté implicitement comme un entier comme datediff retourne un entier, il donne des heures entières sans arrondi.

Pour utiliser votre requête exacte de votre poste mise à jour:

SELECT TimeStamp, (DATEDIFF(minute, TimeStamp, CURRENT_TIMESTAMP) /60) AS Diff FROM ... 
+0

Cela ne sera toujours pas exact. Vous venez de changer l'erreur de 59 minutes à 59 secondes ... – ErikE

+0

@Emtucifor: Une erreur de 59 secondes est toujours beaucoup mieux - je vais l'utiliser pour décider si un utilisateur doit recevoir une notification ou non, et ils ne devraient en avoir qu'un au maximum par heure. Une erreur de 59 minutes dans ce cas est catastrophique - une erreur de 59 secondes est plutôt bonne. Et je peux même obtenir que l'erreur soit encore plus petite (<1 seconde) en faisant la même chose avec des secondes que Ben avec des minutes. –

+0

D'accord, pas de problème alors. Cependant, j'aime mieux ma version de la soustraction des dates, car c'est encore plus simple et c'est aussi précis que le type de données le permet. :) – ErikE

0

Vous pouvez regrouper sur ce point:

SELECT DateDiff(Hour, 0, GetDate() - TimeStamp) 

Si vous voulez connaître l'heure ce qui représente, calco en arrière:

DateAdd(Hour, -DateDiff(Hour, 0, GetDate() - TimeStamp), GetDate()) 

Si vous n'aimez pas soustraire des dates, cela peut être fait mais devient un peu plus difficile. Au lieu de simplement tirer dans le noir, j'ai élaboré une requête pour prouver que c'est correct.

SELECT 
    TimeStamp, 
    Now = GetDate(), 
    HourDiff = DateDiff(Hour, 0, GetDate() - TimeStamp), 
    HourCalc = DateAdd(Hour, -DateDiff(Hour, 0, GetDate() - TimeStamp), GetDate()), 
    HourDiff2 = DateDiff(Hour, DateAdd(Millisecond, AdjustMs, TimeStamp), DateAdd(Millisecond, AdjustMs, GetDate())), 
    HourCalc2 = DateAdd(Hour, -DateDiff(Hour, DateAdd(Millisecond, AdjustMs, TimeStamp), DateAdd(Millisecond, AdjustMs, GetDate())), GetDate()) 
FROM 
    (
     SELECT DateAdd(Second, -3559, GetDate()) 
     UNION ALL SELECT DateAdd(Second, -3600, GetDate()) 
     UNION ALL SELECT DateAdd(Second, -3601, GetDate()) 
    ) x (TimeStamp) 
    CROSS JOIN (
     SELECT 3599997 - DateDiff(Millisecond, 0, DateAdd(Hour, -DateDiff(Hour, 0, GetDate()), GetDate())) 
    ) D (AdjustMs) 

Malheureusement, je devais exploiter ma connaissance de la résolution de datetime type de données (1/300e de seconde), ainsi 3600000-3 = 3599997. Si le réglage de milliseconde a été calculé sur la base TimeStamp au lieu de GetDate () alors cela ne serait pas nécessaire, mais ce serait beaucoup plus compliqué puisque la grande expression dans la table dérivée D devrait être utilisée deux fois dans la requête principale, en remplaçant AdjustMs.

Les calculs sont plus compliqués que cela ne parait nécessaire car vous ne pouvez pas calculer la différence en millisecondes entre les dates aléatoires ou vous obtiendrez une erreur de débordement. Si vous connaissez les plages de dates possibles, vous pourrez peut-être faire des calculs directs en millisecondes en utilisant une date d'ancrage différente de '19000101 00: 00: 00.000' (le 0 dans les expressions ci-dessus).

À la réflexion, vous obtenez seulement 24+ jours de millisecondes dans un long signé:

SELECT DateAdd(Millisecond, 2147483647, 0) = '1900-01-25 20:31:23.647' 
+0

Cela semble aller un long chemin pour éviter de soustraire des dates - mais à partir de votre message, je suppose qu'il pourrait y avoir de bonnes raisons de ne pas vouloir faire cela. Pourquoi ne voudrais-je pas soustraire des dates? –

+0

Eh bien, ce n'est pas une exigence dans ce cas avec ** datetime **, mais dans SQL Server 2008, vous ne pouvez pas ajouter ou soustraire des valeurs du type de données ** date **. Bien que cela fonctionne avec ** datetime **, cela ne fonctionne pas toujours. C# .Net interdit également ceci (vous pouvez seulement ajouter et soustraire des périodes de temps des dates ou d'autres timespans) ainsi nous devrions tous penser aux moyens de l'éviter si nous allons rester au dessus de ces choses à long terme. Certains jours soustrayant des dates pourraient être dépréciés, puis supprimés en tant que fonctionnalité! – ErikE

0

j'utiliser

FLOOR(24 * CAST(CURRENT_TIMESTAMP-[TimeStamp] as float)) 

Test Case

DECLARE @GetDate datetime 
set @GetDate = '2010-07-20 13:40:00.000'; 

WITH TestData As 
(
select CAST('2010-07-20 11:00:00.000' AS DATETIME) AS [TimeStamp] UNION ALL 
select '2010-07-20 10:44:00.000' UNION ALL  
select '2010-07-20 10:14:00.000' UNION ALL 
select '2010-07-20 11:00:00.000' UNION ALL 
select '2010-07-20 11:40:00.000' UNION ALL 
select '2010-07-20 10:16:00.000' UNION ALL 
select '2010-07-20 13:00:00.000' UNION ALL 
select '2010-07-20 12:58:00.000' 
) 

SELECT [TimeStamp], FLOOR(24 * CAST(@GetDate-[TimeStamp] as float)) AS Diff 
FROM TestData 

Résultats

(Vous devrez ajouter 1 pour obtenir les résultats exacts que vous affiché, mais vous dites que vous n'êtes pas pris la peine environ 0 ou 1 indexé)

TimeStamp    Diff 
----------------------- ---------------------- 
2010-07-20 11:00:00.000 2 
2010-07-20 10:44:00.000 2 
2010-07-20 10:14:00.000 3 
2010-07-20 11:00:00.000 2 
2010-07-20 11:40:00.000 2 
2010-07-20 10:16:00.000 3 
2010-07-20 13:00:00.000 0 
2010-07-20 12:58:00.000 0 
+0

Pourquoi le '24 *'? Que me donne 'CAST (@ GetDate- [TimeStamp] AS FLOAT)'? –

+0

@Tomas. 'CAST (@ GetDate- [TimeStamp] AS FLOAT)' est le nombre de jours différence. par exemple. 1,75 serait 1 jour et 18 heures de différence. Donc multiplier par 24 donne le nombre d'heures de différence. En utilisant 'Floor', tout est regroupé en une heure. –

+0

Martin, d'après mon expérience, la conversion en float n'est pas fiable pour datetime. J'ai étudié cela intensément dans le passé. Datediff (Heure, 0, Current_TimeStamp - TimeStamp) fait le même tour. – ErikE

Questions connexes