在sql server中计算行程

时间:2016-01-29 09:55:09

标签: sql sql-server sql-server-2012

我的表结构

id zoneid status
1   35     IN   starting  zone 
2   35     OUT 1st trip has been started
3   36     IN
4   36     IN
5   36     OUT
6   38     IN last station zone 1 trip completed 
7   38     OUT returning back 2nd trip has start
8   38     OUT
9   36     IN
10  36     OUT
11  35     IN when return back in start zone means 2nd trip complete
12  35     IN
13  35     IN
14  35     OUT 3rd trip has been started 
15  36     IN
16  36     IN
17  36     OUT
18  38     IN 3rd trip has been completed
19  38     OUT 4th trip has been started
20  38     OUT
21  36     IN
22  36     OUT
23  35     IN 4th trip completed
24  35     IN

现在我想要一个SQL查询,所以我可以算不上旅行。我不想使用状态字段进行计数 修改

我想要结果总旅行 其中35是起点,38是结束点(这是1次旅行),38次后发生35次意味着2次旅行,依此类推。

3 个答案:

答案 0 :(得分:2)

因此,您不希望查看状态,但只查看按ID排序的zoneid更改。 zoneid 36无关紧要,因此我们只选择35和38,按ID和计数更改排序。我们通过将记录与前一个记录进行比较来检测更改。我们可以用LAG查看以前的记录。

select sum(ischange) as trips_completed
from
(
  select 
    case when zoneid <> lag(zoneid) over (order by id) then 1 else 0 end as ischange
  from trips
  where zoneid in (35,38)
) changes_detected;

答案 1 :(得分:1)

我建议不做任何测试。以下查询是否生成正确的行数?请注意,如果有一个date_created(datetime)列,那么我建议使用该列来排序而不是id。

select
       ca.in_id, t.id as out_id, ca.in_status, t.status as out_status
from table1 t
cross apply (
   select top (1) id as in_id, status as in_status
   from table1
   where table1.id < t.id
   and zoneid = 35
   order by id DESC
   ) ca
where t.zoneid = 38
/* and conditions for selecting one day only */

如果该逻辑正确,那么只需使用COUNT(*)而不是列列表。

CREATE TABLE Table1
    ("id" int, "zoneid" int, "status" varchar(3), "other" varchar(54))
;

INSERT INTO Table1
    ("id", "zoneid", "status", "other")
VALUES
    (1, 35, 'IN', 'starting  zone'),
    (2, 35, 'OUT', '1st trip has been started'),
    (3, 36, 'IN', NULL),
    (4, 36, 'IN', NULL),
    (5, 36, 'OUT', NULL),
    (6, 38, 'IN', 'last station zone 1 trip completed'),
    (7, 38, 'OUT', 'returning back 2nd trip has start'),
    (8, 38, 'OUT', NULL),
    (9, 36, 'IN', NULL),
    (10, 36, 'OUT', NULL),
    (11, 35, 'IN', 'when return back in start zone means 2nd trip complete'),
    (12, 35, 'IN', NULL),
    (13, 35, 'IN', NULL),
    (14, 35, 'OUT', '3rd trip has been started'),
    (15, 36, 'IN', NULL),
    (16, 36, 'IN', NULL),
    (17, 36, 'OUT', 'other'),
    (18, 38, 'IN', '3rd trip has been completed'),
    (19, 38, 'OUT', '4th trip has been started'),
    (20, 38, 'OUT', NULL),
    (21, 36, 'IN', NULL),
    (22, 36, 'OUT', NULL),
    (23, 35, 'IN', '4th trip completed'),
    (24, 35, 'IN', NULL)
;

答案 2 :(得分:1)

出于学习目的,这里有一个自我解释的&amp;详细版本http://sqlfiddle.com/#!15/d8bf4/1/0

该解决方案基于计算“跑步”&#39;从&#35; 35到38&#39;和&#39; 38到35&#39;。解决方案非常特定于OP查询,但可以使用更短的版本进行优化...

with trip_38_to_35 as (
       select * from zonecount 
       where (zoneid=38 and status='OUT') OR (zoneid=35 and status='IN') 
       order by id asc
)
, count_start_on_38 as (    
       select count(*) as start_on_38            
       from  trip_38_to_35
       where (zoneid=38 and status='OUT') AND 
           id < 
           (    select max(id) 
                from trip_38_to_35 
                where (zoneid=35 and status='IN')
           ) /*do not count unfinished trips*/ 
) 
, count_end_on_35 as (  
       select count(*) as end_on_35
       from trip_38_to_35
       where (zoneid=35 and status='IN') 
) /*the other way of trip*/
, trip_35_to_38 as (
       select * from zonecount 
       where (zoneid=35 and status='OUT') OR (zoneid=38 and status='IN') 
       order by id asc
)
,count_start_on_35 as ( 
       select count(*) as start_on_35
       from  trip_35_to_38
       where (zoneid=35 and status='OUT') AND 
             id < 
             (    select max(id) 
                  from trip_35_to_38 
                  where (zoneid=38 and status='IN')
             ) /*do not count unfinished trips*/ 
) 
,count_end_on_38 as (   
       select count(*) as end_on_38
       from trip_35_to_38
       where (zoneid=38 and status='IN') 
)

/*sum the MIN of the two trips count*/

select 
    (case when end_on_35 > start_on_38 then start_on_38 else end_on_35 end) + 
    (case when end_on_38 > start_on_35 then start_on_35 else end_on_38 end)
from 
    count_start_on_38,
    count_end_on_35, 
    count_start_on_35,
    count_end_on_38

顺便说一下,按照定义计算了6次旅行