两年之间可用的年份

时间:2016-08-11 12:25:43

标签: sql sql-server date view

我有一个产品列表,每个产品都有[创建日期]和[结束日期](如果尚未结束,则为null)。我想找到一种方法来查看每个' YYYY-MM'的可用产品数量。我需要这个回到过去以及查看当前时间段。你有什么想法吗?

期望的结果:

enter image description here

原始数据:

enter image description here

2 个答案:

答案 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