簡體   English   中英

如何將數組傳遞給存儲過程以便連續插入一些記錄

[英]How to pass array to stored procedure in order to insert some records consecutively

眾所周知,SQL Server中沒有數組,因此有一些變通方法可以實現此目的,例如表值參數(TVP)和用戶定義的數據類型(UDT)或什至是逗號分隔值(CSV)的參數。

互聯網上也有一些示例顯示如何使用它,但是大多數示例都應用SELECT語句並直接使用參數,如下所示:

CREATE PROCEDURE dbo.GetOrderList1
    (@OrderList VARCHAR(500))
AS
BEGIN
    SET NOCOUNT ON

    DECLARE @SQL VARCHAR(600)

    SET @SQL =  'SELECT OrderID, CustomerID, EmployeeID, OrderDate
                 FROM dbo.Orders
                 WHERE OrderID IN (' + @OrderList + ')'

    EXEC(@SQL)  
END

但是我需要使用INSERT語句,並逐個使用參數的每個部分。

就我而言,我通過SignalR發送消息給多個參與者,我也需要將其保存在數據庫中。 想象我有一個MessageId ,我想這樣保存它:

ID   |    MessageId   | ReceiverId
-----+----------------+-----------
     |                |

我需要存儲過程來只獲得一個說100的MessageId和一個說(1001、1002、1003、1004、1005)的多個ReceiverId ,並將它們一個一個地插入相關表中,如下所示:

EXEC sp_AddToMessageReceivers 100, (1001, 1002, 1003, 1004, 1005)

CREATE PROCEDURE sp_AddToMessageReceivers
    @messageId INT, 
    @ReceiversIds VARCHAR(500)
AS
BEGIN
    DECLARE @i INT = 0

    WHILE @i < @ReceiversIds.length
    BEGIN
        INSERT INTO [dbo].[MessageReceiver] (MessageId, ReceiverIds)
        VALUES (@MessageId, @ReceiversIds[i])

        SET @i = @i + 1
    END
END

我知道如何在存儲過程中獲取表值參數,但我不知道如何在while循環中一個接一個地使用它們。

如果您提供解決此問題的方法,我真的很合適。

您可以從應用程序端創建一個1-Many關系的DataTable ,並將其作為Table Value Parameter傳遞給Stored Procedure ,然后可以將其插入表中。

例如,首先使用MessageIdReceiverId創建一個TVP

CREATE TYPE MessageTableType AS TABLE   
(
MessageId int,
ReceiverId int
)

然后像這樣創建您的存儲過程,

CREATE PROCEDURE uspAddToMessageReceivers
    @MsgTvp MessageTableType readonly
AS
BEGIN
        INSERT INTO [dbo].[MessageReceiver] 
        SELECT MessageId, ReceiverId from @MsgTvp
END

然后從您的應用程序端(假定為C#應用程序)創建一個DataTable,並將其傳遞給存儲過程。

DataTable dataTable = new DataTable();
dataTable.Columns.Add("MessageId", typeof(int));
dataTable.Columns.Add("ReceiverId", typeof(int));
//dataTable.Rows.Add.. Add rows here

您需要創建一個表值函數,以從csv值返回表形式。

CREATE FUNCTION [dbo].[fn_csvToColumns]
    (@CommadelimitedString NVARCHAR(MAX),
     @delimiter CHAR(1)
)
RETURNS @Result TABLE (Value VARCHAR(100))
AS
BEGIN
    -- Fill the table variable with the rows for your result set
    DECLARE @IntLocation INT

    WHILE (CHARINDEX(',',    @CommadelimitedString, 0) > 0)
    BEGIN
        SET @IntLocation =   CHARINDEX(@delimiter, @CommadelimitedString, 0)      

        INSERT INTO @Result (Value)
            --LTRIM and RTRIM to ensure blank spaces are   removed
            SELECT RTRIM(LTRIM(SUBSTRING(@CommadelimitedString, 0, @IntLocation)))   

        SET @CommadelimitedString = STUFF(@CommadelimitedString, 1, @IntLocation, '') 
    END

    INSERT INTO @Result (Value)
        SELECT RTRIM(LTRIM(@CommadelimitedString))--LTRIM and RTRIM to ensure blank     spaces are removed

    DELETE FROM @Result 
    WHERE Value = ''

    RETURN 
END

更改您的存儲過程以使用上述功能:

ALTER PROCEDURE sp_AddToMessageReceivers
    @messageId INT, 
    @ReceiversIds VARCHAR(500)
AS
BEGIN
    DECLARE @temp TABLE (tempid INT)

    INSERT INTO @temp(tempid)
        SELECT value 
        FROM dbo.fn_csvToColumns(@ReceiversIds, ',')

    WHILE EXISTS (SELECT TOP 1 null FROM @temp)
    BEGIN
        SELECT TOP 1 @ReceiverIds = tempid 
        FROM @temp

        INSERT INTO [dbo].[MessageReceiver] (MessageId, ReceiverIds)
        VALUES (@MessageId, @ReceiverIds)

        DELETE FROM @temp 
        WHERE tempid = @ReceiverIds
    END
END

我將使用split函數(可以在此處找到很好的示例)。

例:

INSERT INTO yourTable (messageId, ReceiversId)
SELECT @messageId, fn_ssm.Item
FROM dbo.SplitStrings_Moden fn_ssm (@ReceiversIds, N',')

我強烈反對使用WHILE循環或類似方法的任何方法,尤其是像上面的示例那樣的嵌套循環,因為這可能會嚴重影響代碼性能!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM