[英]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
,然后可以將其插入表中。
例如,首先使用MessageId
和ReceiverId
創建一個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.