2013-10-21 74 views
0

我們有一個流量計數器,以15分鐘的增量計算每個車道(兩個入站和兩個出站)的汽車數量。SQL選擇查詢幫助。連續四行的最大總和。

有一個高峯期定義爲上午7:00至上午9:00。在此高峯期內,我們想知道PeakHourInPeakHourOutPeakHourSum

PeakHourIn是最高的連續4×15分鐘的總(1小時)爲lne1in + lne4in

PeakHourOut是最高的連續4×15分鐘的總(1小時)爲lne2out + lne3out

PeakHourSum是所有車道連續最高的4x15分鐘總計(1小時)。

Date Time lne1in lne2out lne3out lne4in 
09-18-2012 5:45 AM 2 0 0 0 
09-18-2012 6:00 AM 1 0 0 1 
09-18-2012 6:15 AM 2 1 0 0 
09-18-2012 6:30 AM 2 1 0 0 
09-18-2012 6:45 AM 6 1 2 1 
09-18-2012 7:00 AM 9 1 0 3 
09-18-2012 7:15 AM 81 12 22 15 
09-18-2012 7:30 AM 144 31 63 56 
09-18-2012 7:45 AM 84 30 62 42 
09-18-2012 8:00 AM 7 1 0 3 
09-18-2012 8:15 AM 11 2 3 3 
09-18-2012 8:30 AM 12 3 7 1 
09-18-2012 8:45 AM 16 4 8 0 
09-18-2012 9:00 AM 5 2 5 0 
09-18-2012 9:15 AM 10 1 4 0 

結果應該是這樣的:

PeakHourIn 434 PeakHourOut 221 PeakHourSum 655

任何幫助將不勝感激。

+0

這將是困難的。我建議一次一步。嘗試到高峯時間似乎是一個合理的開始。 –

+0

如何處理邊緣案例?高峯時段是否包含15分鐘的時間間隔,這些時間間隔超出了7-9 AM的範圍,或者您說只有5個時間段需要評估(小時時間段從7,7:15,7:30開始, 7:45和8:00)? –

+0

只有5個可能的高峯時間? 7:00-8:00,7:15-8:15 7:30-8:30,7:45-8:45,8:00-9:00如果是這樣,你並不擔心制定一個通用的解決方案,也許只是明確地檢查每個案例更簡單。 –

回答

1

如果您使用本機時間數據類型來存儲日期/時間,你可以組多個自聯接:

SELECT MAX(lne1in + lne4in)     AS PeakHourIn, 
     MAX(lne2out + lne3out)     AS PeakHourOut, 
     MAX(lne1in + lne2out + lne3out + lne4in) AS PeakHourSum 
FROM (
     SELECT t1.lne1in + t2.lne1in + t3.lne1in + t4.lne1in AS lne1in, 
       t1.lne2out + t2.lne2out + t3.lne2out + t4.lne2out AS lne2out, 
       t1.lne3out + t2.lne3out + t3.lne3out + t4.lne3out AS lne3out, 
       t1.lne4in + t2.lne4in + t3.lne4in + t4.lne4in AS lne4in 
     FROM my_table t1 
      JOIN my_table t2 ON t2.DateTime = t1.DateTime + INTERVAL 15 MINUTE 
      JOIN my_table t3 ON t3.DateTime = t2.DateTime + INTERVAL 15 MINUTE 
      JOIN my_table t4 ON t4.DateTime = t3.DateTime + INTERVAL 15 MINUTE 
     WHERE TIME(t1.DateTime) BETWEEN '07:00:00' AND '08:00:00' 
     GROUP BY t1.DateTime 
     ) t 
+0

在[sqlfiddle](http://sqlfiddle.com/#!2/0f6dd/1/0)上查看。按日期對結果進行分組是一個微不足道的變化(http://sqlfiddle.com/#!2/0f6dd/3/0)。 – eggyal

0

編輯

下面是MySQL的一個解決方案:http://sqlfiddle.com/#!2/ff0fb/9

create table TrafficData ( StartTime timestamp
,Lane int ,CarCount int );

create table LaneData 
(
    Lane int 
    , Direction bit 
); 

insert LaneData 
     select 1, 0 
union select 2, 1 
union select 3, 1 
union select 4, 0; 

insert TrafficData 
select dt, lane 
, case lane 
    when 1 then l1 
    when 2 then l2 
    when 3 then l3 
    when 4 then l4 
    else null 
    end 
from 
( 
    select '2012-09-18 05:45' dt, 2 l1, 0 l2, 0 l3, 0 l4 
    union all select '2012-09-18 06:00', 1, 0, 0, 1 
    union all select '2012-09-18 06:15', 2, 1, 0, 0 
    union all select '2012-09-18 06:30', 2, 1, 0, 0 
    union all select '2012-09-18 06:45', 6, 1, 2, 1 
    union all select '2012-09-18 07:00', 9, 1, 0, 3 
    union all select '2012-09-18 07:15', 81, 12, 22, 15 
    union all select '2012-09-18 07:30', 144, 31, 63, 56 
    union all select '2012-09-18 07:45', 84, 30, 62, 42 
    union all select '2012-09-18 08:00', 7, 1, 0, 3 
    union all select '2012-09-18 08:15', 11, 2, 3, 3 
    union all select '2012-09-18 08:30', 12, 3, 7, 1 
    union all select '2012-09-18 08:45', 16, 4, 8, 0 
    union all select '2012-09-18 09:00', 5, 2, 5, 0 
    union all select '2012-09-18 09:15', 10, 1, 4, 0 
) as originalTable 
cross join LaneData; 

select Lane, max(SumCarCount) as MaxSumCarCount 
from 
(
    select a.Lane, SUM(b.CarCount) as SumCarCount 
    from TrafficData a 
    inner join TrafficData b 
     on b.Lane = a.Lane 
     and b.StartTime between a.StartTime and DATE_ADD(DATE_ADD(a.starttime, interval 1 hour), interval -1 second) 
    where time(a.StartTime) between '07:00' and '08:15' 
    group by a.Lane, a.StartTime 
) x 
group by Lane 
order by Lane; 

select Direction, max(SumCarCount) as MaxSumCarCount 
from 
(
    select al.Direction, SUM(b.CarCount) SumCarCount 
    from TrafficData a 
    inner join LaneData al 
     on al.Lane = a.Lane 
    inner join TrafficData b 
     on b.StartTime between a.StartTime and DATE_ADD(DATE_ADD(a.starttime, interval 1 hour), interval -1 second) 
    inner join LaneData bl 
     on bl.Lane = b.Lane 
     and bl.Direction = al.Direction 
    where time(a.StartTime) between '07:00' and '08:15' 
    group by al.Direction, a.StartTime 
) x 
group by Direction 
order by Direction; 

ORIGINAL

這是我怎麼會去了解它在SQL Server:

--I'd change your table structure to be like this - that way you can easily add new lanes without rewriting the whole system 
declare @trafficData table 
(
    StartTime DateTime   
    ,Lane  int 
    ,CarCount int 
) 
--here's where you store additional info about the lanes (e.g. what direction they go in) 
declare @laneData table 
(
    Lane int 
    , Direction bit --0 in, 1 out 
) 
--populate the tables with sample data 
insert @laneData 
     select 1, 0 
union select 2, 1 
union select 3, 1 
union select 4, 0 

insert @trafficData 
select dt, lane 
, case lane 
    when 1 then l1 
    when 2 then l2 
    when 3 then l3 
    when 4 then l4 
    else null --should never happen 
    end 
from 
( 
    select '2012-09-18 5:45 AM' dt, 2 l1, 0 l2, 0 l3, 0 l4 
    union all select '2012-09-18 6:00 AM', 1, 0, 0, 1 
    union all select '2012-09-18 6:15 AM', 2, 1, 0, 0 
    union all select '2012-09-18 6:30 AM', 2, 1, 0, 0 
    union all select '2012-09-18 6:45 AM', 6, 1, 2, 1 
    union all select '2012-09-18 7:00 AM', 9, 1, 0, 3 
    union all select '2012-09-18 7:15 AM', 81, 12, 22, 15 
    union all select '2012-09-18 7:30 AM', 144, 31, 63, 56 
    union all select '2012-09-18 7:45 AM', 84, 30, 62, 42 
    union all select '2012-09-18 8:00 AM', 7, 1, 0, 3 
    union all select '2012-09-18 8:15 AM', 11, 2, 3, 3 
    union all select '2012-09-18 8:30 AM', 12, 3, 7, 1 
    union all select '2012-09-18 8:45 AM', 16, 4, 8, 0 
    union all select '2012-09-18 9:00 AM', 5, 2, 5, 0 
    union all select '2012-09-18 9:15 AM', 10, 1, 4, 0 
) originalTable 
cross join @laneData 

--peak for each individual lane 
select * 
from 
(
    select a.Lane, a.StartTime, SUM(b.CarCount) SumCarCount 
    , ROW_NUMBER() over (partition by a.lane order by SUM(b.CarCount) desc) r 
    from @trafficData a 
    inner join @trafficData b 
     on b.Lane = a.Lane 
     and b.StartTime between a.StartTime and DATEADD(second,-1,DATEADD(hour,1,a.starttime)) 
    group by a.Lane, a.StartTime 
) x 
where r = 1 
order by Lane 

--peak for lane direction 
select * 
from 
(
    select al.Direction, a.StartTime, SUM(b.CarCount) SumCarCount 
    , ROW_NUMBER() over (partition by al.Direction order by SUM(b.CarCount) desc) r 
    from @trafficData a 
    inner join @laneData al 
     on al.Lane = a.Lane 
    inner join @trafficData b 
     on b.StartTime between a.StartTime and DATEADD(second,-1,DATEADD(hour,1,a.starttime)) 
    inner join @laneData bl 
     on bl.Lane = b.Lane 
     and bl.Direction = al.Direction 
    group by al.Direction, a.StartTime 
) x 
where r = 1 
order by Direction 
+0

鑑於問題標記爲[tag:mysql],爲什麼要提供SQL Server特定的答案? – eggyal

+0

@eggyal:該解決方案可以很容易地適用於MySQL - 即使用時間範圍作爲連接條件使用內部聯接本身的想法。我對MySQL不太熟悉,因此需要花費兩倍的時間才能回答(現在是凌晨1點,因此我根本無法回答)。我希望用戶(或者將來會遇到此問題的人)發現我的答案中的信息有用。 – JohnLBevan

+0

稍後再做一下MySQL版本:http://sqlfiddle.com/#!2/ff0fb/9 – JohnLBevan