使用分区运行不同的计数

时间:2016-08-04 11:16:56

标签: sql sql-server sql-server-2016

对于以下数据,我希望按年份分区运行不同的计数:

DROP TABLE IF EXISTS #FACT;
CREATE TABLE #FACT("Year" INT,"Month" INT, "Acc" varchar(5));
INSERT INTO #FACT
    values 
        (2015, 1, 'A'),
        (2015, 1, 'B'),
        (2015, 1, 'B'),
        (2015, 1, 'C'),
        (2015, 2, 'D'),
        (2015, 2, 'E'),
        (2015, 3, 'E'),
        (2016, 1, 'A'),
        (2016, 1, 'A'),
        (2016, 2, 'B'),
        (2016, 2, 'C');
SELECT * FROM #FACT;    

以下内容会返回正确的答案,但是还有一种更简洁的方式吗?

WITH 
dnsRnk AS
(
    SELECT 
        "Year"
        , "Month"
        , DenseR  = DENSE_RANK() OVER(PARTITION BY "Year", "Month" ORDER BY "Acc")
    FROM #FACT
),
mxPerMth AS
(
    SELECT
        "Year"
        , "Month"
        , RunningTotal = MAX(DenseR)
    FROM dnsRnk
    GROUP BY 
        "Year"
        , "Month"
)
SELECT 
    "Year"
    , "Month"
    , X = SUM(RunningTotal) OVER (PARTITION BY "Year" ORDER BY "Month")
FROM mxPerMth
ORDER BY 
    "Year"
    , "Month";

以上内容返回以下内容 - 答案也应该返回完全相同的表:

enter image description here

2 个答案:

答案 0 :(得分:1)

如果您想要不同帐户的运行计数:

select f.*,
       sum(case when seqnum = 1 then 1 else 0 end) over (partition by year order by month) as cume_distinct_acc
from (select f.*,
             row_number() over (partition by account order by year, month) as seqnum
      from #fact f
     ) f;

这会在出现的第一个月内对每个帐户进行计数。

编辑:

糟糕。以上内容不按年份和月份汇总,然后每年重新开始。这是正确的解决方案:

select yyyy, mm,
       sum(sum(case when seqnum = 1 then 1 else 0 end)
          ) over (partition by year order by month) as cume_distinct_acc
from (select f.*,
             row_number() over (partition by account, year order by month) as seqnum
      from #fact f
     ) f
group by year, month
order by year, month;

并且,SQL Fiddle不起作用,但以下是一个例子:

with FACT as (
    SELECT yyyy, mm, account
    FROM (values 
        (2015, 1, 'A'),
        (2015, 1, 'B'),
        (2015, 1, 'B'),
        (2015, 1, 'C'),
        (2015, 2, 'D'),
        (2015, 2, 'E'),
        (2015, 3, 'E'),
        (2016, 1, 'A'),
        (2016, 1, 'A'),
        (2016, 2, 'B'),
        (2016, 2, 'C')) v(yyyy, mm, account)
     )
select yyyy, mm,
       sum(sum(case when seqnum = 1 then 1 else 0 end)) over (partition by yyyy order by mm) as cume_distinct_acc
from (select f.*,
             row_number() over (partition by account, yyyy order by mm) as seqnum
      from fact f
     ) f
group by yyyy, mm
order by yyyy, mm;

答案 1 :(得分:1)

Demo Here:

;with cte
as
(select yearr,monthh,count( distinct acc) as cnt  from #fact
group by yearr,monthh
)
select yearr,monthh,
sum(cnt) over (Partition by yearr order by yearr,monthh rows  unbounded preceding ) as x
from cte