我如何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
这样做的额外好处是,由于它是持久化的,如果您需要保存下游生成的任何数据,您可以在此处引用主键。它也更容易理解正在发生的事情。
我得到了两个整数类型的变量,@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
这样做的额外好处是,由于它是持久化的,如果您需要保存下游生成的任何数据,您可以在此处引用主键。它也更容易理解正在发生的事情。