2010-11-22 5 views
1

serveur: sql 2008 R2; jeu de données: entre 50-100 millions enregistrementsProximité de datetime SQL par rapport à un ensemble

J'ai une table pleine d'instances de vitesse pour les véhicules dont j'ai besoin de déterminer la vitesse moyenne de toutes les voitures (c.-à-d. un nombre pas un nombre pour chaque voiture). L'astuce est que les enregistrements couvrent une grande période de temps et qu'il n'y a pas de cohérence au moment où les enregistrements ont été enregistrés, donc je peux avoir un enregistrement à 8h15 pour une voiture et rien de nouveau jusqu'à 8h20 alors qu'une autre voiture peut avoir des enregistrements pour toutes les 10 secondes à l'intérieur de cette période. Étant donné une date et une heure précises, j'ai besoin de déterminer cette vitesse moyenne et comme il est fort probable qu'il n'y aura pas de correspondance directe entre l'heure donnée et un enregistrement pour cette voiture, je dois choisir la vitesse de l'enregistrement. le plus proche de l'heure donnée.

Voici un script de configuration

CREATE TABLE [dbo].[SpeedRecords](
    [Id] [int] IDENTITY(1,1) NOT NULL, 
    [CarId] [int] NOT NULL, 
    [TimeOfEntry] [datetime] NOT NULL, 
    [Speed] [real] NOT NULL, 
CONSTRAINT [PK_SpeedRecords] PRIMARY KEY CLUSTERED ([Id] ASC)) 
go 
insert into SpeedRecords(CarId,TimeOfEntry,Speed) 
select 1, '11/22/2010 08:16:13', 67.56 union 
select 1, '11/22/2010 08:15:23', 63.87 union 
select 1, '11/22/2010 08:36:33', 45.66 union 
select 1, '11/22/2010 08:23:43', 56.87 union 
select 2, '11/22/2010 08:36:53', 78.66 union 
select 2, '11/22/2010 08:04:03', 34.88 union 
select 2, '11/22/2010 08:08:51', 23.23 union 
select 2, '11/22/2010 08:34:52', 65.87 union 
select 3, '11/22/2010 08:58:43', 45.34 union 
select 3, '11/22/2010 08:34:56', 73.23 union 
select 3, '11/22/2010 08:12:34', 12.87 union 
select 4, '11/22/2010 08:45:12', 66.45 union 
select 4, '11/22/2010 08:36:34', 90.87 union 
select 4, '11/22/2010 08:24:23', 34.89 union 
select 4, '11/22/2010 08:45:12', 45.83 


declare @dt datetime = '11/22/2010 08:43:14' 
-- select the average speed (for all cars) but 
-- only use the record for each car closest to 
-- the given datetime (@dt) 

Répondre

1

utilisation ABS (DATEDIFF ..) pour travailler plus petite différence, ORDER ce, restreindre.

changement ROW_NUMBER() to DENSE_RANK() si vous voulez que la moyenne de 2 vitesses qui sont la même différence de @dt

declare @dt datetime = '11/22/2010 08:43:14' 
-- select the average speed (for all cars) but 
-- only use the record for each car closest to 
-- the given datetime (@dt) 

;WITH Closest AS 
(
    SELECT 
     Speed, 
     ROW_NUMBER() OVER(PARTITION BY ID ORDER BY ABS(DATEDIFF(second,@dt,TimeOfEntry))) AS Ranking 
    FROM 
     SpeedRecords 

) 
SELECT 
    AVG(Speed) 
FROM 
    Closest 
WHERE 
    Ranking = 1 

Pour SQL Server 2000, vous auriez besoin d'un sous-requête corrélée et TOP, mais il serait maladroit