我有一张会员桌,部分内容如下:
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"类型语句,或适合的函数?
感谢。
答案 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');