SQL:获取记录的运行行增量

时间:2015-01-31 17:32:20

标签: sql

我们假设这个表格包含RowIDCall列:

RowID  Call   DesiredOut
1       A        0
2       A        0
3       B        
4       A        1
5       A        0
6       A        0
7       B
8       B
9       A        2
10      A        0

我想SQL查询最后一列DesiredOut,如下所示: 每次Call是' A'回去直到' A'再次找到并计算两个' A'之间的记录数量。条目。

示例:RowID 4有' A'最近的前任位于RowID 2.在RowID 2和RowID之间我们有一个Call' B',所以我们算上1. / p>

使用ANSI SQL是否有一种优雅且高效的方法?

5 个答案:

答案 0 :(得分:2)

我会先找到前一个“A”值的rowid来解决这个问题。然后计算中间值的数量。

以下查询使用相关子查询实现此逻辑:

select t.*,
       (case when t.call = 'A'
             then (select count(*)
                   from table t3
                   where t3.id < t.id and t3.id > prevA
                  )
        end) as InBetweenCount
from (select t.*,
             (select max(rowid)
              from table t2
              where t2.call = 'A' and t2.rowid < t.rowid
             ) as prevA
      from table t
     ) t;

如果您知道rowid是连续的,没有间隙,则可以在外部查询中使用减法而不是子查询进行计算。

答案 1 :(得分:1)

您可以使用查询来查找之前的Call = A行。然后,您可以计算该行与当前行之间的行数:

select  RowID
,       `Call`
,       (
        select  count(*)
        from    YourTable t2
        where   RowID < t1.RowID
                and RowID > coalesce(
                    (
                    select  RowID
                    from    YourTable t3
                    where   `Call` = 'A'
                            and RowID < t1.RowID
                    order by
                            RowID DESC
                    limit 1
                    ),0)
        )
from    YourTable t1

Example at SQL Fiddle.

答案 2 :(得分:1)

以下是使用窗口函数的另一种解决方案:

with flagged as (
  select *,
         case
            when call = 'A' and lead(call) over (order by rowid) <> 'A' then 'end'
            when call = 'A' and lag(call) over (order by rowid) <> 'A' then 'start'
          end as change_flag
  from calls
)
select t1.rowid,
       t1.call,
       case 
         when change_flag = 'start' then rowid - (select max(t2.rowid) from flagged t2 where t2.change_flag = 'end' and t2.rowid < t1.rowid) - 1
         when call = 'A' then 0
       end as desiredout
from flagged t1
order by rowid;

CTE首先标记每个“A” - 块的开始和结束,然后最终选择使用这些标记来获得一个块的开始和前一个块的结束之间的差异。

如果rowid 无间隙,您可以在CTE中轻松添加无间隙rownumber来计算差异。

我不确定表现如何。如果戈登的答案更快,我不会感到惊讶。

SQLFiddle示例:http://sqlfiddle.com/#!15/e1840/1

答案 3 :(得分:1)

信不信由你,如果将两列编入索引,这将非常快。

select  r1.RowID, r1.CallID, isnull( R1.RowID - R2.RowID - 1, 0 ) as DesiredOut
from    RollCall R1
left join RollCall R2
    on  R2.RowID =(
        select  max( RowID )
        from    RollCall
        where   RowID < R1.RowID
            and CallID = 'A')
    and R1.CallID = 'A';

这是 Fiddle

答案 4 :(得分:0)

你可以这样做:

SELECT a.rowid - b.rowid 
FROM table as a, 
     (SELECT rowid FROM table where rowid < a.rowid order by rowid) as b
WHERE <something>
ORDER BY a.rowid

由于我不能说你正在使用哪种DBMS,所以更多种类的伪代码可以根据你的系统运行。