在单个存储过程中多次插入?

时间:2014-04-14 17:18:33

标签: c# sql .net sql-server stored-procedures

TableName:Information

将数据插入上表的存储过程。

CREATE PROCEDURE sp_insert_information
(
    @profileID as int,
    @profileName as varchar(8)
    @profileDescription as varchar(100)
)
AS
BEGIN
   INSERT INTO information(profileid, profilename, profiledescription)
   VALUES (@profileID, @profileName, @profileDescription);
END

我从.NET调用此过程,如果我将profileID作为逗号分隔参数传递,有没有办法进行多次插入? (我可以使用拆分功能吗?)

我可以遍历profileID并逐个发送1到过程,但是除了profileID之外,我的数据将是相同的。

表数据(有3列):

1 profileUnavailable  User Error
2 profileUnavailable  User Error
3 profileUnavailable  User Error
4 profileUnavailable  User Error
5 profileUnavailable  User Error

我可以尝试一次性完成任何其他方法吗?

4 个答案:

答案 0 :(得分:1)

您有几个选择:

SqlBulkInsert - 您可以创建可以转储到表中的数据集。这对许多插件很有用。这将完全绕过该程序。

Table Valued Parameters - 您可以使用表值参数作为存储过程的参数,再次使用数据集操作数据。

带有字符串拆分的CSV参数是一个选项,但我建议使用其中一个。

答案 1 :(得分:0)

不。该sproc一次插入一次,因为它是目前写的。你必须单独调用它。

您也可以考虑将其包装到一个事务中,这样如果一个失败,所有这些都不会被提交。

答案 2 :(得分:0)

几年前我最喜欢的技术是拥有一个分裂函数库,可以将一个定界值的分隔列表(例如所有整数,所有布尔值,所有日期时间等)拆分成表变量。这是一个这样的功能的例子。

CREATE FUNCTION [dbo].[fn_SplitInt](@text varchar(8000), 
                                    @delimiter varchar(20) = '|')
RETURNS @Values TABLE
(    
  pos int IDENTITY PRIMARY KEY,
  val INT
)

AS
BEGIN

  DECLARE @index int 
  SET @index = -1 

  -- while the list is not over...
  WHILE (LEN(@text) > 0) 
    BEGIN  
      -- search the next delimiter
      SET @index = CHARINDEX(@delimiter , @text)  

      IF (@index = 0) -- if no more delimiters (hence this field is the last one)
        BEGIN
          IF (LEN(@text) > 0) -- and if this last field is not empty
            INSERT INTO @Values VALUES (CAST (@text AS INT))  -- then insert it
          ELSE                -- otherwise, if this last field is empty
            INSERT INTO @Values VALUES (NULL)                 -- then insert NULL
          BREAK  -- in both cases exit, since it was the last field
        END  
      ELSE             -- otherwise, if there is another delimiter
        BEGIN   
          IF @index>1   -- and this field is not empty
            INSERT INTO @Values VALUES (CAST(LEFT(@text, @index - 1) AS INT)) -- then insert it
          ELSE          -- otherwise, if this last field is empty
            INSERT INTO @Values VALUES (NULL)                                 -- then insert NULL
          SET @text = RIGHT(@text, (LEN(@text) - @index))  -- in both cases move forward the read pointer,
                                                           -- since the list was not over
        END  
    END
  RETURN
END

如果你有一组这样的函数,那么你的问题就像这个一样简单:

CREATE PROCEDURE sp_insert_information
(
 @profileID as varchar(2000),
 @profileName as varchar(8)
 @profileDescription as varchar(100)
)
AS
BEGIN

  DECLARE @T TABLE (Id int)
  INSERT INTO @T (Id) 
    SELECT val FROM dbo.fn_SplitInt(@profileID)
  INSERT INTO information(profileid, profilename,profiledescription)
    SELECT Id, @profileName, @profileDescription
      FROM @T

END

但是今天可能更快执行,甚至需要更少的编码,生成要插入的数据的XML表示,然后将XML传递给存储过程并让它INSERT INTO表SELECT FROM xml,如果你知道的话我的意思。

答案 3 :(得分:0)

   WHILE len(@ProfileId) > 0
    BEGIN
      DECLARE @comm int= charindex(',',@ProfileId)

      IF @comm = 0 set @comm = len(@ProfileId)+1

          DECLARE @Profile varchar(1000) = substring(@ProfileId, 1, @comm-1)

          INSERT INTO Information(ProfileId,ProfileName,ProfileDescription) 
          VALUES (@ProfileId,@ProfileName,@ProfileDescription)

     SET @ProfileId= substring(@ProfileId, @comm+1, len(@ProfileId)) 

    END