前:转自[https://www.cnblogs.com/SysoCjs/p/9842178.html]
文章很详细,就转过来收藏啦,以下是正文
这里关于SqlServer有两个知识点:一个是使用游标遍历表,另一个是使用if not exists的sql语句进行插入。
一、使用游标遍历表
这个表可以是数据库的表,也可以是外面DataTable类型的参数传进去,使用游标可以概括为以下步骤:声明游标、打开游标、读取数据、操作数据、读取数据、关闭游标、释放游标。
二、在insert语句使用if not exits
使用了if not exists的语句的insert操作,意思是,在找不到相关数据时才进行insert操作。不同数据库,有不同的使用语法。
下面是创建存储过程:
USE [CapacityManagement]
GO
/****** Object: StoredProcedure [dbo].[USP_uploadResGpMaster] Script Date: 2018/10/24 10:09:03 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
--创建一张表,用来接收C#程序传过来的DataTable对象
--注意,这张表的字段必须跟传过来的DataTable对象的属性一致,名字可以不同
create type GS_Master as table
(
ResGp varchar(10),
Plant varchar(12),
Dept varchar(12),
Descrip nvarchar(50),
Step_mapping varchar(10),
CreateDate datetime,
CreateBy char(8),
ChangeDate datetime,
ChangeBy char(8)
)
go
CREATE PROCEDURE [dbo].[USP_uploadMaster] @Master GS_Master readonly,@OperationType nvarchar(3)
AS
BEGIN
SET NOCOUNT ON;
begin try
begin transaction
if(@OperationType ='A')
--声明一些local变量,用于接收查询表得到的数据,以便操作
declare @ResGp varchar(10),
@Plant varchar(12),
@Dept varchar(12),
@Descrip nvarchar(50),
@Step_mapping varchar(10),
@CreateDate datetime,
@CreateBy char(8),
@ChangeDate datetime,
@ChangeBy char(8),
@master_id int
begin
--一、声明游标
declare master_cursor cursor for select * from @Master
--二、打开游标
open master_cursor
--三、取第一条数据
fetch next from master_cursor
into @ResGp,
@Plant,
@Dept,
@Descrip,
@Step_mapping,
@CreateDate,
@CreateBy,
@ChangeDate,
@ChangeBy
while @@FETCH_STATUS = 0
begin
--四、操作数据,先操作[ResGp_Master],后操作[Step_ResGp_Maping]
--1、操作[ResGp_Master]
SELECT @master_id=id FROM [CapacityManagement].[dbo].[ResGp_Master]
where resgp = @ResGp
and plant = @Plant
and dept = @Dept
update [CapacityManagement].[dbo].[ResGp_Master]
set ChaDate = @ChangeDate,
ChaBy = @ChangeBy,
ResGpDesc = @Descrip
where id = @master_id
IF NOT EXISTS (SELECT id FROM [CapacityManagement].[dbo].[ResGp_Master] WHERE id = @master_id)
INSERT INTO [CapacityManagement].[dbo].[ResGp_Master] (ResGp, Dept, CreDate, CreBy, ChaDate, ChaBy, ResGpDesc, plant)
values(@ResGp, @Dept, @CreateDate, @CreateBy, @ChangeDate, @ChangeBy, @Descrip, @Plant)
--2、操作[Step_ResGp_Maping]
update [CapacityManagement].[dbo].[Step_ResGp_Maping]
set ChaDate = @ChangeDate,
ChaBy = @ChangeBy
where Master_id = @master_id
and step = @Step_mapping
if not exists(select master_id from [CapacityManagement].[dbo].[Step_ResGp_Maping] where Master_id = @master_id and step = @Step_mapping)
insert into [CapacityManagement].[dbo].[Step_ResGp_Maping](step, resgp, CreDate, CreBy, ChaDate, ChaBy, Master_id)
values(@Step_mapping, @ResGp, @CreateDate, @CreateBy, @ChangeDate, @ChangeBy, @master_id)
--五、取下一条数据
fetch next from master_cursor
into @ResGp,
@Plant,
@Dept,
@Descrip,
@Step_mapping,
@CreateDate,
@CreateBy,
@ChangeDate,
@ChangeBy
end
--六、关闭游标
close master_cursor
--七、释放游标
deallocate master_cursor
end
commit transaction
end try
begin catch
select ERROR_MESSAGE() as errorMessage
rollback transaction
end catch
END
GO
注释也是够详细了,操作数据那个过程,业务需求是对一堆数据进行插入,如果该数据已经存在,就进行更新,如果属于新数据,那么就进行插入(所以博主想到的是先遍历全部根据主键进行update,再根据主键查找是否存在该数据,若没有,则插入新数据),其实读者可以不细看,因为操作过程是根据业务需求,这里主要讲解游标的使用。
值得留意的一点:存储过程创建一个table类型的变量是用来存储程序传过来的DataTable对象,不仅字段个数要与DataTable的列数一致,类型也要特别注意,假设如果将DataTable的非数字列传给table类型里面的int类型字段,则该存储过程无法执行,会抛出异常。
注意:使用游标时,代码里使用一些局部变量存放查找的值(如@Master_id),如果第一次循环,@Master_id可以通过select查找到值,到了第二次select时却没有查找到值,那么@Master_id这个局部变量在第二次的循环里面的值不是null,也不是0或"",反而是第一次循环的值(即上一次循环的值)