我有一个产品列表,每个产品都有[创建日期]和[结束日期](如果尚未结束,则为null)。我想找到一种方法来查看每个' YYYY-MM'的可用产品数量。我需要这个回到过去以及查看当前时间段。你有什么想法吗?
期望的结果:
原始数据:
答案 0 :(得分:0)
以下是返回所有活动期间的代码:
SELECT * INTO #MyTable FROM (VALUES
(1,'2016-05-05','2016-07-23'),
(2,'2015-04-05',Null),
(3,'2016-05-05',Null),
(4,'2016-01-01',Null),
(5,'2015-02-12','2016-07-23'),
(6,'2016-03-05',Null),
(7,'2013-04-15','2016-05-05'),
(8,'2016-04-10',Null),
(9,'2015-09-09',Null),
(10,'2012-08-08','2016-07-23'),
(11,'2016-06-06',Null),
(12,'2016-07-07',Null)
) as x (ID, Created,[End])
GO
;WITH MinMax as (
SELECT
DATEDIFF(month,MIN(Created),MAX(Created))+1 as MCNT,
DATEDIFF(day,MIN(Created),MAX(Created))+1 as DCNT,
DATEADD(day,1-day(MIN(Created)),MIN(Created)) as MBegin,
DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,MAX(Created))+1,0)) as MEnd
FROM #MyTable
), Periods1 as (
SELECT TOP (SELECT MCNT FROM MinMax)
DATEADD(Month,ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) - 1,MBegin) as MBegin,
DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,DATEADD(Month,ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) - 1,MBegin))+1,0)) as MEnd
FROM sys.messages CROSS JOIN MinMax
), Periods2 as (
SELECT ID, DATEADD(Day,rn,Created) as CDay, [End]
FROM #MyTable
CROSS JOIN (SELECT TOP (SELECT DCNT FROM MinMax) ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) - 1 as rn
FROM sys.messages) as r
WHERE DATEADD(Day,rn,Created) < (SELECT MEnd FROM MinMax) and
([End] is Null or DATEADD(Day,rn,Created) <= [End])
), Available as (
SELECT MBegin, ID FROM Periods1 as p1
INNER JOIN Periods2 as p2 ON p2.CDay between p1. MBegin and MEnd
GROUP BY MBegin, ID
)
SELECT CONVERT(VARCHAR(7),MBegin,121) as 'Year-Month'
, COUNT(*) as 'Products Active'
FROM Available
GROUP BY MBegin
ORDER BY MBegin Desc;
GO
答案 1 :(得分:0)
尝试
-- parameters
declare
@sy int = 2014,
@sm int = 5,
@nm int = 30;
with months as (
-- use tally table instead, if present
select top(@nm) n = @sy*12 + @sm - 1 + row_number() over (order by (select null))
from sys.all_objects
)
select year=(m.n-1)/12, month=(m.n-1)%12 + 1, cnt = count(*)
from (
-- sample data
values (1, cast ('20160105' as date), cast(null as date))
,(2, cast ('20151115' as date), cast('20160302' as date))
) t (id, startDate, endDate)
join months m ON m.n between year(startDate)*12 + month(startDate)
and coalesce (year(endDate)*12 + month(endDate), 9999999)
group by m.n
order by m.n;
如果您需要显示没有数据的月份,请反转连接顺序
-- parameters
declare
@sy int = 2014,
@sm int = 5,
@nm int = 30;
with months as (
-- use tally table instead, if present
select top(@nm) n = @sy*12 + @sm - 1 + row_number() over (order by (select null))
from sys.all_objects
)
select year=(m.n-1)/12, month=(m.n-1)%12 + 1, cnt = count(t.id)
from months m
left join (
-- sample data kindly provided by Slava Murygin
values
(1,cast('2016-05-05' as date),cast('2016-07-23' as date)),
(2,'2015-04-05',Null),
(3,'2016-05-05',Null),
(4,'2016-01-01',Null),
(5,'2015-02-12','2016-07-23'),
(6,'2016-03-05',Null),
(7,'2013-04-15','2016-05-05'),
(8,'2016-04-10',Null),
(9,'2015-09-09',Null),
(10,'2012-08-08','2016-07-23'),
(11,'2016-06-06',Null),
(12,'2016-07-07',Null)
) t (id, startDate, endDate)
on m.n between year(startDate)*12 + month(startDate)
and coalesce (year(endDate)*12 + month(endDate), 9999999)
group by m.n
order by m.n;
结果
year month cnt
2014 5 2
2014 6 2
2014 7 2
2014 8 2
2014 9 2
2014 10 2
2014 11 2
2014 12 2
2015 1 2
2015 2 3
2015 3 3
2015 4 4
2015 5 4
2015 6 4
2015 7 4
2015 8 4
2015 9 5
2015 10 5
2015 11 5
2015 12 5
2016 1 6
2016 2 6
2016 3 7
2016 4 8
2016 5 10
2016 6 10
2016 7 11
2016 8 8
2016 9 8
2016 10 8