Sql 日期范围之间的成员数据

Sql 日期范围之间的成员数据,sql,sql-server,date,grouping,Sql,Sql Server,Date,Grouping,我在SQL Server 2014中有一个名为[Membership]的表,其中包含个人成员数据和两个名为[member from date]和[member to date]的日期字段 我需要总结一下每月的会员情况。只有当某个会员是该整月的会员时,该会员才算是该月的会员 因此,例如,【自日期起的会员】为“2014-02-01”,而【截至日期止的会员】为“2015-03-01”的人士将计入2014年12月,但如果【截至日期止的会员】为“2014-12-25”,则不计入2014年12月 从2010

我在SQL Server 2014中有一个名为[Membership]的表,其中包含个人成员数据和两个名为[member from date]和[member to date]的日期字段

我需要总结一下每月的会员情况。只有当某个会员是该整月的会员时,该会员才算是该月的会员

因此,例如,【自日期起的会员】为“2014-02-01”,而【截至日期止的会员】为“2015-03-01”的人士将计入2014年12月,但如果【截至日期止的会员】为“2014-12-25”,则不计入2014年12月

从2010年1月开始,我每个月都要总结一下,这个表中有数千名成员。结果需要与此类似:

Month      Count
Jan 2010   3230
Feb 2010   3235
Mar 2010   3232
..
Dec 2016   6279
我不知道该怎么做,因为只有当他们是整月规则的会员时


任何帮助都将不胜感激

使用spt_值和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

借助月数表,可以非常轻松地处理此问题:

  /* 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]

为什么您给出的示例不会出现在2015年3月的会员中?例如,如果我们计算2014年12月的会员人数,那么我将按[会员起始日期]=“2014-12-31”进行过滤。希望这能澄清问题。谢谢谢谢你,我发现这很容易理解,现在我想让它做什么就做什么。很高兴帮助@Baldy
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