[英]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
例如,首先使用
MessageId
和ReceiverId
创建一个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.