繁体   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