使用SQL重复记录序列

时间:2009-09-28 12:22:34

标签: sql sql-server tsql stored-procedures

这可以使用代码轻松完成,但我想知道是否可以使用SQL Server(2008)在数据库级别完成。

我有一张类似于下面的表格:

CROP_ID   YEAR_   PRODUCTION   
1         1       0  
1         2       300  
1         3       500  
2         1       100
2         2       700

我希望能够针对每种作物类型的 n 年份运行查询重复此操作,例如

CROP_ID  YEAR_  PRODUCTION  
1        1      0  
1        2      300  
1        3      500  
1        4      0  
1        5      300
1        6      500
etc.

我不确定最好的方法,我认为我需要一个SP并传入一个年变量,并使用循环结构?然而确切的语法让我感到惊讶。任何帮助赞赏。

更新

很抱歉没有提供原始帖子中的所有信息。该表将允许多种裁剪类型,并且可以更新Produciton值,因此具有固定变量的Case语句不太适合。道歉不清楚。

更新

通过TVF答案,我使用以下修改过的SQL来选择CropType 20年。

select top 20 b.CROP_ID,  
YEAR_ = n.num * (select count() from MyBaseTable where CROP_ID = 3) + b.YEAR,  
b.PRODUCTION from MyBaseTable b, dbo.fnMakeNRows(20) n  
where CROP_ID = 3  

4 个答案:

答案 0 :(得分:2)

您可以在标准SQL中执行此操作,而无需创建存储过程或使用临时表。以下示例将执行此操作12年。您可以将其延长至任意年限:

insert into CropYield
(CropID, Year_, Production)
Select 1, a.a + (10 * b.a), 
    case (a.a + (10 * b.a)) % 3
        when 0 then 500
        when 1 then 0
        when 2 then 300
    end
from (Select 0 as a union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) as a
cross join (Select 0 as a union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) as b
where a.a + (10 * b.a) between 1 and 12

答案 1 :(得分:1)

在不需要存储过程的情况下生成此类数据的常用技巧是使用 常量表 。因为这样的表可以是通用的,所以可以使用1到100之间的所有整数,甚至1到1,000来创建它,具体取决于使用情况。

例如

CREATE TABLE tblConstNums
( I INT )
INSERT INTO tblConstNums VALUES (1) 
INSERT INTO tblConstNums VALUES (2) 
INSERT INTO tblConstNums VALUES (3) 
INSERT INTO tblConstNums VALUES (4) 
INSERT INTO tblConstNums VALUES (5)
-- ...
INSERT INTO tblConstNums VALUES (1000)

解决方案可以以声明方式编写(无需存储过程或更一般的程序性陈述:

SELECT CROP_ID,  YEAR_ * I,   PRODUCTION 
FROM myCropTable T
JOIN tblConstNums C on 1=1
WHERE I in (1, 2, 3)
order by CROP_ID,  YEAR_ * I,   PRODUCTION

请注意,常量表可能包含常用案例的几列。例如,即使其中许多可以表示为基本0到n序列中数字的数学表达式,但是可以有一个只有偶数的列,另一个有奇数的列,另一个有5的倍数等。如果它足够小,在常量表上不需要索引,但这些索引可能对更大的开启有用。

答案 2 :(得分:1)

使用这个:

WITH tn (n) as
(
    SELECT 0
  UNION ALL
    SELECT n+1
    FROM tn
  WHERE tn.n < 10
)
SELECT DISTINCT t.CROP_ID, t.YEAR_ + (3*tn.n), t.PRODUCTION
FROM table t, tn 

/*    
    WHERE tn.n < 10 ==> you will get 1 -> (10*3) + 3 = 33

*/

答案 3 :(得分:1)

您可以使用表值函数而不是存储过程,这样可以更灵活地处理结果(因为它可以直接从中选择,插入另一个表,连接到其他表,等)。

您还可以通过让TVF生成N行(每行上的数字从0到N-1)使其更通用,然后使用一些简单的表达式从中生成所需的列。我发现这样的TVF在各种情况下都很有用。

如果你需要生成比0..N-1和简单表达式更复杂的数据,那么你应该创建一个专门满足你特定需求的TVF。

以下示例显示了如何使用通用TVF生成您要求的数据:

create function fnMakeNRows (@num as integer)
returns @result table (num integer not null) as
begin
 if @num is null or @num = 0
 begin
  return
 end
 declare @n as integer
 set @n = 0
 while @n < @num
 begin
  insert into @result values (@n)
  set @n = @n + 1
 end
 return
end
go

select
 CROP_ID = 1,
 YEAR_ = num,
 PRODUCTION = case num % 3 when 0 then 0 when 1 then 300 else 500 end
from dbo.fnMakeNRows(100000)

您也可以使用它来复制现有表格中的行(我认为它更像您想要的)。例如,假设base_table包含问题开头的三行,您可以使用以下内容将3行转换为60行:

select
 b.CROP_ID,
 YEAR_ = n.num * (select count(*) from base_table) + b.YEAR_,
 b.PRODUCTION
from base_table b, dbo.fnMakeNRows(20) n

这(希望)显示了通用fnMakeNRows函数的实用程序。