使用游标生成空行

时间:2016-11-11 07:18:19

标签: sql sql-server sql-server-2008 tsql

我想生成一份年度报告,用户在月份和年份开始插入帐号。使用这些数据我想生成一个临时表,它开始从选定年份的起始月份到12个月后提供用户资源使用情况统计数据。

我正在使用光标这样做。现在,当用户未使用该资源达到某个月时,就会出现问题。我仍然希望临时表为这些月生成空列。我该怎么办?

 declare @account_no varchar(max)                             
 declare @resourse_usage int 
 declare @month int
 declare @year int
 declare @month1 int
 declare @year1 int 

declare @tempdatatable table                                  
(    account_no varchar(max),                             
    resourse_usage int, 
    month int,
    year int,                             
)                        

DECLARE array1 cursor for                        
    select account_no,resourse_usage,month,year from tblstats where account_no=1 and month>@month and year=@year
open array1                                
fetch next from array1 into @account_no,@resourse_usage,@month1,@year1
while @@fetch_status=0                                
begin                           

 insert into @tempdatatable                              
 (account_no,resourse_usage,month,year)                              
values                              
 (@account_no,@resourse_usage,@month1,@year1)    
 fetch next from array1 into @account_no,@resourse_usage,@month1,@year1
end                                
close array1                                
deallocate array1 
select * from @tempdatatable

2 个答案:

答案 0 :(得分:2)

首先,没有理由为此使用游标;简单地使用select语句将允许优化器完成其工作,即使没有任何额外的优化,不使用游标也会运行得更快。 SQL是关于处理元组(行)的集合,如果你可以用集合来表示问题,那么有很多智能代码可以为你工作。

在这种情况下,解决方案是在两个集合的联合上使用group by。第一组是您在问题中选择的那一组(我假设您在名为@account的变量中有目标帐号#):

select account_no,resourse_usage,month,year
from tblstats 
where account_no=@account and (
    month >= @month and year = @year or
    month <  @month and year = @year+1
)

第二组是报告期内所有月份的集合:

;With Months( Month ) as
(
    Select 1 as Month
    union all
    Select Month + 1
        from Months
        where month < 12
)
select @account as account_no, NULL as resourse_usage, month, 
case when month >= @month then @year else @year+1 end as year
from Months

将所有这些结合起来,我们得到:

;With Months( Month ) as
(
    Select 1 as Month
    union all
    Select Month + 1
        from Months
        where month < 12
)
select account_no, max(resourse_usage) as resourse_usage, month, year
from (
    select account_no, resourse_usage, month, year
    from tblstats 
    where account_no=@account and (
        month >= @month and year = @year or
        month <  @month and year = @year+1
    )
    union
    select @account as account_no, NULL as resourse_usage, month, 
    case when month >= @month then @year else @year+1 end as year
    from Months
) G
group by account_no, month, year

答案 1 :(得分:1)

尝试使用months声明临时表并更改游标中的语句:

declare @tblMonths table(month int)
insert into @tblMonths (month) values (1), (2), (3), (4), (5), (6) ,(7), (8), (9), (10), (11), (12)

和 游标语句

select t.account_no,t.resourse_usage, isnull(t.month, m.month) as month, isnull(t.year, @year) 
from tblstats t 
    right join @tblMonths m on t.month = m.month
where t.account_no=1 and t.month>@month and t.year=@year