【问题标题】:SQL Server - Running Count of specific values in a columnSQL Server - 列中特定值的运行计数
【发布时间】:2017-07-21 15:24:26
【问题描述】:

我正在尝试创建一个用于分析的数据集,其中包含每日交易以及未进行交易的日期。

理想的结果将与 Count(subsequent 0's) 列相同。我尝试过运行总计,但没有找到一种方法来仅计算事务列中具有“0”的行,然后在事务列为 0 时重置计数。

谢谢

【问题讨论】:

  • ,isnull(sum(isnull(transactions,0)) over ( partition by accountnumber order by cal.CalendarDate rows between 90 preceding and current row),0) as Previous90DaySubmission
  • ,count(rows) over (partition by transactions = 0 order by calendardate) as NoTransactionCount
  • 我在屏幕上仍然有两种不同的方法来尝试计算“正在运行的后续 ) 列”

标签: sql-server cumulative-sum


【解决方案1】:

我在 SQL Server 2016 SP1 (13.0.4001.0) 中解决了这个问题。这看起来像是“序列中的差距和孤岛”问题,我的解决方案是修改 Dwain Camps 的示例之一。

注意:原始示例列出了一个帐号,但该解决方案适用于多个帐号。

with TestData as
(
    -- data for Mr Bill Withers (account number 11300)
    select CONVERT(date, '29/06/2016', 103) as CalendarDate, 11300 as AccountNumber, 'Mr Bill Withers' as AccountName, 1 as Transactions
    union
    select CONVERT(date, '30/06/2016', 103) as CalendarDate, 11300 as AccountNumber, 'Mr Bill Withers' as AccountName, 3 as Transactions
    union
    select CONVERT(date, '01/07/2016', 103) as CalendarDate, 11300 as AccountNumber, 'Mr Bill Withers' as AccountName, 2 as Transactions
    union
    select CONVERT(date, '02/07/2016', 103) as CalendarDate, 11300 as AccountNumber, 'Mr Bill Withers' as AccountName, 0 as Transactions
    union
    select CONVERT(date, '03/07/2016', 103) as CalendarDate, 11300 as AccountNumber, 'Mr Bill Withers' as AccountName, 0 as Transactions
    union
    select CONVERT(date, '04/07/2016', 103) as CalendarDate, 11300 as AccountNumber, 'Mr Bill Withers' as AccountName, 4 as Transactions
    union
    select CONVERT(date, '05/07/2016', 103) as CalendarDate, 11300 as AccountNumber, 'Mr Bill Withers' as AccountName, 3 as Transactions
    union
    select CONVERT(date, '06/07/2016', 103) as CalendarDate, 11300 as AccountNumber, 'Mr Bill Withers' as AccountName, 0 as Transactions
    union
    select CONVERT(date, '07/07/2016', 103) as CalendarDate, 11300 as AccountNumber, 'Mr Bill Withers' as AccountName, 0 as Transactions
    union
    select CONVERT(date, '08/07/2016', 103) as CalendarDate, 11300 as AccountNumber, 'Mr Bill Withers' as AccountName, 0 as Transactions
    union
    select CONVERT(date, '09/07/2016', 103) as CalendarDate, 11300 as AccountNumber, 'Mr Bill Withers' as AccountName, 0 as Transactions
    union
    select CONVERT(date, '10/07/2016', 103) as CalendarDate, 11300 as AccountNumber, 'Mr Bill Withers' as AccountName, 1 as Transactions

    union

    -- data for Mr Bob Builder (account number 11301)
    select CONVERT(date, '29/06/2016', 103) as CalendarDate, 11301 as AccountNumber, 'Mr Bob Builder' as AccountName, 1 as Transactions
    union
    select CONVERT(date, '30/06/2016', 103) as CalendarDate, 11301 as AccountNumber, 'Mr Bob Builder' as AccountName, 0 as Transactions
    union
    select CONVERT(date, '01/07/2016', 103) as CalendarDate, 11301 as AccountNumber, 'Mr Bob Builder' as AccountName, 0 as Transactions

    union

    -- data for Mr Ted Teddy (account number 11302)
    select CONVERT(date, '29/06/2016', 103) as CalendarDate, 11302 as AccountNumber, 'Mr Ted Teddy' as AccountName, 0 as Transactions

    -- add data for additional account numbers...
),

StartingPoints as
(
    select AccountNumber, CalendarDate, Transactions,
           ROW_NUMBER() over(partition by AccountNumber order by CalendarDate) as rownum
    from TestData as A
    where not exists (
        select *
        from TestData as B
        where B.AccountNumber = A.AccountNumber and Transactions = 0 and dateadd(day, 1, B.CalendarDate) = A.CalendarDate
    )
    and Transactions = 0
),

EndingPoints as
(
    select AccountNumber, CalendarDate, Transactions,
           ROW_NUMBER() over(partition by AccountNumber order by CalendarDate) as RowNum
    from TestData as A
    where not exists (
        select *
        from TestData as B
        where B.AccountNumber = A.AccountNumber and Transactions = 0 and dateadd(day, -1, B.CalendarDate) = A.CalendarDate
    )
    and Transactions = 0
),

ZeroTransactionRanges as
(
    SELECT S.AccountNumber, S.CalendarDate AS start_range, E.CalendarDate AS end_range
    FROM StartingPoints AS S
    INNER JOIN EndingPoints AS E ON E.AccountNumber = S.AccountNumber AND E.RowNum = S.RowNum
),

ZeroRunLengths as
(
    select CalendarDate,
           t1.AccountNumber,
           datediff(day, start_range, CalendarDate) + 1 as runLength
    from ZeroTransactionRanges as t1
    INNER JOIN TestData as t2
    on t1.AccountNumber = t2.AccountNumber
    where start_range <= t2.CalendarDate and t2.CalendarDate <= end_range
)

select t1.*,
       case when t2.runLength is null then 0 else t2.runLength end as 'Count(Subsequent 0s)'
from TestData as t1
-- note the LEFT join here!
LEFT JOIN ZeroRunLengths as t2
on t1.AccountNumber = t2.AccountNumber and t1.CalendarDate = t2.CalendarDate
order by AccountNumber, CalendarDate

【讨论】:

    猜你喜欢
    • 2017-05-18
    • 1970-01-01
    • 1970-01-01
    • 2021-10-08
    • 2021-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多