简体   繁体   English

如何将数组传递给存储过程以便连续插入一些记录

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

As everybody knows there is no array in SQL Server, there are some workarounds to achieve that somehow, like table-valued parameters (TVP) and user-defined data type (UDT) or even a parameter as comma-separated values (CSV). 众所周知,SQL Server中没有数组,因此有一些变通方法可以实现此目的,例如表值参数(TVP)和用户定义的数据类型(UDT)或什至是逗号分隔值(CSV)的参数。

There are also some examples on the internet that show how to use it, but most of them apply SELECT statement and use the parameter directly just like this: 互联网上也有一些示例显示如何使用它,但是大多数示例都应用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

But I need to use an INSERT statement and use every single part of parameter one by one. 但是我需要使用INSERT语句,并逐个使用参数的每个部分。

In my case I send a message to multiple participants by SignalR and I need to save it in data base too. 就我而言,我通过SignalR发送消息给多个参与者,我也需要将其保存在数据库中。 Imagine I have a MessageId and I want to save it this way: 想象我有一个MessageId ,我想这样保存它:

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

I need my stored procedure to get just one MessageId say 100 and multiple ReceiverId s say (1001, 1002, 1003, 1004, 1005) and insert them in related table one by one, something like this: 我需要存储过程来只获得一个说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

I know how to get the table valued parameter in stored procedure but I don't know how to work with them one by one in a while loop. 我知道如何在存储过程中获取表值参数,但我不知道如何在while循环中一个接一个地使用它们。

I really appropriate it if you offer a solution for this problem. 如果您提供解决此问题的方法,我真的很合适。

You can create a 1-Many relationship DataTable from your application side and pass it as Table Value Parameter to your Stored Procedure and then you can insert into the table. 您可以从应用程序端创建一个1-Many关系的DataTable ,并将其作为Table Value Parameter传递给Stored Procedure ,然后可以将其插入表中。

For example, first create a TVP with MessageId and ReceiverId 例如,首先使用MessageIdReceiverId创建一个TVP

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

Then create your Stored Procedure like this, 然后像这样创建您的存储过程,

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

Then create a DataTable from your application side (assuming C# application) and pass it to the Stored Procedure. 然后从您的应用程序端(假定为C#应用程序)创建一个DataTable,并将其传递给存储过程。

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

You need to either create a table value function that returns a table form from csv values. 您需要创建一个表值函数,以从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 your stored procedure to use above function: 更改您的存储过程以使用上述功能:

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

I would use a split function (good examples can be found here ). 我将使用split函数(可以在此处找到很好的示例)。

Example: 例:

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

I strongly vote against any method using WHILE loops or the like, especially nestes loops like the example above since this might affect the code performance significantly! 我强烈反对使用WHILE循环或类似方法的任何方法,尤其是像上面的示例那样的嵌套循环,因为这可能会严重影响代码性能!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM