2017-01-17 11 views
0

私は[Membership]という名前の[Membership]という名前のテーブルと、[member from date]と[member to date]という名前の2つの日付フィールドを持っています。メンバー日付範囲の間のデータ

毎月のメンバーシップを要約する必要があります。メンバーは、その月全体のメンバーである場合にのみ、その月にカウントされます。

たとえば、[会員の日付]が '2014-02-01'で[会員の日付]が '2015-03-01'の人は2014年12月の月にカウントされますが、 [会員の日付]が、例えば、 '2014年12月25日'であってはならない。

私は毎月1月に要約する必要があります、そして、私はこのテーブルに何千人ものメンバーを持っています。結果はこれに似てする必要があります。

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

私はので、「彼らはその全体の月のメンバーである場合にのみ、」ルールのこの仕事にどのように見ることができません。

ご協力いただければ幸いです。

+0

? – LONG

+0

たとえば、2014年12月のメンバーシップを計上している場合、[Member from date] <= '2014-12-01'および[Member to date]> = '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を使用することができます。あなたが与えた例は、Mar.2015のメンバーではないだろう、なぜ

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