ms sql 2000 游标的使用

与windows或DOS的“光标”不同,MS-SQL的游标是一种临时的数据库对象,既对可用来旋转储存在系统永久表中的数据行的副本,也可以指向储存在系统永久表中的数据行的指针。
游标为您提供了在逐行的基础上而不是一次处理整个结果集为基础的操作表中数据的方法。

1.如何使用游标

1)定义游标语句 Declare <游标名> Cursor For
2)创建游标语句 Open <游标名>
3)提取游标列值、移动记录指针 Fetch <列名列表> From <游标名> [Into <变量列表>]
4)使用@@Fetch_Status利用While循环处理游标中的行
5)删除游标并释放语句 Close <游标名>/Deallocate <游标名>
6)游标应用实例

--定义游标
Declare cur_Depart Cursor
For Select cDeptID,cDeptName From Department into @DeptID,@DeptName
--创建游标
Open cur_Depart
--移动或提取列值
Fetch From cur_Depart into @DeptID,@DeptName
--利用循环处理游标中的列值
While @@Fetch_Status=0
Begin
Print @DeptID,@DeptName
Fetch From cur_Depart into @DeptID,@DeptName
End
--关闭/释放游标
Close cur_Depart
Deallocate cur_Depart

2.语句的详细及注意

1)定义游标语句

Declare <游标名> [Insensitive] [Scroll] Cursor
For <Select 语句> [FOR {Read Only | Update [ OF <列名列表>]}]

  • Insensitive DBMS创建查询结果集数据的临时副本(而不是使用直接引用数据库表中的真实数据行中的列)。游标是Read Only,也就是说不能修改其内容或底层表的内容;
  • Scroll 指定游标支持通过使用任意Fetch 选项(First Last Prior Next Relative Absolute)选取它的任意行作为当前行。如果此项省略,则游标将只支持向下移动单行(即只支持游标的Fetch Next);
  • Select语句 定义游标结果集的标准 SELECT 语句。在游标声明的 <Select语句>内不允许使用关键字 COMPUTE、COMPUTE BY、FOR BROWSE 和 INTO;
  • Read Only 防止使用游标的用户通过更新数据或删除行改变游标的内容;
  • Update 创建可更新游标且列出值能被更新的游标列。如果子句中列入了任意列,则只有被列入的列才能被更新。如果Declare Cursor语句中只指定的UPDATE(没有列名列表),则游标将允许更新它的任何或所有列。
    Declare cur_Depart Cursor
    For Select * From Department For Update OF cDeptID,cDeptName

2)提取游标列值、移动记录指针语句

Fetch [Next | Prior | First | Last | {Absolute <行号>} | {Relative <行号>}]
From <游标名> [Into <变量列表……>]

  • 每次执行Fetch语句时,DBMS移到游标中的下一行并把游标中的列值获取到Into中列出的变量中。因此Fetch语句的Into子句中列出的变量必须与游标定义中Select 语句中的列表的类型与个数相对应;
  • 仅当定义游标时使用Scroll参数时,才能使用Fetch语句的行定位参数(First Last Prior Next Relative Absolute);如果Fetch语句中不包括参数Next | Prior | First | Last,DBMS将执行默认的Fetch Next;
  • Next 向下、向后移动一行(记录);
  • Prior 向上、向前移动一行(记录);
  • First 移动至结果集的第一行(记录);
  • Last 移动至结果集的最后一行(记录);
  • Absolute n 移动到结果集中的第n行。如果n是正值,DBMS从结果集的首部向后或向下移动至第n行;如果n是负数,则DBMS从结果集的底部向前或向上移动n行;
    Fetch Absolute 2 From cur_Depart Into @DeptID,@DeptName
  • Relative n 从指针的当前位置移动n行。如果n是正值,DBMS将行指针向后或向下移动至第n行;如果n是负数,则DBMS将行指针向前或向上移动n行;
    Fetch Relative 2 From cur_Depart Into @DeptID,@DeptName

3)基于游标的定位DELETE/UPDATE语句

如果游标是可更新的(也就是说,在定义游标语句中不包括Read Only 参数),就可以用游标从游标数据的源表中DELETE/UPDATE行,即DELETE/UPDATE基于游标指针的当前位置的操作;
举例:

--删除当前行的记录
Declare cur_Depart Cursor
For Select cDeptID,cDeptName From Department into @DeptID,@DeptName
Open cur_Depart
Fetch From cur_Depart into @DeptID,@DeptName
Delete From Department Where CURRENT OF cur_Depart

--更新当前行的内容
Declare cur_Depart Cursor
For Select cDeptID,cDeptName From Department into @DeptID,@DeptName
Open cur_Depart
Fetch From cur_Depart into @DeptID,@DeptName
Update Department Set cDeptID=’2007’ + @DeptID Where CURRENT OF cur_Depart

3.游标使用技巧及注意

1)利用Order By改变游标中行的顺序。此处应该注意的是,只有在查询的中Select 子句中出现的列才能作为Order by子句列,这一点与普通的Select语句不同;
2)当语句中使用了Order By子句后,将不能用游标来执行定位DELETE/UPDATE语句;如何解决这个问题,首先在原表上创建索引,在创建游标时指定使用此索引来实现;例如:

Declare cur_Depart Cursor
For Select cDeptID,cDeptName From Department With INDEX(idx_ID)
For Update Of cDeptID,cDeptName
通过在From子句中增加With Index来实现利用索引对表的排序;
3)在游标中可以包含计算好的值作为列;
4)利用@@Cursor_Rows确定游标中的行数;

----------------------------------------------------------------------------------------------------------------------------------------------------------------------

CREATE procedure UF_Rpt_PoScheduleSp(
@Startingvend_num varchar(12)=NULL
,@Endingvend_num varchar(12)=NULL
,@schedule datetime=NULL
,@blankvend_num bit
,@no_need_rec bit
,@ShowHand bit=0
,@ShowRec bit=0

)
as
declare @Output table(
item varchar (40) NULL,
vend_num char (10) NULL,
qty_on_hand decimal(20, 8) NULL,
due_date_po decimal(18, 8) NULL,
qty_recv decimal(20, 8) NULL,
qty_not_need decimal(20, 8) NULL,
qty_po_os decimal(20, 8) NULL,
day_1 decimal (18, 8) NULL,
day_2 decimal (18, 8) NULL,
day_3 decimal (18, 8) NULL,
day_4 decimal (18, 8) NULL,
day_5 decimal (18, 8) NULL,
day_6 decimal (18, 8) NULL,
day_7 decimal (18, 8) NULL,
wk_2 decimal (18, 8) NULL,
wk_3 decimal (18, 8) NULL,
wk_4 decimal (18, 8) NULL,
wk_5 decimal (18, 8) NULL,
wk_6 decimal (18, 8) NULL,
wk_7 decimal (18, 8) NULL,
wk_8 decimal (18, 8) NULL,
wk_9 decimal (18, 8) NULL,
wk_10 decimal (18, 8) NULL,
wk_11 decimal (18, 8) NULL,
wk_12 decimal (18, 8) NULL,
m_1 decimal (18, 8) NULL,
m_2 decimal (18, 8) NULL,
m_3 decimal (18, 8) NULL,
ID decimal(18, 0) IDENTITY (1, 1) NOT NULL
)

if @blankvend_num=0 -----vend_num is not null
if @no_need_rec=1 --
begin
insert @Output
select item,vend_num,SUM(qty_on_hand) as qty_on_hand,SUM(due_date_po) as due_date_po,SUM(qty_recv) as qty_recv,SUM(qty_not_need) as qty_not_need,SUM(qty_po_os) as qty_po_os,SUM(day_1) as day_1,SUM(day_2) as day_2,SUM(day_3) as day_3,SUM(day_4) as day_4,SUM(day_5) as day_5,SUM(day_6) as day_6,SUM(day_7) as day_7,
SUM(week_2) as wk_2,SUM(week_3) as wk_3,SUM(week_4) as wk_4,SUM(week_5) as wk_5,SUM(week_6) as wk_6,SUM(week_7) as wk_7,SUM(week_8) as wk_8,SUM(week_9) as wk_9,SUM(week_10) as wk_10,SUM(week_11) as wk_11,SUM(week_12) as wk_12,
SUM(month_1) as m_1,SUM(month_2) as m_2,SUM(month_3) as m_3

from Uf_Po_Schedule
where convert(varchar(10),schedule_date,120)=convert(varchar(10),@schedule,120)
and vend_num>=ISNULL(@Startingvend_num,vend_num) and vend_num<=ISNULL(@Endingvend_num,vend_num)
--and ExceptMessage='Receipt Not Needed' ---Not Needed Receipt
group by item,vend_num
end
else --
begin
---vend_num is not null
insert @Output
select item,vend_num,SUM(qty_on_hand) as qty_on_hand,SUM(due_date_po) as due_date_po,SUM(qty_recv) as qty_recv,SUM(qty_not_need) as qty_not_need,SUM(qty_po_os) as qty_po_os,SUM(day_1) as day_1,SUM(day_2) as day_2,SUM(day_3) as day_3,SUM(day_4) as day_4,SUM(day_5) as day_5,SUM(day_6) as day_6,SUM(day_7) as day_7,
SUM(week_2) as wk_2,SUM(week_3) as wk_3,SUM(week_4) as wk_4,SUM(week_5) as wk_5,SUM(week_6) as wk_6,SUM(week_7) as wk_7,SUM(week_8) as wk_8,SUM(week_9) as wk_9,SUM(week_10) as wk_10,SUM(week_11) as wk_11,SUM(week_12) as wk_12,
SUM(month_1) as m_1,SUM(month_2) as m_2,SUM(month_3) as m_3

from Uf_Po_Schedule
where convert(varchar(10),schedule_date,120)=convert(varchar(10),@schedule,120)
and vend_num>=ISNULL(@Startingvend_num,vend_num) and vend_num<=ISNULL(@Endingvend_num,vend_num)
--and (ExceptMessage<>'Receipt Not Needed' OR ExceptMessage IS NULL) ---Not Needed Receipt
group by item,vend_num
end

else
---vend_num is null
if @no_need_rec=1--选中是不需要接受
begin
insert @Output
select item,vend_num,SUM(qty_on_hand) as qty_on_hand,SUM(due_date_po) as due_date_po,SUM(qty_recv) as qty_recv,SUM(qty_not_need) as qty_not_need,SUM(qty_po_os) as qty_po_os,SUM(day_1) as day_1,SUM(day_2) as day_2,SUM(day_3) as day_3,SUM(day_4) as day_4,SUM(day_5) as day_5,SUM(day_6) as day_6,SUM(day_7) as day_7,
SUM(week_2) as wk_2,SUM(week_3) as wk_3,SUM(week_4) as wk_4,SUM(week_5) as wk_5,SUM(week_6) as wk_6,SUM(week_7) as wk_7,SUM(week_8) as wk_8,SUM(week_9) as wk_9,SUM(week_10) as wk_10,SUM(week_11) as wk_11,SUM(week_12) as wk_12,
SUM(month_1) as m_1,SUM(month_2) as m_2,SUM(month_3) as m_3

from Uf_Po_Schedule
where convert(varchar(10),schedule_date,120)=convert(varchar(10),@schedule,120)
--and ((vend_num>=ISNULL(@Startingvend_num,vend_num) and vend_num<=ISNULL(@Endingvend_num,vend_num)) or
and vend_num is null
--and ExceptMessage='Receipt Not Needed' ---Not Needed Receipt
group by item,vend_num
end
else --不选中是不需要接受
begin
insert @Output
select item,vend_num,SUM(qty_on_hand) as qty_on_hand,SUM(due_date_po) as due_date_po,SUM(qty_recv) as qty_recv,SUM(qty_not_need) as qty_not_need,SUM(qty_po_os)as qty_po_os,SUM(day_1) as day_1,SUM(day_2) as day_2,SUM(day_3) as day_3,SUM(day_4) as day_4,SUM(day_5) as day_5,SUM(day_6) as day_6,SUM(day_7) as day_7,
SUM(week_2) as wk_2,SUM(week_3) as wk_3,SUM(week_4) as wk_4,SUM(week_5) as wk_5,SUM(week_6) as wk_6,SUM(week_7) as wk_7,SUM(week_8) as wk_8,SUM(week_9) as wk_9,SUM(week_10) as wk_10,SUM(week_11) as wk_11,SUM(week_12) as wk_12,
SUM(month_1) as m_1,SUM(month_2) as m_2,SUM(month_3) as m_3

from Uf_Po_Schedule
where convert(varchar(10),schedule_date,120)=convert(varchar(10),@schedule,120)
--and ((vend_num>=ISNULL(@Startingvend_num,vend_num) and vend_num<=ISNULL(@Endingvend_num,vend_num)) or
and vend_num is null
-- and (ExceptMessage<>'Receipt Not Needed' OR ExceptMessage IS NULL) ---Not Needed Receipt
group by item,vend_num
end

---------------------------------批量更新--------------------------------------

declare
@x decimal(18,8),
@tmp decimal(18,8)
declare
@item varchar (40) ,
@vend_num char (10) ,
@qty_on_hand decimal(20, 8),
@due_date_po decimal(18, 8) ,
@qty_recv decimal(20, 8) ,
@qty_not_need decimal(20, 8) ,
@qty_po_os decimal(20, 8) ,
@day_1 decimal (18, 8) ,
@day_2 decimal (18, 8) ,
@day_3 decimal (18, 8) ,
@day_4 decimal (18, 8) ,
@day_5 decimal (18, 8) ,
@day_6 decimal (18, 8) ,
@day_7 decimal (18, 8) ,
@wk_2 decimal (18, 8) ,
@wk_3 decimal (18, 8) ,
@wk_4 decimal (18, 8) ,
@wk_5 decimal (18, 8) ,
@wk_6 decimal (18, 8) ,
@wk_7 decimal (18, 8) ,
@wk_8 decimal (18, 8) ,
@wk_9 decimal (18, 8) ,
@wk_10 decimal (18, 8) ,
@wk_11 decimal (18, 8) ,
@wk_12 decimal (18, 8) ,
@m_1 decimal (18, 8) ,
@m_2 decimal (18, 8) ,
@m_3 decimal (18, 8) ,
@ID decimal (18, 0)

declare IntCursor CURSOR static local for
select * from @Output
Open IntCursor
while 1=1
begin
fetch IntCursor into
@item ,
@vend_num ,
@qty_on_hand ,
@due_date_po ,
@qty_recv ,
@qty_not_need ,
@qty_po_os ,
@day_1 ,
@day_2 ,
@day_3 ,
@day_4 ,
@day_5 ,
@day_6 ,
@day_7 ,
@wk_2 ,
@wk_3 ,
@wk_4 ,
@wk_5 ,
@wk_6 ,
@wk_7 ,
@wk_8 ,
@wk_9 ,
@wk_10 ,
@wk_11 ,
@wk_12 ,
@m_1 ,
@m_2 ,
@m_3 ,
@ID
set @x=0
if @@fetch_status<>0
break
if @day_1-cast(@day_1 as int)<>0
--判断是否有小数,有则处理 无不理
begin
set @tmp=@day_1-@x
select @day_1=i from UF_GetInt_decimal(@tmp)
select @x=d from UF_GetInt_decimal(@tmp)
end
if @day_2-cast(@day_2 as int)<>0
begin
if @day_2>=@x
begin
set @tmp=@day_2-@x
select @day_2=i from UF_GetInt_decimal(@tmp)
select @x=d from UF_GetInt_decimal(@tmp)

end
else
begin
set @x=@x-@day_2
set @day_2=0
end
end

if @day_3-cast(@day_3 as int)<>0
begin
if @day_3>=@x
begin
set @tmp=@day_3-@x
select @day_3=i from UF_GetInt_decimal(@tmp)
select @x=d from UF_GetInt_decimal(@tmp)

end
else
begin
set @x=@x-@day_3
set @day_3=0
end
end


if @day_4-cast(@day_4 as int)<>0
begin
if @day_4>=@x
begin
set @tmp=@day_4-@x
select @day_4=i from UF_GetInt_decimal(@tmp)
select @x=d from UF_GetInt_decimal(@tmp)

end
else
begin
set @x=@x-@day_4
set @day_4=0
end
end

if @day_5-cast(@day_5 as int)<>0
begin
if @day_5>=@x
begin
set @tmp=@day_5-@x
select @day_5=i from UF_GetInt_decimal(@tmp)
select @x=d from UF_GetInt_decimal(@tmp)

end
else
begin
set @x=@x-@day_5
set @day_5=0
end
end

if @day_6-cast(@day_6 as int)<>0
begin
if @day_6>=@x
begin
set @tmp=@day_6-@x
select @day_6=i from UF_GetInt_decimal(@tmp)
select @x=d from UF_GetInt_decimal(@tmp)

end
else
begin
set @x=@x-@day_6
set @day_6=0
end
end

if @day_7-cast(@day_7 as int)<>0
begin
if @day_7>=@x
begin
set @tmp=@day_7-@x
select @day_7=i from UF_GetInt_decimal(@tmp)
select @x=d from UF_GetInt_decimal(@tmp)

end
else
begin
set @x=@x-@day_7
set @day_7=0
end
end

if @wk_2-cast(@wk_2 as int)<>0
begin
if @wk_2>=@x
begin
set @tmp=@wk_2-@x
select @wk_2=i from UF_GetInt_decimal(@tmp)
select @x=d from UF_GetInt_decimal(@tmp)

end
else
begin
set @x=@x-@wk_2
set @wk_2=0
end
end

if @wk_3-cast(@wk_3 as int)<>0
begin
if @wk_3>=@x
begin
set @tmp=@wk_3-@x
select @wk_3=i from UF_GetInt_decimal(@tmp)
select @x=d from UF_GetInt_decimal(@tmp)

end
else
begin
set @x=@x-@wk_3
set @wk_3=0
end
end
if @wk_4-cast(@wk_4 as int)<>0
begin
if @wk_4>=@x
begin
set @tmp=@wk_4-@x
select @wk_4=i from UF_GetInt_decimal(@tmp)
select @x=d from UF_GetInt_decimal(@tmp)

end
else
begin
set @x=@x-@wk_4
set @wk_4=0
end
end

if @wk_5-cast(@wk_5 as int)<>0
begin
if @wk_5>=@x
begin
set @tmp=@wk_5-@x
select @wk_5=i from UF_GetInt_decimal(@tmp)
select @x=d from UF_GetInt_decimal(@tmp)

end
else
begin
set @x=@x-@wk_5
set @wk_5=0
end
end

if @wk_6-cast(@wk_6 as int)<>0
begin
if @wk_6>=@x
begin
set @tmp=@wk_6-@x
select @wk_6=i from UF_GetInt_decimal(@tmp)
select @x=d from UF_GetInt_decimal(@tmp)

end
else
begin
set @x=@x-@wk_6
set @wk_6=0
end
end

if @wk_7-cast(@wk_7 as int)<>0
begin
if @wk_7>=@x
begin
set @tmp=@wk_7-@x
select @wk_7=i from UF_GetInt_decimal(@tmp)
select @x=d from UF_GetInt_decimal(@tmp)

end
else
begin
set @x=@x-@wk_7
set @wk_7=0
end
end

if @wk_8-cast(@wk_8 as int)<>0
begin
if @wk_8>=@x
begin
set @tmp=@wk_8-@x
select @wk_8=i from UF_GetInt_decimal(@tmp)
select @x=d from UF_GetInt_decimal(@tmp)

end
else
begin
set @x=@x-@wk_8
set @wk_8=0
end
end

if @wk_9-cast(@wk_9 as int)<>0
begin
if @wk_9>=@x
begin
set @tmp=@wk_9-@x
select @wk_9=i from UF_GetInt_decimal(@tmp)
select @x=d from UF_GetInt_decimal(@tmp)

end
else
begin
set @x=@x-@wk_9
set @wk_9=0
end
end

if @wk_10-cast(@wk_10 as int)<>0
begin
if @wk_10>=@x
begin
set @tmp=@wk_10-@x
select @wk_10=i from UF_GetInt_decimal(@tmp)
select @x=d from UF_GetInt_decimal(@tmp)

end
else
begin
set @x=@x-@wk_10
set @wk_10=0
end
end

if @wk_11-cast(@wk_11 as int)<>0
begin
if @wk_11>=@x
begin
set @tmp=@wk_11-@x
select @wk_11=i from UF_GetInt_decimal(@tmp)
select @x=d from UF_GetInt_decimal(@tmp)

end
else
begin
set @x=@x-@wk_11
set @wk_11=0
end
end

if @wk_12-cast(@wk_12 as int)<>0
begin
if @wk_12>=@x
begin
set @tmp=@wk_12-@x
select @wk_12=i from UF_GetInt_decimal(@tmp)
select @x=d from UF_GetInt_decimal(@tmp)

end
else
begin
set @x=@x-@wk_12
set @wk_12=0
end
end

if @m_1-cast(@m_1 as int)<>0
begin
if @m_1>=@x
begin
set @tmp=@m_1-@x
select @m_1=i from UF_GetInt_decimal(@tmp)
select @x=d from UF_GetInt_decimal(@tmp)

end
else
begin
set @x=@x-@m_1
set @m_1=0
end
end

if @m_2-cast(@m_2 as int)<>0
begin
if @m_2>=@x
begin
set @tmp=@m_2-@x
select @m_2=i from UF_GetInt_decimal(@tmp)
select @x=d from UF_GetInt_decimal(@tmp)

end
else
begin
set @x=@x-@m_2
set @m_2=0
end
end

if @m_3-cast(@m_3 as int)<>0
begin
if @m_3>=@x
begin
set @tmp=@m_3-@x
select @m_3=i from UF_GetInt_decimal(@tmp)
select @x=d from UF_GetInt_decimal(@tmp)

end
else
begin
set @x=@x-@m_3
set @m_3=0
end
end
------------------------------------update--------------------------------------------
update @Output
set day_1=@day_1,day_2=@day_2,day_3=@day_3,day_4=@day_4,day_5=@day_5,day_6=@day_6,day_7=@day_7,wk_2=@wk_2,wk_3=@wk_3,wk_4=@wk_4,wk_5=@wk_5,wk_6=@wk_6,wk_7=@wk_7,wk_8=@wk_8,wk_9=@wk_9,wk_10=@wk_10,wk_11=@wk_11,wk_12=@wk_12,m_1=@m_1,m_2=@m_2,m_3=@m_3
where ID=@ID
--------------------------------------------------------------------------------------

end
close IntCursor
DEALLOCATE IntCursor


select a.item ,
a.vend_num ,
a.qty_on_hand ,
a.due_date_po ,
a.qty_recv ,
a.qty_not_need ,
a.qty_po_os ,
a.day_1 ,
a.day_2 ,
a.day_3 ,
a.day_4 ,
a.day_5 ,
a.day_6 ,
a.day_7 ,
a.wk_2 ,
a.wk_3 ,
a.wk_4 ,
a.wk_5 ,
a.wk_6 ,
a.wk_7 ,
a.wk_8 ,
a.wk_9 ,
a.wk_10 ,
a.wk_11 ,
a.wk_12 ,
a.m_1 ,
a.m_2 ,
a.m_3 ,
c.Qty_Rec,
b.qtynohand
from @Output a

left join (select item,sum(L.Uf_GrnWaitCheck-L.qty_rec-L.qty_rej-L.qty_returned-L.Uf_GrnReturn) as Qty_Rec from grn_line L
left join poitem I on L.po_num=I.po_num and L.po_line=I.po_line and L.po_release=I.po_release
where L.Uf_GrnWaitCheck-L.qty_rec-L.qty_rej-L.qty_returned-L.Uf_GrnReturn>0 group by item) C ON A.item=C.item
left join (select item,sum(qty_on_hand) as qtynohand from itemloc where mrb_flag<>1 group by item) b
on a.item=b.item
GO

你可能感兴趣的:(sql)