我提供了两个变量,@month
和@year
整数类型(因此月份是1,2,3,... 9,10,11,12和年份是四位数年)。
我要做的是创建一个表值函数,它将接收这两个参数并返回过去60个月,然后年终结束到2005年。
因此,例如,对于@month = 1
和@year = 2018
,我希望返回此表:
+----+------+
| 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循环 - 但它们似乎效率很低。我不认为这是最难做到的,但我想为它编写“好”的代码。很长一段时间以来,我一直在思考“最好”的方式。
不幸的是,我对数据的来源没有任何发言权,这是我需要提供的回报,否则我会使用日期数据类型和日期函数。
答案 0 :(得分:2)
这使用递归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
答案 1 :(得分:2)
我倾向于将其保留在表格中。基本上,创建一个尽可能远的桌子,然后让它在未来50年左右。然后,您的函数可以从该表中选择。
表:
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
这样做的另一个好处是,由于它是持久的,如果你需要保存下游生成的任何数据,你可以在这里引用主键。它也更容易理解正在发生的事情。