创建用于按case语句

时间:2018-01-11 00:24:06

标签: sql sql-server tsql sql-update dynamic-sql

我知道有很多关于这方面的问题,但我无法找到答案。

我有一个看起来像这样的表:

+----+--------+--------+----------+
| 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的值。我想要插入的值不存储在数据库中的任何表中,它们只是我所拥有的单独列表。 如果我使用常规case语句来更新表,它看起来像这样:

 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&#39的值的字符串;字段而不是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语句声明。

有关如何将我的sql转换为动态更新sql的任何建议? 在此先感谢!!

2 个答案:

答案 0 :(得分:1)

在连接部件以形成动态查询时,您需要确保所有内容都为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. 在此方法中,您将收集表中的所有ItemId值 变量@ItemValues和a中相应的StrataId值 table varaible @StrataIDValues
  2. 确保两个表中的值顺序相同,以便这样 @ItemValues表中的第一条记录对应于第一条记录 @StrataIdValues表。

    无动态查询更新

    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;
    

答案 1 :(得分:0)

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

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