我如何return 60组月份和年份数据在一个月份和年份列中?

How do I return 60 sets of month and year data in a month and year column?

我得到了两个整数类型的变量,@month@year(因此月份是 1、2、3、... 9、10、11、12,年份是四个-数字年份)。

我想要做的是创建一个 table 值函数,它将接受这两个参数和 return 过去 60 个月,然后到 2005 年结束。

因此,例如,对于 @month = 1@year = 2018,我希望 return 这个 table:

+----+------+
| 1  | 2018 |
+----+------+
| 12 | 2017 |
+----+------+
| 11 | 2017 |
+----+------+
| 10 | 2017 |
+----+------+
| 9  | 2017 |
+----+------+
| 8  | 2017 |
+----+------+
| 7  | 2017 |
+----+------+
| 6  | 2017 |
+----+------+
| 5  | 2017 |
+----+------+
| 4  | 2017 |
+----+------+
| 3  | 2017 |
+----+------+
| 2  | 2017 |
+----+------+
| 1  | 2017 |
+----+------+
| 12 | 2016 |
+----+------+
| 11 | 2016 |
+----+------+
| 10 | 2016 |
+----+------+
| 9  | 2016 |
+----+------+
| 8  | 2016 |
+----+------+
| 7  | 2016 |
+----+------+
| 6  | 2016 |
+----+------+
| 5  | 2016 |
+----+------+
| 4  | 2016 |
+----+------+
| 3  | 2016 |
+----+------+
| 2  | 2016 |
+----+------+
| 1  | 2016 |
+----+------+
| 12 | 2015 |
+----+------+
| 11 | 2015 |
+----+------+
| 10 | 2015 |
+----+------+
| 9  | 2015 |
+----+------+
| 8  | 2015 |
+----+------+
| 7  | 2015 |
+----+------+
| 6  | 2015 |
+----+------+
| 5  | 2015 |
+----+------+
| 4  | 2015 |
+----+------+
| 3  | 2015 |
+----+------+
| 2  | 2015 |
+----+------+
| 1  | 2015 |
+----+------+
| 12 | 2014 |
+----+------+
| 11 | 2014 |
+----+------+
| 10 | 2014 |
+----+------+
| 9  | 2014 |
+----+------+
| 8  | 2014 |
+----+------+
| 7  | 2014 |
+----+------+
| 6  | 2014 |
+----+------+
| 5  | 2014 |
+----+------+
| 4  | 2014 |
+----+------+
| 3  | 2014 |
+----+------+
| 2  | 2014 |
+----+------+
| 1  | 2014 |
+----+------+
| 12 | 2013 |
+----+------+
| 11 | 2013 |
+----+------+
| 10 | 2013 |
+----+------+
| 9  | 2013 |
+----+------+
| 8  | 2013 |
+----+------+
| 7  | 2013 |
+----+------+
| 6  | 2013 |
+----+------+
| 5  | 2013 |
+----+------+
| 4  | 2013 |
+----+------+
| 3  | 2013 |
+----+------+
| 2  | 2013 |
+----+------+
| 12 | 2012 |
+----+------+
| 12 | 2011 |
+----+------+
| 12 | 2010 |
+----+------+
| 12 | 2009 |
+----+------+
| 12 | 2008 |
+----+------+
| 12 | 2007 |
+----+------+
| 12 | 2006 |
+----+------+
| 12 | 2005 |
+----+------+

我正在考虑用几种方法来做到这一点,也许是交叉连接,或者是一些 while 循环——但它们看起来效率很低。我不认为它是最难做的,但我想为它编写 'good' 代码。我已经思考 "best" 方式好一段时间了。

不幸的是,我对数据如何到达我没有任何发言权,这是我需要提供的 return,否则我将使用日期数据类型和日期函数。

这使用递归 CTE。如果您的环境允许,我自然会使用 dimension table。这是一种方式,但最好的方式当然是有争议的。

declare @year int = 2018
declare @month int = 1



;with cte as(
    select [Month], [Year] = 2005
    from  (values(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)) as X([Month]) 
    union all
    select [Month], [Year] + 1
    from cte
    where [Year] < @year
),

someYears as(
select [Years] = 2005
union all
select [Years] + 1
from someYears
where [Years] < @year),

t as(
select  *, RN = row_number() over (order by [Year] desc, [Month] desc) 
from cte
where [Month] <= case when [Year] = @year then @month else 13 end)


select [Month], [Year]
from t
where RN <= 60
union 
select 12, [Years]
from (select [Years] from someYears) x
where x.Years < @year
order by [Year] desc, [Month] desc

我的偏好是在 table 中坚持这一点。基本上,创建一个尽可能远的 table,然后让它进入大约 50 年后的未来。然后,您的函数可以 select 来自 table.

table:

create table MonthDim
(
PK_ID int identity(1, 1) primary key,
Month int,
Year int,
Dt date --set this to the first of each month
)

查询:

select *
from MonthDim
where dt >= dateadd(month, -60, datefromparts(@year, @month, 1))
    and dt <= datefromparts(@year, @month, 1)

union all

select *
from MonthDim
where dt < dateadd(month, -60, datefromparts(@year, @month, 1))
    and Month = 12

这样做的额外好处是,由于它是持久化的,如果您需要保存下游生成的任何数据,您可以在此处引用主键。它也更容易理解正在发生的事情。