SQL Server从列生成一组特定的年份值,它给出一个日期/年

时间:2014-03-16 20:01:23

标签: sql sql-server

假设下表

Maintable

我想使用上面的数据并将其转换为以下结果

ResultantSet

我可以考虑使用临时表和游标来逐步向结果中添加行来解决这个问题的唯一方法,因为原始表中的记录当前数以千计并且预计会呈指数上升。

任何人都有更好的主意吗?

由于

2 个答案:

答案 0 :(得分:6)

这是使用计数表或数字表的绝佳机会。也就是说,一个包含单个索引整数列的表,其中包含非负整数的排序序列。以下是一个看起来如何的例子:

number
--- 
0
1
2
3
...

使用此表,您可以使用基于集合的方法执行连接以应用算术运算。您的查询结构如下:

select a.id,
a.agreementyear + a.incrementalperiodinyears * t.number as yearinfocus
from agreements a
cross join tally t
where a.agreementperiodinyears >= a.incrementalperiodinyears * t.number
order by a.id,
a.incrementalperiodinyears * t.number

在您的数据库中拥有一个永久的计数表通常会派上用场,但如果您不这样做,您可以在临时表中创建一个。

如果数据包含不完美排列的协议期和增量期,您可能需要在where子句中添加一个检查以考虑余数(使用mod或转换为十进制)。例如,增量期为三年,但协议期为八年。

答案 1 :(得分:3)

(a.AgreementPeriodInYears / a.IncrementalPeriodInYears + 1)小于或等于10000时,以下解决方案将有效:

;WITH N10(Num) -- This CTE returns all numbers between 1 and 10
AS
(
    SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL 
    SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9 UNION ALL SELECT 10
), N100(Num) -- This CTE generates all numbers between 1 and 100
AS
(
    SELECT  (x.Num - 1)*10 + y.Num -- Test data
    FROM    N10 x CROSS JOIN N10 y 
), N10000(Num) -- This CTE generates all numbers between 1 and 10000
AS
(
    SELECT  (x.Num - 1)*100 + y.Num
    FROM    N100 x CROSS JOIN N100 y 
)
SELECT  a.ID, a.AgreementYear + a.IncrementalPeriodInYears * (b.Num - 1) AS AgreementYear
FROM 
(
    SELECT  1, 2011, 3, 9 UNION ALL
    SELECT  2, 2013, 2, 10
) a(ID, AgreementYear, IncrementalPeriodInYears, AgreementPeriodInYears)
INNER JOIN N10000 b ON b.Num <= (a.AgreementPeriodInYears / a.IncrementalPeriodInYears + 1)

注意:您应该使用源表替换(...) a派生表。