【问题标题】:Issue with dynamic SQL insert statement not recognizing values passed as parameter动态 SQL 插入语句无法识别作为参数传递的值的问题
【发布时间】:2017-01-20 18:17:26
【问题描述】:

我一直试图找出这个动态 SQL 插入语句有什么问题。显然,当我将一串值传递给它以插入时,它导致的错误使它看起来像是正确解析,但它说它与语句中指定的列数不匹配。我附上了我要插入数据的表定义、动态语句和下面的值参数:

M2016_Field_ID 列是一个标识列,不需要插入,与具有分配当前日期的默认约束的 Enabled_ON 列相同。

@valuesList = '(''description'', ''0,0'')'

SET @sql = N' INSERT INTO tblM2016_MetaData_Fields ' +
                   N' (Name, FieldNum) ' +
                   N' VALUES (@values);';
SET @params = N'@values nvarchar(max)';

IF @debug = 1
BEGIN
    PRINT @sql;
    PRINT @params;
    PRINT @valuesList;
END
ELSE
    EXEC sp_executesql @sql, @params, @values = @valuesList;

当我尝试执行语句时,它会抛出以下错误:

消息 109,第 15 级,状态 1,第 3 行
INSERT 语句中的列多于 VALUES 子句中指定的值。 VALUES 子句中的值数必须与 INSERT 语句中指定的列数匹配。

【问题讨论】:

  • insert 中有两列,values 中只有一列。仅仅因为一个字符串可能包含逗号并不会把它变成多个值。
  • 我现在明白了。谢谢。

标签: sql sql-server sql-server-2016


【解决方案1】:

你不能这样参数化查询。试试这个方法

SET @valuesList = '''description'', ''0,0'''

SET @sql = N' INSERT INTO tblM2016_MetaData_Fields ' +
                   N' (Name, FieldNum) ' +
                   N' VALUES ('+@valuesList+');';

【讨论】:

    【解决方案2】:

    我不相信您可以将值列表作为字符串传递给单个参数,它可能正在运行的是:

    插入 tblM2016_MetaData_Fields (名称,字段编号) values ('(''description'',''0.0'')') 所以它试图将 name 设置为等于您设置 values list 的字符串。为了执行您正在尝试的操作,您可能只需将该字符串直接添加到您的 sql 语句中或创建两个参数(每个字段一个)。

    【讨论】:

      【解决方案3】:

      幸运或不幸的是,单个参数仅代表查询中的单个值。 T-SQL 没有列表的概念。

      解决此问题的一种方法是将值列表填充到查询字符串中:

      @valuesList = '(''description'', ''0,0'')'
      SET @sql = N'
      INSERT INTO tblM2016_MetaData_Fields (Name, FieldNum) 
           VALUES (@values)';
      
      SET @sql = REPLACE(@sql, '@values', @valuesList);
      IF @debug = 1
      BEGIN
          PRINT @sql;
      END;
      ELSE
          EXEC sp_executesql @sql;
      

      【讨论】:

      • 你的意思是@values 应该是替换中的@valuesList 吗?
      【解决方案4】:

      最好的方法确实是使用参数,但您需要将参数分开。此外,SQL Server 将通过这种方式处理引号的转义,最好不要自己做,因为迟早你会搞砸它是不可避免的。

      结果:

      SET @value1 = 'description'
      SET @value2 = '0,0'
      
      SET @sql = N' INSERT INTO tblM2016_MetaData_Fields ' +
                 N' (Name, FieldNum) ' +
                 N' VALUES (@NameV, @FieldNumV);';
      
      SET @params = N'@NameV varchar(50), @FieldNumV varchar(max)';
      
      EXEC sp_executesql @sql, @params, @NameV = @value1, @FieldNumV = @value2;
      

      请注意,您还需要为Enabled_ON 提供一个值,因为它在表格屏幕截图中定义为NOT NULL

      【讨论】:

      • 真的...投反对票?我想知道为什么。这是迄今为止唯一保留参数的答案,从而避免了所有 sql 注入或损坏的机会。
      • 我没有对你投反对票,这是肯定的。你的答案不是我想要的。顺便说一句,我在问题中指出 Enabled_ON 有一个默认约束,因此它不需要包含在插入中。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-03-27
      • 1970-01-01
      • 2015-05-08
      • 2013-03-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多