2016-09-29 27 views
2

我有4列 - 代码,金额,开始,结束。我想要在开始和结束列中的数量之间进行比较,并将它们更改为具有所有结果的一列。有关如何实现这一目标的任何建议?谢谢。SQL Server如何检索2个数字之间的所有数字

Current Results: 
Code Amount Start End 
1  5000 2015 2016 
2  5000 2014 2016 
3  20000 2012 2016 

Desired Results: 
Code Amount StartEnd 
1  5000 2015 
1  5000 2016 
2  5000 2014 
2  5000 2015 
2  5000 2016 
3  20000 2012 
3  20000 2013 
3  20000 2014 
3  20000 2015 
3  20000 2016 
+0

哪个版本的SQL Server的本

SELECT c.code, c.amount, f.yr FROM #code c CROSS APPLY fn_yearslist(c.startyr, c.endyr) f 

功能? – techspider

+0

对不起,2008年。 – ajc101

回答

5

您可以使用递归CTE生成所有的最低起点和终点最大的数字并加入对生成的数字。

with cte as (select min(start) col,max(end) mx from tablename 
      union all 
      select col+1,mx from cte where col < mx) 
select t.code,t.amount,c.col 
from cte c 
join tablename t on c.col between t.start and t.end 

或更简单地

​​
+0

也许我错了...左加入意味着,如果有没有价值的年份,将只有一行只有最后一列和空值,所以我想它的操作 – Hogan

+0

@霍根..离开这里不需要加入。 –

+0

没错,除非他想显示没有任何范围的年份。 – Hogan

1

另一种选择是一个UDF。我用这个TVF生成动态范围

Declare @YourTable table (Code int, Amount int, Start int , [End] int) 
Insert into @YourTable values 
(1,5000 ,2015,2016), 
(2,5000 ,2014,2016), 
(3,20000,2012,2016) 

Select A.Code 
     ,A.Amount 
     ,StartEnd = cast(B.RetVal as int) 
From @YourTable A 
Cross Apply (Select * from [dbo].[udf-Range-Number](A.Start,A.[End],1)) B 

返回

Code Amount StartEnd 
1  5000 2015 
1  5000 2016 
2  5000 2014 
2  5000 2015 
2  5000 2016 
3  20000 2012 
3  20000 2013 
3  20000 2014 
3  20000 2015 
3  20000 2016 

的功能

CREATE FUNCTION [dbo].[udf-Range-Number] (@R1 money,@R2 money,@Incr money) 
Returns Table 
Return (
    with cte0(M) As (Select cast((@[email protected])/@Incr as int)), 
     cte1(N) As (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N)), 
     cte2(N) As (Select Top (Select M from cte0) Row_Number() over (Order By (Select NULL)) From cte1 a,cte1 b,cte1 c,cte1 d,cte1 e,cte1 f,cte1 g,cte1 h) 

    Select RetSeq=1,[email protected] Union All Select N+1,(N*@Incr)[email protected] 
    From cte2 
) 
/* 
Max 100 million observations -- 
Syntax: 
Select * from [dbo].[udf-Range-Number](0,4,0.25) 
*/ 
0

我不知道这是否适用于SQL 2008,但这里有一个CTE:

;with sel_cte as (
select Code, Amount, start StartEnd 
from @tblTest t 

union all 

select t.code, t.amount, c.StartEnd + 1 StartEnd 
from sel_cte c 
    inner join @tblTest t on t.code = c.code 
where c.StartEnd + 1 <= [end] 
) 
select * 
from sel_cte 
order by Code, StartEnd 

注意:将@tblTest替换为实际的表名。

-1

如果要求允许您只有连续的数字(如2014年,2015年,然后2016年等),那么上述方法(cte)将工作正常。但是,如果没有,你可以创建另一个临时表(比如说有1列的数字),并且按照你想要的结果输出的连续顺序编号。

Number 
2014 
2015 
2016 
2018 <-- Missing 2017 and jumping on 2018 
2019 

然后使用右连接以渐进系列的形式获得结果,查询类似于下面的查询。

select Code, StartEnd, Amount from numbers 
    right join inputs on number between Start and End 
+0

我没有看到一些事情1)这与OP已经明确指出“检索2个数字之间的所有数字”表示连续数字的问题有什么关系。 2)你提到你可以填充另一个临时表,如果你想,但你没有展示如何做到这一点或讨论它的逻辑的任何方法。也许你认为cte方法会取得表格的最大和最小值并生成所有数字。因此,如果有突破,让我们说行3在哪里开始2009年结束2012年,那么你会错过2013年的数据?但该cte实际上可以忽略2013年 – Matt

+0

另一个表的方法可能会引入跳过数字的额外的灵活性,可能是,未来。我错过了创建和插入单孔表格的细节,假设单字表格连续编号应该易于创建和填充。而且,使用cte方法忽略或跳过数字将需要硬编码。对不起,我是从全栈背景来的,所有这些想法都是固有的。 – ash

0

您可以查询像你cancreate这样

CREATE FUNCTION fn_yearslist (@startyear int, @endyear int) 
RETURNS @t TABLE (
    yr int 
) 
AS 
BEGIN 
    WHILE (@startyear <= @endyear) 
    BEGIN 
    INSERT INTO @t (yr) 
     VALUES (@startyear) 
    SET @startyear += 1 
    END 
    RETURN 
END 
相关问题