簡體   English   中英

SQL:獲取記錄的運行行增量

[英]SQL: Get running row delta for records

假設我們有一個帶有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 4之間,我們有一個Call “ B”,因此我們計為1。

使用ANSI SQL是否有一種優雅而高效的方法?

我將首先找到上一個“ 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是連續的且沒有間隙,則可以在外部查詢中僅使用減法而不是子查詢來進行計算。

您可以使用查詢來查找先前的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

SQL Fiddle中的示例。

這是使用窗口函數的另一種解決方案:

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中添加無間隙的行號以計算差異。

我不確定性能。 如果戈登的答案更快,我不會感到驚訝。

SQLFiddle示例: http ://sqlfiddle.com/#!15/e1840/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';

這是小提琴

您可以這樣做:

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,這是一種更多的偽代碼,可以根據您的系統工作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM