2017-01-17 122 views
0

我在SQL Server 2014中有一個名爲[Membership]的表,其中包含個人成員數據和兩個名爲[member from date]和[member to date]的日期字段。成員日期範圍內的數據

我需要總結每月的會員資格。只有當他們是整個月份的會員時,會員才能在給定的月份內進行統計。

因此,例如,[2014-02-01] [會員]和[2015-03-01] [會員]的會員將在2014年12月份計算,但會如果[迄今爲止的成員]是'2014-12-25'則不是。

我需要每個月回顧一下2010年1月的情況,我在這張表中有成千上萬的會員。結果需要類似於此:

Month  Count 
Jan 2010 3230 
Feb 2010 3235 
Mar 2010 3232 
.. 
Dec 2016 6279 

我看不出如何工作,因爲「只有當他們是爲整個月的成員」的規則這一點。

任何幫助將不勝感激!

+0

爲什麼你給了就不會在Mar.2015成員的例子嗎? – LONG

+0

例如,如果我們計算2014年12月的會員資格,那麼我將按[會員從日期] <='2014-12-01'和[會員至日期]> ='2014-12-31'進行過濾。希望澄清。謝謝! – Baldy

回答

1

使用spt_values和cte生成日曆,這裏是一個計數成員的示例。

declare @members table (member int, start_date date, end_date date) 
insert @members select 1, '2015-12-15', '2017-01-15' 
insert @members select 2, '2016-01-15', '2016-12-15' 
insert @members select 3, '2016-03-01', '2016-10-31' 

declare @cal_from datetime = '2016-01-01'; 
declare @cal_to datetime = '2016-12-31'; 

with calendar_cte as (
    select top (datediff(month, @cal_from, @cal_to) + 1) 
      [Month] = month(dateadd(month, number, @cal_from)) 
      , [Year] = year(dateadd(month, number, @cal_from)) 
      , [Start] = dateadd(month, number, @cal_from) 
      , [End] = dateadd(day, -1, dateadd(month, number + 1, @cal_from)) 
    from  [master].dbo.spt_values 
    where [type] = N'P' 
    order by number 
) 
select [Month] 
    , [Year] 
    , [Count] = (select count(*) 
        from @members 
        where start_date <= [Start] 
         and end_date >= [End]) 
from calendar_cte 
0

隨着月表的幫助下,這可以很容易地處理:

/* creating a months table */ 

create table dbo.Months([Month] date primary key, MonthEnd date); 

declare @StartDate  date = '20100101' 
     ,@NumberOfYears int = 30; 

insert dbo.Months([Month],MonthEnd) 
    select top (12*@NumberOfYears) 
     [Month] = dateadd(month, row_number() over (order by number) -1, @StartDate) 
     , MonthEnd = dateadd(day,-1, 
      dateadd(month, row_number() over (order by number), @StartDate) 
      ) 
    from master.dbo.spt_values; 

    /* the query */ 

select [Month], [Count]=count(*) 
    from dbo.Months mo 
    inner join dbo.[Membership] me on 
    /* Member since the start of the month */ 
      me.MemberFromDate >= mo.[Month] 
    /* Member for the entire month being counted */ 
     and me.MemberToDate > mo.[MonthEnd] 
    group by [Month] 
    order by [Month] 

如果你真的不希望有一個表個月,你可以使用一個cte這樣的:

declare @StartDate  date = '20100101' 
     ,@NumberOfYears int = 30; 

;with Months as (
select top (12*@NumberOfYears) 
    [Month] = dateadd(month, row_number() over (order by number) -1, @StartDate) 
    , MonthEnd = dateadd(day,-1, 
      dateadd(month, row_number() over (order by number), @StartDate) 
     ) 
    from master.dbo.spt_values 
) 

    /* the query */ 

select [Month], [Count]=count(*) 
    from Months mo 
    inner join dbo.[Membership] me on 
    /* Member since the start of the month */ 
      me.MemberFromDate >= mo.[Month] 
    /* Member for the entire month being counted */ 
     and me.MemberToDate > mo.[MonthEnd] 
    group by [Month] 
    order by [Month] 
+0

謝謝,我發現這很容易理解,現在就做我想做的事。 – Baldy

+0

樂意幫忙@Baldy – SqlZim

0
create table members(name varchar(50),fromdate datetime, todate datetime) 
go 
create table months(firstday datetime) 
go 
insert members values('Joe','2014-02-01','2015-03-25'),('Jon','2014-03-12','2015-01-12') 

declare @date datetime = '2000-01-01' 
while (@date < '2016-01-01') 
begin 
    insert into months values(@date) 
    select @date = dateadd(month,1,@date) 
end 

with MyCTE(date) as 
( select left(convert(varchar, firstday, 120),7) 
    from members m 
    join months d on d.firstday > m.fromdate and d.firstday < datefromparts(year(m.todate),month(m.todate),1) 
) 
select date as 'month', count(*) as 'count' 
from MyCTE 
group by date