创建用于通过 case 语句更新列的存储过程

Creating stored procedure for updating columns by case statement

我知道有很多关于此的问题,但我找不到我的答案。

我有一个 table 看起来像这样:

+----+--------+--------+----------+
| ID | FormID | ItemID | StrataID |  
+----+--------+--------+----------+
| a  | b      |   1111 | NULL     |  
| a  | b      |   2222 | NULL     |  
| a  | b      |   3333 | NULL     |  
| a  | g      |   4563 | NULL     |  
| b  | f      |   6666 | NULL     |  
+----+--------+--------+----------+

我想根据 ID+FormID+ItemID 更新 StrataID 的值。我想插入的值没有存储在数据库中的任何 table 中,它们只是我拥有的一个单独的列表。 如果我使用常规案例语句来更新 table 它看起来像这样:

 UPDATE [Table1]
    SET [StrataID] = 
        CASE ([ItemID])
            when 111  then 1
            when 222 then 2
            when 333 then 5
        else [StrataID]
        END 
WHERE [ID] = 'a'and [FormID] = 'b'

所以最后的结果是:

+----+--------+--------+----------+--+
| ID | FormID | ItemID | StrataID |  |
+----+--------+--------+----------+--+
| a  | b      |   1111 | 1        |  |
| a  | b      |   2222 | 2        |  |
| a  | b      |   3333 | 5        |  |
| a  | g      |   4563 | NULL     |  |
| b  | f      |   6666 | NULL     |  |
+----+--------+--------+-------

但我想避免为每个 FormID 重复 case 语句,因为我有超过 2000 条记录要以这种方式更新。

我尝试了以下动态 sql,其中 @ColumnName 是特定 ID+FormID 的所有可用 FormID,@NewValue 是我想插入到 'StrataID' 的值的字符串字段而不是 NULLS:

DECLARE @DynamicPivotQuery AS NVARCHAR(MAX)
DECLARE @ColumnName AS NVARCHAR(MAX)
DECLARE @NewValue AS NVARCHAR(MAX)


SELECT @ColumnName = STUFF((SELECT distinct  ',' +  QUOTENAME(ItemID)
                      FROM [Table1] 
                      where [ID] = 'a'and [FormID] = 'b'
                      FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)') , 1, 1, '');

SET @NewValue = ',1,2,5,';


SET @DynamicPivotQuery = 

    'UPDATE [Table1] SET [StrataID] = '+@NewValue+'
     WHERE[ID] = ''a'' and [FormID] = ''b'' AND ItemID ='+@ColumnName+';' 

--Execute the Dynamic Query
EXEC sp_executesql @DynamicPivotQuery

当我尝试执行它时出现错误 -

Msg 137, Level 15, State 2, Line 18
Must declare the scalar variable "@NewValue".

我知道它可能将 @NewValue 视为字符串而不是整数,但我不确定如何以不同方式存储我需要设置为新值的值以及如何创建动态 sql 语句来自重复的 case 语句。

关于如何将我的 sql 转换为动态更新 sql 的任何建议? 提前致谢!!

通过查看您的查询,我注意到的第一件事是更新列值和 ItemID 缺少单引号应该是 IN 而不是 =,因为您有多个列名。 它应该是“SET [StrataID] = ''+@NewValue+'' WHERE[ID] = ''a'' and [FormID] = ''b'' [SectionID] = 1 AND ItemID IN '+ @ColumnName+';'

打印@DynamicPivotQuery 并执行以查看实际错误是什么。发送实际更新语句和错误以及查找问题。

在连接部分以形成动态查询时,您需要确保所有内容都是 nvarchar 类型,否则会出错。因此,您应该使用以下代码,而不是您现在拥有的代码。

请注意,在下面的代码中所有参数值都被转换为 nvarchar 数据类型。

SET @DynamicPivotQuery = 

        'UPDATE [Table1] SET [StrataID] = '+ cast(@NewValue as nvarchar(100)) +'
         WHERE[ID] = ''a'' and [FormID] = ''b'' 
           AND ItemID ='+ cast( @ColumnName as nvarchar(500)) +';'

但是,您不需要动态查询来处理您的场景。而是遵循以下方法。

  1. 在这种方法中,您可以在 table 中收集所有 ItemId 值 变量 @ItemValues 和相应的 StrataId 值 table 变量 @StrataIDValues.
  2. 确保两个 table 中值的顺序相同,这样 @ItemValues table 中的第一条记录对应于 @StrataIdValues table.

    没有动态查询的更新

    DECLARE @ItemValues TABLE (
     SequenceNumber int IDENTITY (1, 1),
     ItemID int
    )
    INSERT INTO @ItemValues (ItemID)
    SELECT
     ItemId
    FROM Table1
    WHERE [ID] = 'a'
    AND [FormID] = 'b';
    
    --populate the corresponding values for StrataID in same sequence as
    --ItemId values in above table
    DECLARE @StrataIDValues TABLE (
      SequenceNumber int IDENTITY (1, 1),
      StrataID int
    )
    INSERT INTO @StrataIDValues (StrataID)
    VALUES (1), (2), (5);
    
    UPDATE [Table1]
     SET [StrataID] = v.StrataID
     FROM Table1 t
      INNER JOIN (SELECT
                   ItemID,
                   StrataID
                FROM @ItemValues
        INNER JOIN @StrataIDValues
     ON [@ItemValues].SequenceNumber = [@StrataIDValues].SequenceNumber) v
     ON t.ItemID = v.ItemID;