【问题标题】:Update multiple rows in SQL Server with IN clause使用 IN 子句更新 SQL Server 中的多行
【发布时间】:2013-07-12 07:29:33
【问题描述】:

我有一个这样的存储过程:

CREATE PROCEDURE Resume 
    @UserID nvarchar(100)
AS
BEGIN
    SET NOCOUNT ON;

    update Candidate set Approved = 'y' where UserId_I in (@UserID)
END
GO

在此@UserID 是字符串格式。我将参数@UserID 的值从代码作为字符串发送到1,2,3

我得到了错误

将 nvarchar 值 '1,2,3' 转换为数据类型 int 时转换失败。

请解决这个问题

【问题讨论】:

  • in 的多个单独参数在逻辑上与 恰好 包含逗号的 单个 字符串参数不同。 SQL 与几乎所有其他编程语言一样,不会神奇地决定检查字符串并更改它。对此的正确解决方案是首先不要传递 字符串——传递(理想情况下)表值参数或XML 文档——旨在包含多个值的东西。毫无疑问,您会得到指向在服务器上创建拆分函数的答案(或接近投票),但这确实是错误的方法。

标签: c# sql sql-server


【解决方案1】:

您可以通过多种方式做到这一点。您可以定义表类型并通过该表类型传递用户 ID 列表(请参阅此问题:INSERT using LIST into Stored Procedure)。

您还可以在WHILE 循环中以逗号分隔字符串并将ID 添加到临时表中。然后你可以使用... IN (SELECT UID FROM @tempTable)。粗略算法:

DECLARE @tempTable TABLE (UID INT)

WHILE ([Length of @UserID > 0])
BEGIN
    IF ([@UserID contains comma?])
    BEGIN
        [GET STRING UNTIL COMMA]
        [CONVERT TO INT AND INSERT INTO @tempTable]
        [REMOVE STRING AND COMMA FROM @UserID]
    END ELSE
    BEGIN
        [CONVERT @UserID TO INT AND INSERT INTO @tempTable]
        SET @UserID = ''
    END
END

您也可以使用EXEC 方法,但我倾向于不使用带有从外部传递的参数的EXEC - 您将代码打开到SQL 注入。我要做的最少检查是@UserID 参数是否只包含数字、逗号和空格。

【讨论】:

    【解决方案2】:

    尝试使用性能比子查询更好的临时表

    DECLARE @userIds NVARCHAR(MAX)
    SET @userIds ='1,2,3,4,5,6'
    
    CREATE table #TempUser 
    (
        userId Int
    ) 
    DECLARE @SplitOn VARCHAR(1)
    SET @SplitOn = ','
    
    While (Charindex(@SplitOn,@userIds)>0)
    Begin
        Insert Into #TempUser (userId)
        Select 
            userId = ltrim(rtrim(Substring(@userIds ,1,Charindex(@SplitOn,@userIds )-1)))
        Set @userIds = Substring(@userIds,Charindex(@SplitOn,@userIds)+1,len(@userIds))
    End
    
    Insert Into #TempUser (userId)
    Select Data = ltrim(rtrim(@userIds))
    
    SELECT * FROM #TempUser
    

    现在您可以使用此临时表更新您的记录。

    【讨论】:

      【解决方案3】:

      请使用EXECUTE (Transact-SQL) 命令更新。

      CREATE PROCEDURE Resume 
          -- Add the parameters for the stored procedure here
          @UserID nvarchar(100)
      AS
      BEGIN
          -- SET NOCOUNT ON added to prevent extra result sets from
          -- interfering with SELECT statements.
          SET NOCOUNT ON;
      
          -- Insert statements for procedure here
          exec ('update Candidate set Approved=''y'' where UserId_I in ('+@UserID+')')
      END
      GO
      

      【讨论】:

      • 这当然也是一种选择,但请注意这里的 SQL 注入可能性。 ;-)
      【解决方案4】:

      对于拆分@UserID 参数,您可以使用XQuery value() method

      CREATE PROCEDURE Resume 
        @UserID nvarchar(100)
      AS
      BEGIN
        SET NOCOUNT ON;
      
        UPDATE Candidate 
        SET Approved = 'y' 
        WHERE UserId_I IN 
          (SELECT Split.a.value('.', 'int')
           FROM (SELECT CAST ('<M>' + REPLACE(@UserID , ',', '</M><M>') + '</M>' AS XML) AS val    
                 ) AS A CROSS APPLY val.nodes('/M') AS Split(a)
           )
      END
      GO
      

      SQLFiddle上查看演示

      【讨论】:

        【解决方案5】:

        发生错误是因为您不能使用字符串 (@UserID) 作为 IN 运算符的右手运算符。 IN 运算符需要一个 SET 作为右手运算符 - 在这种情况下,您需要一组整数来判断 UserId_I 是否是该集合的一部分。

        您可以在这里做两件事:要么为@UserID 参数使用表值参数,要么编写一个将@UserID 字符串转换/拆分为表/整数集的函数,在这种情况下你会得到类似的东西:

        ...WHERE @UserId_I IN dbo.ParseIntSet(@UserId);
        

        【讨论】:

          【解决方案6】:

          您可以尝试下面给出的演示...

          CREATE PROCEDURE [dbo].[Proc_Name] @CSVConnectivityIds NVARCHAR(MAX)
          WHILE len(@CSVConnectivityIds) > 0
              BEGIN
                  INSERT INTO tblName
                  VALUES (left(@CSVConnectivityIds, charindex(',', @CSVConnectivityIds + ',') - 1))
                  SET @CSVConnectivityIds = stuff(@CSVConnectivityIds, 1, charindex(',', @CSVConnectivityIds + ','), '')
              END
          

          希望对你有帮助

          【讨论】:

            猜你喜欢
            • 2016-05-13
            • 1970-01-01
            • 1970-01-01
            • 2013-11-11
            • 2014-02-06
            • 2013-06-25
            • 1970-01-01
            • 1970-01-01
            • 2014-04-16
            相关资源
            最近更新 更多