這里關於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或"",反而是第一次循環的值(即上一次循環的值)
