2010-06-01 7 views
3

Juste quelque chose d'intéressant vient dans mon esprit. Supposons que nous avons une table (dans SQL Server) comme ceci:Trouvez la période de survitesse?

  • Lieu
  • Vitesse
  • temps

par exemple:

Location  Velocity Time 
1   40   1:20 
2   35   2:00 
3   45   2:05 
4   50   2:30 
5   60   2:45 
6   48   2:55 
7   40   3:00 
8   35   3:15 
9   50   3:20 
10   70   3:30 
11   50   3:35 
12   40   3:40 

On suppose que la barrière de vitesse est 40kph, la sortie est quelque chose comme ça

Quelle est la meilleure façon de déterminer les périodes de dépassement de vitesse (la barrière de vitesse est définie)?
Starttime   Endtime 
2:05    3:00 
3:20    3:35 

Quelle est la meilleure façon de déterminer les périodes de survitesse? Ma première idée était de charger la table dans un tableau, puis itérer sur tableau pour trouver ces périodes:

(Pseudo code C#)

bool isOverSpeed = false; 

for (int i =0;i<arr.Length;i++) 
{ 
if (!isOverSpeed) 
    if (arr[i].Velocity > speedBarrier) 
     { 
      #insert the first record into another array. 
      isOverSpeed = true; 
     } 
if(isOverSpeed) 

    if (arr[i].Velocity < speedBarrier) 
      { 
      #insert the record into that array 
      isOverSpeed = false; 
      } 

} 

Il fonctionne, mais un peu « pas très efficace ». Existe-t-il un moyen plus "intelligent", comme une requête T-SQL ou un autre algorithme pour le faire?

+0

Le point est que vous voulez agréger les temps de 'Velocity> speedBarrier', comme' TimeSpan'-s? Ce n'est pas très clair. Quelle sortie attendez-vous? – Kobi

+0

La sortie que je m'attends à ce que la voiture passe de «quand» à «quand», non seulement TimeSpan – Vimvq1987

+0

Quel est votre modèle de variation de la vitesse du véhicule dans le temps? –

Répondre

2

Vous pouvez réaliser cela en utilisant CTE (Common Table Expressions).

La requête ci-dessous fonctionne avec la table de démonstration Adventure Works de SQL Server (la "limite de vitesse" étant de 7).

Ceci est fortement inspiré par une autre question sur SO: GROUP BY for continuous rows in SQL.

with CTE as (
    select 
     ROW_NUMBER() over(order by SalesTaxRateID) as RowNo 
     , * 
    from 
     Sales.SalesTaxRate 
) 
, MyLogGroup as (
    select 
     l.* 
     ,(select 
       max(SalesTaxRateID) 
      from 
       CTE c 
      where 
       not exists (select * from CTE 
           where RowNo = c.RowNo-1 
           and TaxRate > 7 
           and c.TaxRate > 7) 
       and c.SalesTaxRateID <= l.SalesTaxRateID) as GroupID 
    from 
     Sales.SalesTaxRate l) 
select 
    min(SalesTaxRateID) as minimum 
    , max(SalesTaxRateID) as maximum 
    , avg(TaxRate) 
from 
    MyLogGroup 
group by 
    GroupID 
having 
    min(TaxRate) > 7 
order by 
    minimum 

Quelque chose le long de ces lignes devrait vous convenir:

with CTE as (
    select 
     ROW_NUMBER() over(order by [Time]) as RowNo 
     , * 
    from 
     <table_name> 
) 
, MySpeedGroup as (
    select 
     s.* 
     ,(select 
       max([Time]) 
      from 
       CTE c 
      where 
       not exists (select * from CTE 
           where RowNo = c.RowNo-1 
           and Velocity > <speed_limit> 
           and c.Velocity > <speed_limit>) 
       and c.[Time] <= s.[Time]) as GroupID 
    from 
     <table_name> l) 
select 
    min([Time]) as minimum 
    , max([Time]) as maximum 
    , avg([Velocity]) -- don't know if you want this 
from 
    MySpeedGroup 
group by 
    GroupID 
having 
    min(Velocity) > <speed_limit> 
order by 
    minimum 
+0

excellent. Merci – Vimvq1987

1

Il ne peut pas être que simple, ou peut-il?

SELECT 
    Location, 
    Velocity, 
    Time, 
    CASE WHEN Velocity > @SpeedBarrier THEN 1 ELSE 0 END AS IsOverSpeed 
FROM 
    SpeedTable 
+0

Il semble que votre requête répertorie TOUS les enregistrements de survitesse, au lieu de seulement les périodes de survitesse. Ne pas avoir une vraie table à tester maintenant :) – Vimvq1987

+0

@ Vimvq1987: Oui, c'est pourquoi ma réponse était si réticente. ;-) – Tomalak

+0

juste testé, votre requête retourne tous les enregistrements, vient d'ajouter un nouveau champ (IsOverSpeed ​​1/0) :) – Vimvq1987

-1

Si l'on suppose que si elle correspond, il sera faux suivre la ci-dessous requête SQL

sélectionnez l'emplacement , la vitesse, le temps, (vitesse> Speedlimit = true ou la vitesse < = Speedlimit = false) comme survitesse de Table où Speedlimit = yourGivenLimit

Je n'ai pas testé, mais je suis sûr que quelque chose comme il le fera.

+0

pas sûr pourquoi cela a été noté, bien sûr quelqu'un est prêt à atteindre la réputation par punir les autres, allez comprendre ... –

1

Je l'ai utilisé la partie suivante pour obtenir des données (je suis sur le mode de compatibilité 80 atm donc je n'ai pas le temps domaine et je suis utilise un INT pour l'horodatage)

DECLARE @Info TABLE (Location INT IDENTITY, Velocity INT, [Time] INT); 
INSERT INTO @Info (Velocity, [Time]) VALUES (40, 80); 
INSERT INTO @Info (Velocity, [Time]) VALUES (35, 120); 
INSERT INTO @Info (Velocity, [Time]) VALUES (45, 125); 
INSERT INTO @Info (Velocity, [Time]) VALUES (50, 150); 
INSERT INTO @Info (Velocity, [Time]) VALUES (60, 165); 
INSERT INTO @Info (Velocity, [Time]) VALUES (48, 175); 
INSERT INTO @Info (Velocity, [Time]) VALUES (40, 180); 
INSERT INTO @Info (Velocity, [Time]) VALUES (35, 195); 
INSERT INTO @Info (Velocity, [Time]) VALUES (50, 200); 
INSERT INTO @Info (Velocity, [Time]) VALUES (70, 210); 
INSERT INTO @Info (Velocity, [Time]) VALUES (50, 215); 
INSERT INTO @Info (Velocity, [Time]) VALUES (40, 220); 
INSERT INTO @Info (Velocity, [Time]) VALUES (45, 225); 
INSERT INTO @Info (Velocity, [Time]) VALUES (45, 230); 

en supposant que votre emplacement sont des points fixes qui doit être adoptée afin de compléter la suivante produira la sortie désirée. Je l'ai décomposé en plusieurs étapes afin de clarifier ce que chaque partie fait.

DECLARE @Limit INT; 
SET @Limit = 40; 

WITH Stage1 ([Location], [Velocity], [Time]) AS (
    SELECT * FROM @Info WHERE [Velocity] > @Limit 
), Stage2 (Start) AS (
    SELECT [Time] 
     FROM [Stage1] 
    WHERE ([Location] - 1) NOT IN (SELECT [Location] FROM [Stage1]) 
), Stage3 ([Start], [Stop]) AS (
    SELECT [Start] 
     , (SELECT MIN([Time]) FROM [Stage1] WHERE ([Location] + 1) NOT IN (SELECT [Location] FROM [Stage1]) AND [Time] > [Stage2].[Start]) 
     FROM Stage2 
) 
SELECT * 
    FROM Stage3