2015-11-07 42 views
0

用下面的记录结构:计数有效的项目/年无临时今年表

<item> | <start> | <stop> 
Item-A | 2013-04-05 | 2014-06-07 
Item-B | 2012-06-07 | 2015-03-07 

是否可以使用SQL查询(在MS-SQL> = 2008和火鸟> = 2.5)多少个项目每年都活跃?结果应该是:

2012 | 1 
2013 | 2 
2014 | 2 
2015 | 1 

我用含系列(1900..2100)一temorary表和使用之间的连接源表和临时表,并提取(年..)。但是我正在寻找更好的解决方案,而不使用额外的表格。

+0

使用派生表的子查询/的/ CTE,而不是真正的表 – lad2025

+0

如果您需要声明可以在SQL Server和Firebird中使用,那么这是不太可能的。例如,从日期中提取年份的函数在两个数据库中是不同的 –

+0

为什么不创建一个包含数字1到一些任意大数(如1000)的永久性单列表并使用它来生成一系列年? – Bohemian

回答

1

这符合您的要求。

select Years.[Year], 
     count(1) [Count] 
from MyTable mt 
join (select distinct(year(start)) as [Year] 
     from MyTable 

     union 

     select distinct(year(stop)) 
     from MyTable 

     union 

     select year(getdate()) 
     from MyTable 
     where exists 
      (select 1 
      from MyTable 
      where stop is null)) as Years 
on Years.[Year] between Year(mt.start) and Year(isnull(mt.stop, getdate())) 
group by Years.[Year] 
order by Years.[Year] 
+0

子选择'年'不能返回不包含在任何开始/停止值中的年份,不是吗?例如,对于开始年份1980年和停止年份2014的单行,查询仅返回1980年和2014年? – cytrinox

+0

@ctrinox,你是对的,但通常与真实的数据我会相信,这永远不会是这样。看到我的其他答案,如果你的数据可以有这个。 – JBrooks

0

这就是我将如何使用帮助函数。

declare @StartMin datetime 
declare @StopMax datetime 

select @StartMin = min(start), 
@StopMax = max(isnull(stop, getdate())) 
from MyTable 

select Years.[Year], 
count(1) [Count] 
from MyTable mt 
join [dbo].[YearsBetween](@StartMin, @StopMax) as Years 
on Years.[Year] between Year(mt.start) and Year(isnull(mt.stop, getdate())) 
group by Years.[Year] 
order by Years.[Year] 

这是辅助功能,我有很多人,DatesBetween,MonthsBetween,NumbersBetween等

create function [dbo].[YearsBetween](@Start datetime, @Stop datetime) 
returns @Years TABLE 
(
[Year] int 
) 
begin 
declare @StartYear int 
declare @StopYear int 

set @StartYear = year(@Start) 
set @StopYear = year(@Stop) 

while(@StartYear <= @StopYear) 
begin 
    insert into @Years 
    values(@StartYear) 

    set @StartYear = @StartYear + 1 
end 

return; 
end