Sql Server在存儲過程里面使用游標遍歷一個表


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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM