计算仅知道开始日期和到期日期的每个月的活动成员数

时间:2015-12-12 05:56:17

标签: sql count summary

我有一张会员桌,部分内容如下:

   MemberID     StartDate   StopDate
    555753      1/1/2010    1/1/2010
    222458      1/1/2011    12/1/9999
    707222      1/1/2011    12/1/9999
    312643      4/1/2011    1/1/2015
    489112      7/1/2011    12/1/9999
    228466      3/1/2012    12/1/9999
    388456      2/1/2010    8/1/2010
    122345      7/1/2013    2/1/2014
    345677      8/1/2014    12/1/9999
    113884      8/1/2014    12/1/9999
    645322      3/1/2015    12/1/9999
    587432      7/1/2010    12/1/2011
    197534      4/1/2015    12/1/2015
    522345      9/1/2015    12/1/9999
    723891      10/1/2015   12/1/9999
    ...

显示12/1/9999的过期日期代表具有终身会员资格的成员。 ID号与开始日期或结束日期之间没有相关性。每个成员都是一个记录。我正在尝试创建一个汇总表,显示从2010年1月开始到当前的每个月的活跃成员数。每个月随机数量的成员加入,而其他成员则离开。记录的月份永远不会比当月更新(限制终身会员追踪的月份)。

             Qty
MonthBucket Members
01-2010      25
02-2010      24
03-2010      25
04-2010      28
05-2010      39
06-2010      35
07-2010      31
08-2010      37
09-2010      42
10-2010      44
11-2010      45
12-2010      41
01-2011      40
02-2011      33
03-2011      37
04-2011      38
05-2011      42
06-2011      45
...

在计算每个月加入的会员数量或每个月失去的会员数量时,我已经看到了很好的解决方案,因为它们计算了开始和停止日期。计数逻辑的下一步是简单地从加入的数字中减去数字。但是,您如何解释开始日期和停止日期之间的隐含月份?我想用if语句做一些循环来比较是否计算的月份是在开始日期和结束日期之间,但我对SQL编程是相当新的,有没有"做的不是EOF"类型语句,或适合的函数?

感谢。

2 个答案:

答案 0 :(得分:1)

主要问题是您要打印MonthBuckets,那个月的会员资格表中没有数据。原则上你必须生成桶表。虽然它可以在飞行中完成,但我建议保存一次并使用它。这将使您想要的查询非常简单。

制作样本数据

CREATE TABLE membership (
id int,
fromDate date,
toDate date
);

INSERT INTO membership (id, fromDate, toDate)
VALUES
(1, '2014-01-01', '2014-05-10'),
(2, '2014-02-02', '2014-03-10'),
(3, '2014-02-03', '2014-05-10'),
(4, '2014-03-03', '9999-12-31'),
(5, '2014-04-04', '2014-08-08'),
(6, '2015-01-01', '9999-12-31'),
(7, '2015-07-07', '2015-08-08');

现在制作水桶表

CREATE TABLE monthBucket(
bucketName nvarchar(10),
bucketFirstDay date,
bucketLastDay date 
);

;WITH
  Pass0 as (select 1 as C union all select 1), --2 rows
  Pass1 as (select 1 as C from Pass0 as A, Pass0 as B),--4 rows
  Pass2 as (select 1 as C from Pass1 as A, Pass1 as B),--16 rows
  Pass3 as (select 1 as C from Pass2 as A, Pass2 as B),--256 rows
  Pass4 as (select 1 as C from Pass3 as A, Pass3 as B),--65536 rows
  Tally as (select row_number() over(order by C) as Number from Pass4)
INSERT monthBucket(bucketName, bucketFirstDay)
SELECT  
RIGHT('0000'+CONVERT(nvarchar(10), Y.Number),4) + '-'+ RIGHT('00'+CONVERT(nvarchar(10), M.Number),2),
CONVERT(date, convert(nvarchar(10), Y.Number)+'-'+convert(nvarchar(10),M.Number)+'-01')
FROM Tally as Y
CROSS JOIN Tally as M
WHERE Y.Number < 2100 AND y.Number >= 1980
AND M.Number <= 12

;UPDATE monthBucket SET bucketLastDay = EOMONTH(bucketFirstDay)
--UPDATE monthBucket SET bucketLastDay = DATEADD(DAY, -1, DATEADD(MONTH, 1, bucketFirstDay))

这个丑陋的代码实际构建了非常简单的表:

bucketName  bucketFirstDay  bucketLastDay
1980-01     1980-01-01      1980-01-31
1980-02     1980-02-01      1980-02-29
1980-03     1980-03-01      1980-03-31
1980-04     1980-04-01      1980-04-30
1980-05     1980-05-01      1980-05-31
1980-06     1980-06-01      1980-06-30
1980-07     1980-07-01      1980-07-31
1980-08     1980-08-01      1980-08-31
1980-09     1980-09-01      1980-09-30
1980-10     1980-10-01      1980-10-31
...

现在我们终于可以查询

SELECT bucketName, 
(SELECT COUNT(*) FROM membership WHERE fromDate <= bucketLastDay)
-(SELECT COUNT(*) FROM membership WHERE toDate < bucketFirstDay)
as membersCount
FROM monthBucket
WHERE bucketLastDay >= (SELECT MIN(fromDate) FROM membership) 
  AND bucketFirstDay <= GETDATE()
ORDER BY bucketFirstDay

和输出

bucketName  membersCount
2014-01     1
2014-02     3
2014-03     4
2014-04     4
2014-05     4
2014-06     2
2014-07     2
2014-08     2
2014-09     1
2014-10     1
2014-11     1
2014-12     1
2015-01     2
2015-02     2
2015-03     2
2015-04     2
2015-05     2
2015-06     2
2015-07     3
2015-08     3
2015-09     2
2015-10     2
2015-11     2
2015-12     2

答案 1 :(得分:-1)

如果您想以相同的方式但按成员类型检索计数,该怎么办?

CREATE TABLE membership (
id int,
fromDate date,
toDate date,
type varchar(10)
);

INSERT INTO membership (id, fromDate, toDate, type)
VALUES
(1, '2014-01-01', '2014-05-10','gold'),
(2, '2014-02-02', '2014-03-10','gold'),
(3, '2014-02-03', '2014-05-10','silver'),
(4, '2014-03-03', '9999-12-31','silver'),
(5, '2014-04-04', '2014-08-08','gold'),
(6, '2015-01-01', '9999-12-31','bronze'),
(7, '2015-07-07', '2015-08-08','silver');